日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32F103按键操作的另一种实现——状态机

發布時間:2023/12/20 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32F103按键操作的另一种实现——状态机 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

#ifndef _KEY_H_ #define _KEY_H_#include "HAL_gpio.h" // 換成STM32F103對應的GPIO庫 #include "type.h" // type.h主要是一些類型的重命名#define KEY_UP_GRP GPIOA #define KEY_UP_IDX GPIO_Pin_9 #define KEY_UP_IS_DOWN() GPIO_ReadInputDataBit(KEY_UP_GRP, KEY_UP_IDX) #define KEY_UP_CONFIG() GPIOConfig(KEY_UP_GRP, KEY_UP_IDX, GPIO_Mode_IPU) // 這個函數我在之前帖子里面寫過#define KEY_DOWN_GRP GPIOA #define KEY_DOWN_IDX GPIO_Pin_10 #define KEY_DOWN_IS_DOWN() GPIO_ReadInputDataBit(KEY_DOWN_GRP, KEY_DOWN_IDX) #define KEY_DOWN_CONFIG() GPIOConfig(KEY_DOWN_GRP, KEY_DOWN_IDX, GPIO_Mode_IPU)#define KEY_FUNC_GRP GPIOA #define KEY_FUNC_IDX GPIO_Pin_11 #define KEY_FUNC_IS_DOWN() GPIO_ReadInputDataBit(KEY_FUNC_GRP, KEY_FUNC_IDX) #define KEY_FUNC_CONFIG() GPIOConfig(KEY_FUNC_GRP, KEY_FUNC_IDX, GPIO_Mode_IPU) #define KEY_TURN_GRP GPIOA #define KEY_TURN_IDX GPIO_Pin_12 | GPIO_Pin_13 #define KEY_TURN_IS_DOWN() GPIO_ReadInputDataBit(KEY_TURN_GRP, KEY_TURN_IDX) #define KEY_TURN_CONFIG() GPIOConfig(KEY_TURN_GRP, KEY_TURN_IDX, GPIO_Mode_IPU)//==================================================================================== typedef enum {CONFIRM_KEY = 1,FUNC_KEY,UP_KEY,DOWN_KEY } key_event_t;#define state_keyUp 0 //初始狀態,未按鍵 #define state_keyDown 1 //鍵被按下 #define state_keyLong 2 //長按 #define state_keyTime 3 //按鍵計時態#define return_keyUp 0x00 //初始狀態 #define return_keyPressed 0x01 //鍵被按過,普通按鍵 #define return_keyLong 0x02 //長按 #define return_keyAuto 0x04 //自動連發#define key_down 0 //按下 #define key_up 0xf0 //未按時的key有效位鍵值 #define key_longTimes 100 //10ms一次,200次即2秒,定義長按的判定時間 #define key_autoTimes 20 //連發時間定義,20*10=200,200毫秒發一次#define KEYS1_VALUE 0xe0 //keyS1 按下 #define KEYS2_VALUE 0xd0 //keyS2 按下 #define KEYS3_VALUE 0xb0 //keyS3 按下 #define KEYS4_5_VALUE 0x70 //keyS4_5 按下//==================================================================================== void KeyProcess(void); //T0定時器調用的工作函數 void KeyTimerInit(void);#endif /* _KEY_H_ */ #include <stdio.h> #include "key.h" #include "timer.h" // STM32F103定時器的配置static uint8_t key_get(void) //獲取P3口值 {if(KEY_UP_IS_DOWN() == key_down){return KEYS1_VALUE;}if(KEY_DOWN_IS_DOWN() == key_down){return KEYS2_VALUE;}if(KEY_FUNC_IS_DOWN() == key_down){return KEYS3_VALUE;}if(KEY_TURN_IS_DOWN() == key_down){return KEYS4_5_VALUE;}return key_up ; //0xf0 沒有任何按鍵 }//函數每20ms被調用一次,而我們彈性按鍵過程時一般都20ms以上 //所以每次按鍵至少調用本函數2次 static uint8_t key_read(uint8_t* pKeyValue) {static uint8_t s_u8keyState = 0; //未按,普通短按,長按,連發等狀態static uint16_t s_u16keyTimeCounts = 0; //在計時狀態的計數器static uint8_t s_u8LastKey = key_up ; //保存按鍵釋放時的P3口數據uint8_t keyTemp = 0; //鍵對應io口的電平int8_t key_return = 0; //函數返回值keyTemp = key_up & key_get(); //提取所有的key對應的io口switch(s_u8keyState) //這里檢測到的是先前的狀態{case state_keyUp: //如果先前是初始態,即無動作{if(key_up != keyTemp) //如果鍵被按下{s_u8keyState = state_keyDown; //更新鍵的狀態,普通被按下}}break;case state_keyDown: //如果先前是被按著的{if(key_up != keyTemp) //如果現在還被按著{s_u8keyState = state_keyTime; //轉換到計時態s_u16keyTimeCounts = 0;s_u8LastKey = keyTemp; //保存鍵值}else{s_u8keyState = state_keyUp; //鍵沒被按著,回初始態,說明是干擾}}break;case state_keyTime: //如果先前已經轉換到計時態(值為3){//如果真的是手動按鍵,必然進入本代碼塊,并且會多次進入if(key_up == keyTemp) //如果未按鍵{s_u8keyState = state_keyUp;key_return = return_keyPressed; //返回1,一次完整的普通按鍵//程序進入這個語句塊,說明已經有2次以上10ms的中斷,等于已經消抖//那么此時檢測到按鍵被釋放,說明是一次普通短按}else //在計時態,檢測到鍵還被按著{if(++s_u16keyTimeCounts > key_longTimes) //時間達到2秒{s_u8keyState = state_keyLong; //進入長按狀態s_u16keyTimeCounts = 0; //計數器清空,便于進入連發重新計數key_return = return_keyLong; //返回state_keyLong}//代碼中,在2秒內如果我們一直按著key的話,返回值只會是0,不會識別為短按或長按的}}break;case state_keyLong: //在長按狀態檢測連發 ,每0.2秒發一次{if(key_up == keyTemp){s_u8keyState = state_keyUp;}else //按鍵時間超過2秒時{if(++s_u16keyTimeCounts > key_autoTimes)//10*20=200ms{s_u16keyTimeCounts = 0;key_return = return_keyAuto; //每0.2秒返回值的第2位置位(1<<2)}//連發的時候,肯定也伴隨著長按}key_return |= return_keyLong; //0x02是肯定的,0x04|0x02是可能的}break;default:break;}*pKeyValue = s_u8LastKey ; //返回鍵值return key_return; } // 這個函數就是要在中斷中調用的。主要是使用事件隊列的方式。 void KeyProcess(void) {uint8_t key_stateValue;uint8_t keyValue = 0;uint8_t* pKeyValue = &keyValue;key_stateValue = key_read(pKeyValue);if ((return_keyPressed == key_stateValue) && (*pKeyValue == KEYS1_VALUE)){//短按keyS1時改變對時狀態,將其加入隊列,隊列的基本操作在將隊列的時候寫過。if(QueueEventIsEmpty(g_state_manager.process->key_event) ||(!QueueEventIsEmpty(g_state_manager.process->key_event) &&!QUEUE_EVENT_IS_EQUEL(g_state_manager.process->key_event, UP_KEY))){QueueEventPush(g_state_manager.process->key_event, UP_KEY);}} }//====================================================================================== void KeyTimerInit(void) {KEY_UP_CONFIG();KEY_DOWN_CONFIG();KEY_FUNC_CONFIG();KEY_TURN_CONFIG();// 20msTimerConfig(KEY_TIMER, KEY_TIMER_DIV, KEY_TIMER_PERIOD);TimerDisable(KEY_TIMER);TimerEnable(KEY_TIMER); }主要是描述一下按鍵狀態機的思維,使用定時器中斷的方法,按鍵按下將其加入隊列中,在主函數的循環中實現出隊。親測可用。


總結

以上是生活随笔為你收集整理的STM32F103按键操作的另一种实现——状态机的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。