本文隸屬於AVR單片機教程系列。
好久沒寫這個系列了。今天講講旋轉編碼器。
旋轉編碼器好像不是單片機玩家很常用的器件,但是我們的開發板上有,原因如下:
-
旋轉編碼器挺好用的。電位器能旋轉的角度有限,旋轉編碼器可以無限圈旋轉;旋轉時不連續,有卡點,適合對應離散數據。
-
開發板上選用的旋轉編碼器,使用起來簡單、方便。
-
本來旁邊的電位器(旋鈕,以后會講)一枝獨秀,挺孤單的,我就配一個高度大致相同的旋轉編碼器陪伴它。
今天我想寫旋轉編碼器,於是在網絡上搜索了一下,相關資料很少。最基本地,旋轉編碼器的作用是將角位移、角速度等機械量轉換為電信號。本文不求成為旋轉編碼器的百科全書,但會把 觸點電刷式 增量式 旋轉編碼器的原理講清楚。這里出現了兩個定語,是對類別的限定;關於旋轉編碼器的分類,請自行百度。
開發板上的旋轉編碼器是從淘寶買的,淘寶商家提供了資料,這是本講的主題。為避免廣告嫌疑,我不能放鏈接上來,所以我就把它轉換成圖片放在文章里(請在新頁面中查看):
我們從旋轉編碼器的原理開始。旋轉編碼器的內部是觸點與電刷,可以看作按鍵:當兩者接觸時,開關閉合;反之斷開。實際上它們的本質是一樣的。在旋轉時,按鍵會周期性地閉合、斷開;如果一端接地,另一端接上拉電阻,就會有周期性高、低電平的脈沖信號產生。我們使用的旋轉編碼器每轉過一圈會輸出24個脈沖。
通過對脈沖進行計數,可以知道編碼器轉過的角度。如果不管方向,測量角度或角加速度等,用一個輸出就夠了。但是如果考慮方向,無論是順時針還是逆時針轉動,電平都是“高低高低高……”。為了獲得方向的信息,需要使用兩個輸出,它們的相位相差90°,如圖所示:
A和B是兩個輸出端,C端接地。當程序檢測到A端由高電平變為低電平時(方法在按鍵那里講過了),如果檢測到B端是高電平(這就更簡單了),那就是順時針旋轉;如果是低電平,那就是逆時針旋轉。實際上不一定要檢測A端的下降沿,只要按照這張圖來,怎么都對。
庫函數使用的檢測方法是:A、B端由低低變為高低時,判為順時針轉過一格;由低低變為低高時,判為逆時針轉過一格。這不是最好的方法(你可以想一下怎樣改進,但是不要低估它的難度),但從實際使用上來看,只要用戶不故意在兩個卡點之間扭來扭去,這種方法是可以勝任的。
我們寫一個用旋轉編碼器控制數碼管顯示數字的程序,也可以理解為對旋轉編碼器進行計數並用數碼管顯示。旋轉編碼器A和B端分別連接端口4和5,數碼管連接6和7。程序的思路是:每隔一毫秒調用rotary_rotated
(它和button_pressed
函數類似——如果你還記得的話)檢測編碼器是否被轉動以及轉動的方向,並根據方向對計數器變量num
進行增減。(為什么讓num
為uint8_t
類型?)為了凸顯旋轉編碼器的主題,數碼管就用segment_auto
來解決了。
#include <ee1/delay.h>
#include <ee1/rotary.h>
#include <ee1/segment.h>
int main()
{
rotary_init(PIN_4, PIN_5);
segment_init(PIN_6, PIN_7);
segment_auto();
uint8_t num = 0;
while (1)
{
switch (rotary_rotated())
{
case ROTARY_CW:
++num;
break;
case ROTARY_ACW:
--num;
break;
default:
break;
}
segment_hex(num);
delay(1);
}
}
注意相鄰卡點之間擠了4個AB端口的狀態,因此延時不能過長。你可以試試更長的間隔。
作業:對於旋轉編碼器,直接檢測IO口電平;對於數碼管,使用“原始”的動態掃描,即不要用segment_auto()
;重寫樣例。(提示:你可以分別完成兩個要求,然后合並。)