在學習過程中,遇到了要使用很多個按鍵的情況,(沒有同時按下的處理,沒有用矩陣鍵盤)。一增加一個新按鍵,需要改動的地方太多,在網上看了一篇博客
https://blog.csdn.net/jiejiemcu/article/details/83097992
覺得它使用的方法不錯,就進行學習研究,移植到stm32單片機上。這種編程思想值得學習,做個小總結。
typedef struct button
{
/* 下面是一個函數指針,指向判斷按鍵手否按下的函數 */
uint8_t (*Read_Button_Level)(void); /* 讀取按鍵電平函數,需要用戶實現 */
char Name[BTN_NAME_MAX];
uint8_t Button_State : 4; /* 按鍵當前狀態(按下還是彈起) */
uint8_t Button_Last_State : 4; /* 上一次的按鍵狀態,用於判斷雙擊 */
uint8_t Button_Trigger_Level: 2; /* 按鍵觸發電平 */
uint8_t Button_Last_Level: 2; /* 按鍵當前電平 */
uint8_t Button_Trigger_Event; /* 按鍵觸發事件,單擊,雙擊,長按等 */
Button_CallBack CallBack_Function[number_of_event];
uint8_t Button_Cycle; /* 連續按鍵週期 */
uint8_t Timer_Count; /* 計時 */
uint8_t Debounce_Time; /* 消抖時間 */
uint8_t Long_Time_Record; /* 有長按記錄 */
uint8_t Long_Time; /* 按鍵按下持續時間 */
struct button *Next;
}Button_t
uint8_t (*Read_Button_Level)(void); /* 讀取按鍵電平函數,需要用戶實現 */
這段代碼是一個函數指針形式,指向函數的指針,可以用來塞用戶的函數
函數指針的定義:如果在程序中定義了一個函數,那麼在編譯時系統就會爲這個函數代碼分配一段存儲空間,這段存儲空間的首地址稱爲這個函數的地址。而且函數名錶示的就是這個地址。既然是地址我們就可以定義一個指針變量來存放,這個指針變量就叫作函數指針變量,簡稱函數指針。
關於函數指針的詳解:
https://blog.csdn.net/luoyayun361/article/details/80428882
Button_CallBack CallBack_Function[number_of_event]; 這是一個回調函數的數組,
#define TRIGGER_CB(event) \ if(btn->CallBack_Function[event]) \ btn->CallBack_Function[event]((Button_t*)btn)
這個是關於回調的解析:
https://blog.csdn.net/booirror/article/details/20007009
通過jlink_rttview 進行打印,按鍵的信息
按鍵1按下,短按,雙擊,長按,長按釋放
這裏是20ms輪詢一下相應的按鍵狀態查詢函數
按鍵的創建程序,相應的回調函數,事件和stm32的低層函數進行連接
/************************************************************
* @brief 按鍵創建
* @param name : 按鍵名稱
* @param btn : 按鍵結構體
* @param read_btn_level : 按鍵電平讀取函數,需要用戶自己實現返回uint8_t類型的電平
* @param btn_trigger_level : 按鍵觸發電平
* @note NULL
***********************************************************/
void Button_Create(const char *name,
Button_t *btn,
uint8_t(*read_btn_level)(void),
uint8_t btn_trigger_level)
{
if(btn == NULL)
{
SEGGER_RTT_WriteString(0, RTT_CTRL_TEXT_BRIGHT_RED"struct button is null!"RTT_CTRL_RESET"\n");
}
memset(btn,0,sizeof(*btn));
StrnCopy(btn->Name,name,BTN_NAME_MAX);
btn->Button_State = NONE_TRIGGER;
btn->Button_Last_State = NONE_TRIGGER;
btn->Button_Trigger_Event = NONE_TRIGGER;
btn->Read_Button_Level = read_btn_level;
btn->Button_Trigger_Level = btn_trigger_level;
btn->Button_Last_Level = btn->Read_Button_Level();
btn->Debounce_Time = 0;
btn->Long_Time_Record = 0;
SEGGER_RTT_printf(0,"button create success \n");
Add_Button(btn);
Print_Btn_Info(btn);
}
相應的回調函數,用戶可以將要處理的事件放在這段函數裏
/************************************************************
* @brief 相應的回調事件
* @param btn:處理的按鍵
* @return NULL
* @note 用戶可在這裏添加自己的事件處理函數
***********************************************************/
void Btn1_Down_CallBack(void *btn)
{
SEGGER_RTT_printf(0,"Btn1_Down_CallBack\n");
}
void Btn1_Double_CallBack(void *btn)
{
SEGGER_RTT_printf(0,"Btn1_Double_CallBack\n");
}
void Btn1_Long_CallBack(void *btn)
{
SEGGER_RTT_printf(0,"Btn1_Long_CallBack\n");
}
void Btn1_LongFree_CallBack(void *btn)
{
SEGGER_RTT_printf(0,"Btn1_LongFree_CallBack\n");
}
這是修改後,並應用的工程,希望從網絡中學習到更多的東西
鏈接:https://pan.baidu.com/s/1o3xpBR1_bWkAQx1kgv5yNA
提取碼:27pt