[實用小物] Rotary_Encoder with STM32 TIMER

Morgan Ting
閱益如美
Published in
11 min readApr 21, 2023
Photo by Jorge Ramirez on Unsplash

Rotary Encoder 旋轉編碼器是一種人機互動裝置,提供使用者以旋轉方式進行輸入因此常見於各項需要手動設定與調整的裝置上。有別於一般旋轉編碼器在控制上除了輪詢 ( Polling ) 、中斷 ( Interrupt ),STM32 提供一種更方便的輸入介面使得這項工作輕鬆不少。本文章介紹使用 STM32 TIMER 提供的旋轉編碼器控制模式並以 STM32CubeIDE 開發軟體完成本次項目。

使用工具 / 材料

  1. STM32F103C8T6 ( Blue Pill ) *1
  2. ST-LINK V2 *1
  3. Rotary Encoder module KY-040 *1
  4. STM32 CubeIDE 1.5.1

旋轉編碼器

之前的一篇文章 [ Rotary Encoder with Arduino ] 介紹使用 Arduino UNO 以中斷方式進行旋轉編碼器的介面控制。先來快速回顧旋轉編碼器的運作吧。

旋轉編碼器一般分為光學式與機械式,光學式以光遮斷方式偵測編碼器是否被轉動適合用在速度較快的場合,機械式編碼器其內部有機械式接點當轉動時這些接點會輸出訊號,透過讀取接點訊號便可以判斷轉動量與方向等資訊。

KY-040 是一款機械式旋轉編碼器,其構造簡單價格實惠適合用來要求不高的場合也適合 DIY 玩家進行學習與開發。

接著,我們來關心璇編碼器的輸出狀態。KY-040 有兩個相位腳位分別是 CLK與 DT ,還有一個按鈕腳位 SW,其電源可以接 5 V 或 3.3 V 適合大多數微處理器系統,KY-040 旋轉時其 CLK 與 DT 腳位會先後改變電位,兩個訊號輸出相差 90 度。

順時鐘旋轉時輸出訊號如下:

順時鐘轉動輸出波形

從圖中可以看出 CLK 輸出低電位時若 DT 輸出為高電位表示編碼器順時鐘旋轉。

逆時鐘旋轉輸出訊號如下:

逆時鐘轉動輸出波形

從圖中可以看出 CLK 輸出低電位時若 DT 輸出為低電位表示編碼器逆時鐘旋轉。

上面兩圖中的垂直橘線放在 CLK 負緣,這是假設以 CLK 腳為監控對象進行判斷由於 KY-040 模組的相位輸出腳位與按鈕腳位各自放了上拉電阻,另一端接在 GND 因此當編碼器轉動或是按鈕被壓下時會輸出低電位。

STM32 TIMER

STM32 系列微處理器問世已經好一段時間其功能強大體積小很受歡迎。

STM32 TIMER 除了一般的定時器、PWM 訊號產生之外還附帶一個旋轉編碼器訊號捕捉功能。由內部電路進行訊號解析驅動計數器上下數,讓驅動轉編碼器這一項工作變得很簡單。

STM32 的 TIMER 系統方塊圖如下:

source : STM32 datasheet

從系統方塊圖可以看出一個 TIMER 有 4 個通道 CH1 — CH4,由於旋轉編碼器只有兩個輸出腳位,因此本次只需要使用兩個通道。

旋轉編碼器模式的計數運作

電路圖

本次實驗使用搭載 STM32F103C8T6 的 Blue Pill 開發板,使用 TIMER 2 ,其通道一的腳位為 A0 通道二腳位為 A1 ,因此我們把 KY-040 模組的 CLK 接到 開發板的 A0,將 DT 接到發板的 A1 腳位,別忘記 KY-040 的電源與 GND 腳位也要接上開發板的 +3.3 V 與 GND 上。

電路圖

實作

STM32 的廠商提供了官方整合開發軟體 STM32CubeIDE 而且免費使用還提供更新,是不是很棒呢 ? 接下來跟隨操作步驟一步步來完成吧 !

一、開啟 STM32CubeIDE 設定專案目錄後來到歡迎頁面,點選 Start New STM32 project 新增一個專案。

開啟新專案

二、在 Target Selection 頁面中於搜尋列輸入 「F103C8 」便會出現 STM32F103C8T6 型號,選取該晶片型號後按下 Next。

選擇晶片型號

三、輸入專案名稱後按下 Finish 。

輸入專名稱

四、在 Categories 項目中找到 Timers ,展開後點選 TIM 2 。

各項參數設定如下:

  • Conbined Channels : Encoder Mode 編碼器模式
  • Counter Mode : Up 計數器上數模式
  • Counter Period : 65535 最大計數值
  • auto-reload preload : Enable 計數值自動重置 ( 數到最大計數值後自動歸零重新計數 )
  • Encoder Mode : Encoder Mode TI1 and TI2 設定 TI1 與 TI2 為編碼器模式輸入腳位
  • Input Filter : 10 輸入濾波功能有助於去彈跳 ( Debounce ) ,此參數範圍 0 ~ 15 。

以上為 TIMER 設定,其他參數使用預設即可。

TIMER 編碼器模式
TIMER 組態設定

五、Categories 中的 SYS 項目,debug 選擇 Serial Wire。

Serial Wire

六、 Categories 中的 RCC 項目,High Speed Clock ( HSE ) 選擇 Crystal / Ceramic Resonator。

Clock Source

七、Clock Configuration 設定 TIMER 時脈來源,首先在 PLL Source Mux 選擇 HSE,PLL Mul 選擇 9 ,System Clock Mux 選擇 PLLCLK ,最後在 APB1 Prescaler 選擇 /2 。Timer 的時脈來源便設定完成。

Clock

八、Project Manager 的部分確認一下專案目錄與名稱以及 Code Generator 的部分是否需要更改。

專案訊息
專案訊息

九、如果沒問題,上方命令列 Project ==> Generate Code ,產生初始程式碼或是直接按存檔也可以。

產生預設程式碼

產生程式碼後會開啟另一個視窗,可以看見已經有自動產生一些程式碼了,這些都是對應剛才的參數設定而產生的程式碼,如此便可以省下大量功夫與時間真的非常方便。

緊接著,可以開始撰寫程式。程式的步驟很簡單,設定一個全域變數 cnt 用來存放計數值,之後在除錯模式中觀察該變數的數值變化。

在 /* USER CODE BEGIN PV */ 與 /* USER CODE END PV */ 之間宣告一個變數 int16_t cnt = 0;

/* USER CODE BEGIN PV */
int16_t cnt = 0;
/* USER CODE END PV */

往下找到 int main(void) 區段,在 /* USER CODE BEGIN 2 */ 與 /* USER CODE END 2 */

之間加上一段程式碼啟動計時器的編碼器模式

/* USER CODE BEGIN 2 */
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);
/* USER CODE END 2 */

最後在 while(1) 循環區段中寫下一段程式

cnt = __HAL_TIM_GET_COUNTER(&htim2);

其中, __HAL_TIM_GET_COUNTER 是用來讀取計時器當前計數值的指令,由系統內建。

while (1)
{
cnt = (int16_t)__HAL_TIM_GET_COUNTER(&htim2);
}

程式寫完了,就是這麼簡單。

再來就是要上傳程式碼到開發板並觀察數值變化。

十、完成程式碼的撰寫後,上方命令列 Project ==> Build All 或是榔頭圖示,建立相關檔案。

建立與編譯程式碼

十一、相關檔案建立後,按下 RUN 綠色播放鍵圖示。

上傳程式碼

十二、出現 Debug 設定,點選 Debugger ,將 Interface 內的 ST_LINK 前方框框打勾並按下右方的 Scan 按鈕,如果此時ST-LINK v2 燒錄器有接在電腦上就會出現燒錄器 ID 號碼。

完成後分別按下 Apply 與 Debug 後進行編譯與燒錄。

選擇燒錄器

十三、透過 Live Expression 功能來觀察變數。進入 Debug 模式後再視窗畫面右上方找到並點選 Live Expression ,按 + 號圖示增加變數,我們可以添加以下變數名稱來觀察數值變化 。

Live Expression

完成變數設定後按 Resume 按鈕就會看到結果顯示在 Live Expression 視窗。

開始除錯模式

此時可以轉動旋編碼器,正轉或反轉觀察變數 cnt 的數值變化,可以發現數值隨著編碼器正反轉有所增減

但是一次增減 4 ,怎麼回事 ?

轉動一次編碼器輸出增減 4

小問題

還記得 STM32 手冊那張編碼器模式計數圖嗎 ?

旋轉編碼器模式計數運作

由於我們同時使用了 TI1 與 TI2 兩個通道來捕捉編碼器訊號,這張圖恰好說明兩個通道在一個訊號週期內計數器數了 4 步,如果要讓數值隨著編碼器旋轉步數增減 1 該怎麼辦 ?

簡單粗暴,把結果除以 4 吧 !

/* USER CODE BEGIN 2 */
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL) / 4;
/* USER CODE END 2 */
將計數結果除以 4

另一種方式,將 TIMER 參數中的 Prescaler 設為 4 ,意即將 TIMER 的時脈除以 4 。

雙擊 Project Explore 中副檔名為 ioc 檔案回到設定畫面。

Project Explorer

設定 Prescaler

Prescaler 設為 4

結果如何 ?

試驗結果是差強人意,數值不會乖乖增減 1。

還是用簡單粗暴法即可 : )

另一個問題,如果只設定一個輸入捕捉通道呢 ?

回到設定參數畫面,將 Encoder Mode 改成 Encoder Mode TI1

編碼器模式-單通道

啟動 TIMER 指令改成只使用通道 1

/* USER CODE BEGIN 2 */
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_1);
/* USER CODE END 2 */

只看 TI1 腳位的變化,也就是只捕捉 KY-040 的 CLK 腳位,存檔後編譯上傳觀察 Live Expression

發現編碼器正反轉動一格,數值會增減 2 !!。

只使用單通道結果

總結

STM32 提供旋轉編碼器模式輸入捕捉可以自動計數編碼器的旋轉方向以及轉動量,本文章總結如下:

  • STM32 TIMER 可以對轉編碼器進行單一輸入通道以及雙通道捕捉。
  • Input Filter 可設定 0 ~ 15 之間對輸入訊號進行去彈跳處理。
  • 啟動 TIMER 編碼器模式指令為 HAL_TIM_Encoder_Start。
  • 獲取計時器內容指令為 __HAL_TIM_GET_COUNTER。
  • 在雙通道捕捉模式下,編碼器旋轉一格計數器會增減 4 。
  • 在單通道捕捉模式下,編碼器旋轉一格計數器會增減 2 。

參考出處

  1. KY-040 旋轉編碼器資料手冊 [ 連結 ]
  2. 維基百科 — 旋轉編碼器 [ 連結 ]
  3. STM32F103 手冊 [ 連結 ]
  4. STM32F1 HAL and Low-layer drivers [ 連結 ]

感謝有您

若文章有幫助到您可以拍手給我鼓勵,或是免費加入 Like Coin 帳戶並點擊拍手按鈕 5 下,免費支持我。

--

--

Morgan Ting
閱益如美

用好奇心探索世界。喜愛學習樂於分享。