簡(jiǎn)介
MultiButton 是一個(gè)小巧簡(jiǎn)單易用的事件驅(qū)動(dòng)型按鍵驅(qū)動(dòng)模塊,可無(wú)限量擴(kuò)展按鍵,按鍵事件的回調(diào)異步處理方式可以簡(jiǎn)化你的程序結(jié)構(gòu),去除冗余的按鍵處理硬編碼,讓你的按鍵業(yè)務(wù)邏輯更清晰。
本章使用環(huán)境:
正點(diǎn)原子stm32F4探索者
代碼工程使用正點(diǎn)原子HAL庫(kù)實(shí)驗(yàn)三-按鍵輸入實(shí)驗(yàn)
下載
GIthub地址:https://github.com/0x1abin/MultiButton
配有g(shù)it環(huán)境可以使用以下命令進(jìn)行下載
git clone https://github.com/0x1abin/MultiButton.git
使用介紹
MultiButton 使用C語(yǔ)言實(shí)現(xiàn),基于面向?qū)ο蠓绞皆O(shè)計(jì)思路,每個(gè)按鍵對(duì)象單獨(dú)用一份數(shù)據(jù)結(jié)構(gòu)管理:
struct Button {
uint16_t ticks;
uint8_t repeat: 4;
uint8_t event : 4;
uint8_t state : 3;
uint8_t debounce_cnt : 3;
uint8_t active_level : 1;
uint8_t button_level : 1;
uint8_t button_id;
uint8_t (*hal_button_Level)(uint8_t button_id_);
BtnCallback cb[number_of_event];
struct Button* next;
};
這樣每個(gè)按鍵使用單向鏈表相連,依次進(jìn)入 button_handler(struct Button* handle) 狀態(tài)機(jī)處理,所以每個(gè)按鍵的狀態(tài)彼此獨(dú)立。
按鍵事件
事件 | 說(shuō)明 |
---|---|
PRESS_DOWN | 按鍵按下,每次按下都觸發(fā) |
PRESS_UP | 按鍵彈起,每次松開(kāi)都觸發(fā) |
PRESS_REPEAT | 重復(fù)按下觸發(fā),變量repeat計(jì)數(shù)連擊次數(shù) |
SINGLE_CLICK | 單擊按鍵事件 |
DOUBLE_CLICK | 雙擊按鍵事件 |
LONG_PRESS_START | 達(dá)到長(zhǎng)按時(shí)間閾值時(shí)觸發(fā)一次 |
LONG_PRESS_HOLD | 長(zhǎng)按期間一直觸發(fā) |
工程移植
我們將下載好的MultiButton源碼中的multi_button.c和multi_button.h文件拷貝到stm32工程目錄下的handware中的key文件夾下
然后我們?cè)趉eil中添加該文件
代碼分析
#define TICKS_INTERVAL 5 //ms 輪詢間隔時(shí)間,也就是時(shí)間片
#define DEBOUNCE_TICKS 3 //MAX 8 雙擊間隔時(shí)間片
#define SHORT_TICKS (300 /TICKS_INTERVAL) // 短按時(shí)間片
#define LONG_TICKS (1000 /TICKS_INTERVAL) // 長(zhǎng)按時(shí)間片
然后我們可以看到輪詢的函數(shù)中是不斷的遍歷鏈表
void button_ticks()
{
struct Button* target;
for(target=head_handle; target; target=target->next) {
button_handler(target);
}
}
根據(jù)代碼我們可以看出來(lái)button_start函數(shù)就是添加鏈表節(jié)點(diǎn)的函數(shù)(那相應(yīng)的button_stop就是刪除鏈表節(jié)點(diǎn)的功能)
int button_start(struct Button* handle)
{
struct Button* target = head_handle; // 頭節(jié)點(diǎn)
while(target) {
if(target == handle) return -1; //already exist.
target = target->next; // 遍歷到最后一個(gè)節(jié)點(diǎn)
}
handle->next = head_handle;// 環(huán)形結(jié)構(gòu)的鏈表頭尾相連
head_handle = handle;
return 0;
}
void button_stop(struct Button* handle)
{
struct Button** curr;
for(curr = &head_handle; *curr; ) {
struct Button* entry = *curr;
if (entry == handle) {
*curr = entry->next;
// free(entry);
return;//glacier add 2021-8-18
} else
curr = &entry->next;
}
}
按鍵事件驅(qū)動(dòng)枚舉
typedef enum {
PRESS_DOWN = 0, // 按下信號(hào)
PRESS_UP, // 彈起信號(hào)
PRESS_REPEAT, // 重復(fù)按下計(jì)數(shù),在button結(jié)構(gòu)體變量中repeat存儲(chǔ)次數(shù)
SINGLE_CLICK, // 單擊信號(hào)
DOUBLE_CLICK, // 雙擊信號(hào)
LONG_PRESS_START, // 長(zhǎng)安信號(hào)
LONG_PRESS_HOLD, // 長(zhǎng)按期間會(huì)重復(fù)觸發(fā)
number_of_event,
NONE_PRESS // 未按下
}PressEvent;
typedef struct Button {
uint16_t ticks;
uint8_t repeat : 4; // 單機(jī)次數(shù)記錄
uint8_t event : 4; // 事件
uint8_t state : 3; // 狀態(tài)
uint8_t debounce_cnt : 3;
uint8_t active_level : 1; // 觸發(fā)電平
uint8_t button_level : 1; // 當(dāng)前按鍵電平
uint8_t button_id; // 按鍵id
uint8_t (*hal_button_Level)(uint8_t button_id_); // 按鍵狀態(tài)讀取函數(shù)通過(guò)指針數(shù)組保存
BtnCallback cb[number_of_event]; // 回調(diào)函數(shù)數(shù)組(注冊(cè)的回調(diào)函數(shù)會(huì)存在這里,輪詢會(huì)通過(guò)該數(shù)組調(diào)用)
struct Button* next; // 指向下一個(gè)按鍵的指針(鏈表)
}Button;
由上分析得知注冊(cè)按鍵第一個(gè)參數(shù)為按鍵節(jié)點(diǎn),第二個(gè)為參數(shù)為讀取按鍵電平的函數(shù),第三個(gè)為按鍵觸發(fā)電平,第四個(gè)為按鍵id定義
void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level, uint8_t button_id);
觸發(fā)事件注冊(cè),第一個(gè)參數(shù)為按鍵節(jié)點(diǎn),第二個(gè)參數(shù)為按鍵事件枚舉值,第三個(gè)為回調(diào)觸發(fā)函數(shù)
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb);
返回該按鍵節(jié)點(diǎn)的觸發(fā)類型,當(dāng)我們不使用回調(diào)函數(shù)方法時(shí)可以輪詢?cè)摵瘮?shù)判斷按鍵事件信號(hào)
PressEvent get_button_event(struct Button* handle);
multi_button.c文件中還有一個(gè)button_handler函數(shù)也就是我們tick函數(shù)輪詢判斷的函數(shù),該函數(shù)為實(shí)現(xiàn)按鍵各個(gè)事件實(shí)現(xiàn)的方法,大家可以自行閱讀學(xué)習(xí)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-431899.html
完整使用流程
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "multi_button.h"
enum Button_IDs {
btn1_id,
btn2_id,
};
struct Button btn1;
struct Button btn2;
uint8_t read_button_GPIO(uint8_t button_id)
{
// you can share the GPIO read function with multiple Buttons
switch(button_id)
{
case btn1_id:
return HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4);
case btn2_id:
return HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3);
default:
return 0;
}
}
void BTN1_PRESS_DOWN_Handler(void* btn)
{
//do something...
printf("btn1 press down\r\n");
}
void BTN1_PRESS_UP_Handler(void* btn)
{
//do something...
printf("btn2 press up\r\n");
}
void BTN2_LONG_PRESS_START_Handler(void* btn)
{
//do something...
printf("btn2 press down\r\n");
}
void BTN2_DOUBLE_Click_Handler(void* btn)
{
//do something...
printf("btn2 press up\r\n");
}
int main(void)
{
HAL_Init(); //初始化HAL庫(kù)
Stm32_Clock_Init(336,8,2,7); //設(shè)置時(shí)鐘,168Mhz
delay_init(168); //初始化延時(shí)函數(shù)
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
KEY_Init(); //初始化按鍵
printf("MultiButton Test...\r\n");
button_init(&btn1, read_button_GPIO, 0, btn1_id);
button_init(&btn2, read_button_GPIO, 0, btn2_id);
// 這里只注冊(cè)了按下和談起信號(hào),其余的信號(hào)也可以自己實(shí)驗(yàn)以下
button_attach(&btn1, PRESS_DOWN, BTN1_PRESS_DOWN_Handler);
button_attach(&btn1, PRESS_UP, BTN1_PRESS_UP_Handler);
button_attach(&btn2, LONG_PRESS_START, BTN2_LONG_PRESS_START_Handler);
button_attach(&btn2, DOUBLE_CLICK, BTN2_DOUBLE_Click_Handler);
button_start(&btn1);
button_start(&btn2);
while(1)
{
button_ticks();
delay_ms(5);
}
}
實(shí)驗(yàn)效果
我這里使用的方法是回調(diào)函數(shù)觸發(fā),還有一個(gè)方式也就是上面說(shuō)的通過(guò)get_button_event來(lái)判斷按鍵事件狀態(tài)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-431899.html
while(1)
{
if(btn1_event_val != get_button_event(&btn1)) {
btn1_event_val = get_button_event(&btn1);
if(btn1_event_val == PRESS_DOWN) {
//do something
} else if(btn1_event_val == PRESS_UP) {
//do something
} else if(btn1_event_val == LONG_PRESS_HOLD) {
//do something
}
}
}
到了這里,關(guān)于【嵌入式開(kāi)源庫(kù)】MultiButton的使用,簡(jiǎn)單易用的事件驅(qū)動(dòng)型按鍵驅(qū)動(dòng)模塊的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!