
Arduino | 旋轉編碼器模組使用(2)---使用中斷
關鍵字:arduino旋轉編碼器模組、arduino中斷。繼上篇<Arduino | 旋轉編碼器模組使用(1)>的介紹後,此篇說明如何藉由Arduino開發板的中斷功能,計算旋轉編碼器的轉速與位置。
中斷服務(ISR)
黑修斯只有簡單節錄一些重點介紹中斷,關於中斷服務的詳細說明,請至本篇文章最下方的參考有更詳細的說明。註:呼叫的函數在官方文件為ISR,中文為中斷處理函數或中斷服務常式等。
什麼是中斷?
中斷就好像是燒開水的水壺鳴笛,當水還沒燒開時,我們能夠先去做自己的事情,當水燒開,水壺會發出鳴笛聲(中斷發生),告訴我們水已經燒開,這個時候我們先暫停手邊的工作將火熄滅。attachInterrupt(中斷編號, 呼叫的函數, 中斷模式)在Arduino開發板中,最基本的中斷呼叫方法如上,其中需要引入三個參數(中斷編號, 呼叫的函數, 中斷模式),下列會依序說明。
中斷編號
Arduino (Uno, Nano, Mini, other 328-based)開發板配備二個中斷編號,對應的腳位如下表中斷編號 | 對應之Arduino腳位 |
中斷0 | Pin 2 |
中斷1 | Pin 3 |
Arduino(Mega, Mega2560, MegaADK)開發板配備六個中斷編號,對應的腳位如下表
中斷編號 | 對應之Arduino腳位 |
中斷0 | Pin 2 |
中斷1 | Pin 3 |
中斷2 | Pin 21 |
中斷3 | Pin 20 |
中斷4 | Pin 19 |
中斷5 | Pin 18 |
呼叫函式
當中斷發生時,將執行的函式,一般中斷呼叫的函式,盡量都以簡單的運算為主,中斷時間太長將會影響Arduino晶片的運作。中斷模式
中斷模式有4+1種,其中中斷模式HIGH限用特定的開發板。中斷模式 | 觸發中斷方法 | 備註 |
LOW | 訊號低電位(LOW)時觸發中斷 | |
CHANGE | 訊號改變時觸發中斷 | |
RISING | 訊號由LOW變成HIGH時觸發中斷 | |
FALLING | 訊號由HIGH變成LOW時觸發中斷 | |
HIGH | 訊號高電位(HIGH)時觸發中斷 | 只限用於某些板子如 Due, Zero and MKR1000 .... |
中斷服務的使用範例
attachInterrupt(0, test,CHANGE )
- 啟用中斷0(Arduino 開發板Pin 2)
- 中斷模式為"CHANGE"
- 中斷發生時會呼叫test函式,test函式可以自己自訂名稱。
腳位說明
腳位 | 說明 |
CLK | 相當於A相 |
DT | 相當於B相 |
SW | 編碼器按鈕腳位(編碼器上有開關的功能,可以按壓) |
+ | 正電源 |
GND | 接地 |
腳位觸發變化
通電後,CLK、DT、SW都是高電位(HIGH),當觸發時會變低電位(LOW),而SW(按鈕)被按下時變為低電位(LOW)。
程式接腳
腳位
|
連接Arduino開發板腳位
| |
CLK
|
<--->
|
Arduino Pin2
|
DT
|
<--->
|
Arduino Pin7
|
SW
|
<--->
| 不使用 |
+
|
<--->
|
正電源 5V or 3.3V
|
GND
|
<--->
|
接地
|
程式碼
程式亦可到GitHub下載。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Arduino Rotary Encoder Tutorial | |
* | |
* by Dejan Nedelkovski, www.HowToMechatronics.com | |
* 時間:2018/06/20 | |
* 作者:黑修斯 (陳建仲) | |
* 檔名:encoder_hu02 | |
* 版本:v01 | |
* 說明:旋轉編碼器模組加入中斷來計算,減少丟步(遺失訊號)。 | |
*/ | |
#define outputA 2 //定義 outputA = 2 | |
#define outputB 7 //定義 outputB = 7 | |
int counter = 0; //定義 counter 為 int 類型變數,且初始值為0 | |
int aState; //定義 aState 為 int 類型變數 | |
int aLastState; //定義 aLastState 為 int 類型變數 | |
//初始化設定↓↓↓ | |
void setup() { | |
pinMode (outputA,INPUT); //埠口模式設定:outputA 設為 輸入 | |
pinMode (outputB,INPUT); //埠口模式設定:outputB 設為 輸入 | |
attachInterrupt (0, test, CHANGE); //啟用中斷函式(中斷0,test函式,CHANGE模式) | |
Serial.begin (9600); //Serial通訊鮑率設為9600 | |
aLastState = digitalRead (outputA); //將初始outputA的讀取值 設給 aLastState | |
} | |
//主程式運作區↓↓↓ | |
void loop() { | |
Serial.print("Position: "); //透過serial印出字串 Position: | |
Serial.println(counter); //透過serial印出 counter 值 | |
} | |
//test函式 | |
void test(){ | |
aState = digitalRead(outputA); //將outputA的讀取值 設給 aState | |
if (aState != aLastState){ //條件判斷,當aState 不等於 aLastState時發生 | |
if (digitalRead(outputB) != aState) { //條件判斷,當outputB讀取值 不等於 aState時發生 | |
counter ++; //計數器+1 | |
} else { | |
counter --; //計數器-1 | |
} | |
} | |
aLastState = aState; //將aState 最後的值 設給 aLastState | |
} |
中斷模式CHANG說明
當讀者將黑修斯的範例程式燒錄到Arduino開發板上,就能夠動手理解"中斷模式CHANG"的實際運作方式。理論觸發狀況
CHANG模式[有改變就觸發],訊號由HIGH -> LOW 或 LOW -> HIGH。理論上會如下圖,當旋轉編碼器轉動一下,計數值應為+1或-1。

實際觸發狀況
實際上,計數值有可能為+2或-2,因為旋轉編碼器的初始狀態是"高電位",如下圖二說明,每轉一次的pluse狀態會觸發兩次中斷,所以計數2次。解決實際計數值不符
解決實際計數值不符的狀況,黑修斯故意埋伏筆,讓讀者們可以試著思考與解決,提示兩個解決問題的方向。1.CHANGE模式改LOW 模式
2018/06/24:黑修斯在撰寫系列文章第三篇< Arduino | 旋轉編碼器模組使用(3)---使用中斷並加入按鈕歸零>中,嘗試過LOW模式與FALLING模式,效果並不是很好,應該說準確性沒有CHANGE模式好,而且可以說是不如人意,所以建議讀者們參考方法2。機構上的小問題
這款旋轉編碼器只要輕轉半格,計數值還是可以顯示+1或-1,原因在於內部結構為光遮罩式的設計,輕轉半格就能遮光,進而產生LOW->HIGH的Pluse訊號。
2.程式中的計數值/2 再顯示
![]() |
圖一 |
![]() |
圖二 |
最後的結論
透過中斷的方式,可以準確地控制,只要轉速不超過Arduino開發板的處理速度即可。另外的小地雷(設計上的BUG)
另外的小實驗:使用中斷仍然會失步的狀況,通訊延遲造成的將原本程式碼中void loop()的區塊,如下圖移到test()函式中的位置,讓每次中斷發生才傳回計數值,如果旋轉編碼氣旋轉快一些,會出現計數錯誤,原因為通訊速度造成的延遲現象,可透過調高Serial Port的通訊速度減少這個現象。
亦或是使用原本的程式碼,不將void loop()的區塊移動。

Reference
轉貼本文時,需註明來自黑修斯隨手札記原創作者 hughes chen(黑修斯),及附上原文連結,同時 禁止修改,禁止商業使用 。
0 留言
不一定能即時回覆問題,有時間會盡量答覆。