前幾天看到論壇里的舊帖《自己動手制作 “POV LED” 旋轉LED顯示屏》,文中樓主提到......外部中斷函數產生了兩次以上......
估計就是霍爾傳感器接到外部中斷IO上。實際磁鋼每次經過霍爾元件時,單片機觸發了兩次或多次外部中斷。這使我想起前一陣子的自制繞線機的事情。
前一陣子,有個電路上需要壓電陶瓷片,得用自制磁芯變壓器。初級10繞制00圈,次級是30和60圈。
希望繞線時能控制銅線位置,這樣初級每層銅線比較整齊,所以要求繞線速度必須要低。后來發現用兩節七號鎳氫電池給TT直流減速電機供電,轉速差不多一秒一圈。速度低,比較合適,我可以拉著銅線,適時調整繞線銅線位置。
減速電機軸一端套上碼盤,另一端套上變壓器骨架的。當時,先用的紅外對射模塊(其他名稱有測速傳感器模塊 計數器模塊 電機測試模塊 槽型光耦模塊等等),碼盤上有20個孔,用黑膠帶封了19個,只留下一個孔,這樣碼盤轉動一圈,紅外模塊只會輸出一次下降沿。
單片機程序下載后,運行時發現,實際數碼管上的計數數值不是按一遞增的,大多數時候是按二遞增的,偶爾會按一遞增或按三、四遞增的。
以為是紅外模塊有故障,換了一個,現象依舊。換傳感器,在碼盤邊緣粘上一個小磁鋼,換用霍爾傳感器模塊,單片機運行時也是同樣的現象。
奇怪了,當時因為著急用變壓器,沒再分析故障了,在代碼里面計數數值除以二,結果再顯示在數碼管上。按此方法繞制了磁芯變壓器,裝上電路可正常工作的。后來就沒有再查找這個計數故障了。
碼盤紅外模塊電機安裝總成.JPG (66.47 KB, 下載次數: 99)
下載附件
2018-6-28 21:39 上傳
直到看到那個舊帖,才想起來,也有人遇到同樣的問題了(樓主當時還是個初中生,真厲害!!)。
但對樓主分析的原因不敢茍同,于是翻了翻單片機教程和幾本書,有了自己的想法。
以下是個人看法,業余水平,歡迎各位看官拍磚。
無論是紅外對射模塊,還是霍爾傳感器,其實電路上就是運放比較器,比較器是能穩定可靠工作的,應該不是故障源頭。問題應該集中在紅外發射接收對管和霍爾元件裝置上。
紅外發射管發射的紅外線光束是散射的。不像激光那樣筆直和纖細。減速軸上安裝的碼盤也沒有和紅外對射模塊嚴格定位,做到碼盤平面與對射光軸嚴格垂直。由于碼盤還在運動,難免有抖動的。那么光電接收管收到的紅外光很可能既有發射管直射過來的,也包括從碼盤小孔側壁上反射過來的,甚至還可能還包括衍射過來的紅外光。
主要因為機械抖動或振動,紅外線的傳播有了多個路徑,多個路徑傳播的紅外線中就有那么幾個光線強度足以致模塊輸出了低電平信號,也就有了下降沿。霍爾元件和磁鋼也是類似的。若是有示波器或邏輯分析儀,抓取一段,就能看到這個直觀現象的。
還記得機械按鍵嘛,使用時必須“消抖”,否則就可能出現多次中斷的情況。既然如此,那就“消抖”是了。
人手按按鍵,前后幾十毫秒的時間,和機械按鍵不一樣的是,這里機械抖動或振動很可能不到一毫秒,需要實測才知道的。我沒有那些測試設備,那么就用笨辦法,一個一個地試驗。哪位有條件的,抽空抓取一段看看。所以,消抖的方法不能像機械按鍵那么簡單的。
我想到的辦法是單穩態電路。
收到外部觸發信號后,電路被觸發,進入單穩態;
單穩態時間要稍長,這樣就無視后來的幾個觸發信號了;
單穩態時間也不能太長,以免影響下一次正常的觸發信號。
555.JPG (31 KB, 下載次數: 118)
下載附件
2018-6-28 21:40 上傳
我用的是555時基集成電路,多試了幾個電容和電阻,調整了RC參數,計數就正確了。最后用的是0.1微法的電解電容和150歐姆的電阻,計算時間常數是1.1*0.1*150=16.5微秒。想通了,就簡單了!
555面包板.JPG (62.1 KB, 下載次數: 107)
下載附件
2018-6-28 21:41 上傳
8位數碼管.JPG (43.7 KB, 下載次數: 100)
下載附件
2018-6-28 21:46 上傳
后來,換用碼盤,沒有遮孔的,計數也正常了。減速電機換用4節鎳氫電池供電,提高轉速(大概2、3圈每秒),計數也是正常的。
整裝.JPG (44.4 KB, 下載次數: 90)
下載附件
2018-6-28 21:41 上傳
準備繞線了。
視頻太大附件也傳不了的。
繞完了.JPG (79.97 KB, 下載次數: 89)
下載附件
2018-6-28 21:47 上傳
繞完了。
當然了,若是用在其他更高速的地方,估計還得再調整RC參數的。
單片機源程序如下:
- #include<reg52.h>
- sbit flashLed=P1^1; //閃爍燈
- unsigned char T0RH = 0; //T0重載值的高字節
- unsigned char T0RL = 0; //T0重載值的低字節
- unsigned int uiCount=0;
- bit flag200ms=0;
- unsigned char code Tab[18]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,0x7F,0xFF};
- unsigned char ledChar[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
- /* 配置并啟動T0,ms-T0定時時間 */
- void ConfigTimer0(unsigned int ms)
- {
- unsigned long tmp;
- tmp = 11059200 / 12;
- tmp = (tmp * ms) / 1000;
- tmp = 65536 - tmp;
- tmp = tmp + 18;
- T0RH = (unsigned char)(tmp>>8);
- T0RL = (unsigned char)tmp;
- TMOD &= 0xF0;
- TMOD |= 0x01;
- TH0 = T0RH;
- TL0 = T0RL;
- ET0 = 1;
- TR0 = 1;
- }
- void LedScan()
- {
- static unsigned char i = 0; //動態掃描索引
- unsigned char location=0x01;
- P0=0xFF; //關閉所有段選位,顯示消隱
- P2=0xff;
- location=location<<i;
- location=~location;
- P0=ledChar[i];
- P2=location;
- i++;
- i=i%8;
- }
- /* T0中斷服務函數,執行數碼管掃描顯示 */
- void InterruptTimer0() interrupt 1
- {
- static unsigned char tc=0;
- tc++;
- TH0 = T0RH; //重新加載重載值
- TL0 = T0RL;
- if(tc==200)
- {
- tc=0;
- flag200ms=1;
- flashLed=~flashLed;
- }
- LedScan(); //數碼管掃描顯示
- }
- //外部中斷函數
- void INT0_Count() interrupt 0
- {
- uiCount++;
- }
- void main(void)
- {
- unsigned char k=0;
- unsigned int uiTmp=0;
- EX0=1; //允許外部中斷INT0中斷
- IT0=1; //外部中斷INT0采用脈沖負跳變觸發方式
- EA = 1;
- uiCount=0;
- ConfigTimer0(1); //配置T0定時1ms
- while (1)
- {
- if(flag200ms)
- {
- flag200ms=0;
- uiTmp=uiCount;
- for(k=0;k<8;k++)
- ledChar[k]=0xff;
- ledChar[7]=Tab[uiTmp%10];
- if(uiTmp>=10)
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
繞線計數器a51程序.zip
(24.56 KB, 下載次數: 29)
2018-6-28 21:49 上傳
點擊文件名下載附件
51程序 下載積分: 黑幣 -5
|