中斷方式驅動旋轉編碼器
旋轉編碼器是一種位置傳感器,可將旋鈕的角位置(旋轉)轉換為用于確定旋鈕旋轉方向的輸出信號。
由于其堅固性和良好的數字控制;它們被用于許多應用中,包括機器人技術,CNC機器和打印機。
旋轉編碼器有兩種類型-絕對式和增量式。絕對編碼器為我們提供旋鈕的精確位置(以度為單位),而增量編碼器報告軸已移動了多少增量。
編碼器內部是一個槽形磁盤,該磁盤連接到公共接地引腳C以及兩個接觸針A和B。旋轉旋鈕時,A和B根據旋轉旋鈕的方向以特定順序與公共接地引腳C接觸。
當它們接觸公共接地時,它們會產生信號。當一個引腳先于另一引腳接觸時,這些信號就會彼此錯開90°。這稱為 正交編碼 。
順時針旋轉旋鈕時,首先連接A引腳,然后連接B引腳。逆時針旋轉旋鈕時,首先連接B引腳,然后連接A引腳。
通過跟蹤每個引腳何時與地面連接或與地面斷開,我們可以使用這些信號變化來確定旋鈕的旋轉方向。您可以通過在A更改狀態時觀察B的狀態來做到這一點。
我們搭建電路,如下:
載入方案
我們使用的開發板是 R128-Devkit,需要開發 C906 核心的應用程序,所以載入方案選擇r128s2_module_c906
$ source envsetup.sh
$ lunch_rtos 1
勾選 GPIO 驅動
mrtos_menuconfig
找到下列驅動
Drivers Options --- >
soc related device drivers --- >
GPIO devices --- >
[*] enable GPIO driver
[*] enbale GPIO hal APIs Test command
編寫程序
打開你喜歡的編輯器,修改文件:lichee/rtos/projects/r128s2/module_c906/src/main.c
引入頭文件
#include < hal_gpio.h >
使用 GPIO 配置引腳
配置 GPIO 的上下拉狀態
使用 hal_gpio_set_pull(gpio_pin_t pin, gpio_pull_status_t pull);
來設置。這里我們設置 PA25
引腳為默認上拉狀態。
hal_gpio_set_pull(GPIOA(25), GPIO_PULL_UP);
配置 GPIO 輸入輸出模式
使用 hal_gpio_set_direction(gpio_pin_t pin, gpio_direction_t direction);
來設置 GPIO 的輸入輸出模式,這里配置為輸入模式。
hal_gpio_set_direction(GPIOA(25), GPIO_DIRECTION_INPUT);
配置 GPIO 的 MUX 功能
GPIO 通常有多種功能,需要配置 MUX 選擇需要的功能,使用 hal_gpio_pinmux_set_function(gpio_pin_t pin, gpio_muxsel_t function_index);
來設置 GPIO 的復用功能,這里配置為GPIO 輸入模式(GPIO_MUXSEL_IN
)
hal_gpio_pinmux_set_function(GPIOA(25), GPIO_MUXSEL_IN);
獲取 GPIO 的電平
使用 int hal_gpio_get_data(gpio_pin_t pin, gpio_data_t *data);
來獲取 GPIO 的電平
gpio_data_t gpio_data;
hal_gpio_get_data(GPIOA(25), &gpio_data);
申請配置中斷
使用 hal_gpio_to_irq
方法來申請中斷號。hal_gpio_irq_request
綁定中斷服務,hal_gpio_irq_enable
啟用中斷。這里配置一個
// 存放中斷號
uint32_t irq_clk;
// 申請中斷號
ret = hal_gpio_to_irq(ENC_CLK, &irq_clk);
if (ret < 0){
printf("gpio to irq error, irq num:%d error num: %dn", irq_clk, ret);
}
// 綁定中斷處理函數
ret = hal_gpio_irq_request(irq_clk, gpio_irq_encode, IRQ_TYPE_EDGE_BOTH, NULL);
if (ret < 0){
printf("request irq error, irq num:%d error num: %dn", irq_clk, ret);
}
// 啟用中斷
ret = hal_gpio_irq_enable(irq_clk);
if (ret < 0){
printf("request irq error, error num: %dn", ret);
}
完整代碼
#include < stdio.h >
#include < stdint.h >
#include < string.h >
#include < unistd.h >
#include "interrupt.h"
#include < portmacro.h >
#include < cli_console.h >
#include < aw_version.h >
#include < hal_time.h >
#include < hal_gpio.h >
#include "FreeRTOS.h"
#include "task.h"
#include "tinatest.h"
extern int amp_init(void);
// 定義旋轉編碼器的引腳
#define ENC_CLK GPIOA(24)
#define ENC_DT GPIOA(25)
#define ENC_SW GPIOA(29)
// 相關全局變量存儲
int encode_counter = 0;
int encode_current_clk;
int encode_lask_clk;
int current_dir = 0;
// 編碼器中斷處理函數
static hal_irqreturn_t gpio_irq_encode(void *data)
{
// 獲取引腳的高低電平狀態
gpio_data_t clk_value = GPIO_DATA_LOW;
gpio_data_t dt_value = GPIO_DATA_LOW;
hal_gpio_get_data(ENC_DT, &dt_value);
hal_gpio_get_data(ENC_CLK, &clk_value);
// 判斷當前數據狀態
encode_current_clk = clk_value;
if (encode_current_clk != encode_lask_clk && encode_current_clk == 1){
// 判斷正反轉
if (dt_value != encode_current_clk) {
// 正轉
encode_counter ++;
current_dir = 1;
} else {
// 反轉
encode_counter --;
current_dir = -1;
}
printf("Direction = %d, Counter = %dn", current_dir, encode_counter);
}
// 刷新當前狀態
encode_lask_clk = encode_current_clk;
return 0;
}
void cpu0_app_entry(void *param)
{
int ret = 0;
// 初始化系統資源
amp_init();
// A24 - > CLK, A25 - > DT. A29 - > SW
hal_gpio_set_pull(ENC_CLK, GPIO_PULL_DOWN_DISABLED);
hal_gpio_set_direction(ENC_CLK, GPIO_DIRECTION_INPUT);
hal_gpio_pinmux_set_function(ENC_CLK, GPIO_MUXSEL_IN);
// 獲取初始編碼器 CLK 狀態
gpio_data_t clk_data;
hal_gpio_get_data(ENC_CLK, &clk_data);
encode_lask_clk = clk_data;
hal_gpio_set_pull(ENC_DT, GPIO_PULL_DOWN_DISABLED);
hal_gpio_set_direction(ENC_DT, GPIO_DIRECTION_INPUT);
hal_gpio_pinmux_set_function(ENC_DT, GPIO_MUXSEL_IN);
// 存放 CLK,DT 中斷號
uint32_t irq_clk, irq_dt;
// 申請 ENC_CLK 為中斷引腳,跳變觸發
ret = hal_gpio_to_irq(ENC_CLK, &irq_clk);
if (ret < 0){
printf("gpio to irq error, irq num:%d error num: %dn", irq_clk, ret);
}
// 綁定中斷處理函數
ret = hal_gpio_irq_request(irq_clk, gpio_irq_encode, IRQ_TYPE_EDGE_BOTH, NULL);
if (ret < 0){
printf("request irq error, irq num:%d error num: %dn", irq_clk, ret);
}
// 啟用中斷
ret = hal_gpio_irq_enable(irq_clk);
if (ret < 0){
printf("request irq error, error num: %dn", ret);
}
// 申請 ENC_DT 為中斷引腳,跳變觸發
ret = hal_gpio_to_irq(ENC_DT, &irq_dt);
if (ret < 0){
printf("gpio to irq error, irq num:%d error num: %dn", irq_dt, ret);
}
// 綁定中斷處理函數
ret = hal_gpio_irq_request(irq_dt, gpio_irq_encode, IRQ_TYPE_EDGE_BOTH, NULL);
if (ret < 0){
printf("request irq error, irq num:%d error num: %dn", irq_dt, ret);
}
// 啟用中斷
ret = hal_gpio_irq_enable(irq_dt);
if (ret < 0){
printf("request irq error, error num: %dn", ret);
}
vTaskDelete(NULL);
}
結果
旋轉旋轉編碼器即可看到計數變化
評論
查看更多