STM32F103按键操作的另一种实现——状态机
生活随笔
收集整理的這篇文章主要介紹了
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按键操作的另一种实现——状态机的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 决策树——CART和模型树
- 下一篇: ros学习-中国大学MOOC---《机器