今天在修復(fù)離職同事遺留下來關(guān)于編碼器的bug,我之前也沒接觸過這玩意,前輩的做法是在定時(shí)器中查詢AB相的電平狀態(tài),來判斷當(dāng)前是正傳還是反正。他搞了個(gè)定時(shí)器1溢出中斷,將32M時(shí)鐘進(jìn)行了64000分頻,131s,信號都漏掉了,我將其改為了1600分頻,16位溢出也就是400ms,正常運(yùn)行(IAR 8.20)。
這個(gè)問題在最新的IAR(IAR 9.30)不會(huì)復(fù)現(xiàn),并且不管哪種分頻在最新的IAR可以正常運(yùn)行。也許還有地方的邏輯沒有看明白,最終還是沒有去改他的分頻。
接下來我們直接來看關(guān)于編碼器的圖:
編碼器工作原理及如何實(shí)現(xiàn)定位控制,秒懂!www.shkcfs.com/Article/MEMS/5738.html
控制:
a. 以上連接是大概原理,我們不看z相,直接看關(guān)于AB相正反轉(zhuǎn)的的控制:
1. 順時(shí)針:A相觸發(fā)上升沿,那么接下來B也觸發(fā)上升沿;A相觸發(fā)下降沿,B相也觸發(fā)下降沿
2. 逆時(shí)針:A相觸發(fā)上升沿,那么接下來B觸發(fā)下降沿; A相觸發(fā)下降沿,B相觸發(fā)上升沿
b. 這樣我就需要設(shè)置雙邊沿觸發(fā)中斷,但是對于一些低端的單片機(jī)來講,可能無法做到,這個(gè)時(shí)候就需要用定時(shí)器和讀IO的電平狀態(tài)來做(前同事之前的做法是將coderScan()放到定時(shí)器中斷函數(shù)中,為了處理幾個(gè)和時(shí)間有關(guān)的任務(wù),開了4個(gè)定時(shí)器,我們完全可以使用時(shí)間片的方式做)
1.順時(shí)針: 如果A相前一刻的電平和當(dāng)前電平不一樣,并且當(dāng)前電平為低,B相為低,則順時(shí)針旋轉(zhuǎn); 如果B相前一刻的電平和當(dāng)前電平不一樣,并且當(dāng)前電平為高,A相為低。
2. 逆時(shí)針: 如果A相前一刻的電平和當(dāng)前電平不一樣,并且當(dāng)前電平為低,B相為高,則逆時(shí)針旋轉(zhuǎn);如果B相前一刻的電平和當(dāng)前電平不一樣,并且當(dāng)前電平為高,A相為高。
void coderScan() { u8 i; u8 aPin, bPin; for(i=0; i<CODER_NUM; i++) //從編碼器1 到 編碼器n輪詢檢測 { aPin = GPIO_ReadInputDataBit(CODER_IO_ARRAY[i].aPin.group, CODER_IO_ARRAY[i].aPin.pin); bPin = GPIO_ReadInputDataBit(CODER_IO_ARRAY[i].bPin.group, CODER_IO_ARRAY[i].bPin.pin); if((_coder[i].aPin != aPin) && (aPin == 0x00)) /* 讀取到的值為低電平 */ { if(bPin) // 電壓下降有效 { coderCCW(i);//逆時(shí)針旋轉(zhuǎn) } else { coderCW(i);//順時(shí)針旋轉(zhuǎn) } } else if((_coder[i].bPin != bPin) && (bPin == 0x01)) { if(aPin) // 電壓上升有效 { coderCCW(i);//逆時(shí)針旋轉(zhuǎn) } else { coderCW(i);//順時(shí)針旋轉(zhuǎn) } } _coder[i].aPin = aPin; _coder[i].bPin = bPin; } }
一般,編碼器旋轉(zhuǎn)一圈有1024個(gè)脈沖,而編碼器是有格數(shù)的(每次咔吧一聲轉(zhuǎn)動(dòng)了一格),我數(shù)了一下我手上的有30格,因此想要正確表示旋轉(zhuǎn),我們不僅要通過電平變化知道方向,還要根據(jù)脈沖格數(shù)來判斷,也就是大概一格34個(gè)脈沖,如果按90%計(jì)算脈沖個(gè)數(shù),也就檢測到30個(gè)脈沖觸發(fā)一次。