一般的開發(fā)板,給出的例程,對按鍵掃描的寫法如下:
#define KEY1 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10)
#define KEY2 HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_2)
uint8_t K1_Value;
uint8_t K2_Value;
void KEY_SCAN(void)
{
if (KEY1 == 0) {
delay(200); // 延時200毫秒
if(KEY1 == 0) { K1_Value= 1; }
else {K1_Value = 0;}
}
if (KEY2 == 0) {
delay(200); // 延時200毫秒
if(KEY2 == 0) { K2_Value= 1; }
else {K2_Value = 0;}
}
}
這種寫法非常簡陋,也就是害人害己,無法在實際項目中使用,很多有名氣的教授寫的教材也是這樣的。
以下是本人原創(chuàng)的按鍵掃描,經(jīng)過反復(fù)實驗,在DX103開發(fā)板上測試能正常工作。代碼可以在項目中使用。
/**
* @brief KEY Scan Structure definition
*/
typedef struct
{
uint16_t Shift_Cnt; /* 向下毫秒計數(shù),粘滯鍵掃描延遲和啟動標志,限制生成向上鍵值 */
uint16_t Up_Cnt; /* 向下毫秒計數(shù), 彈起鍵掃描延遲和啟動標志 */
uint16_t Down_Repeat; /* 限制500毫秒內(nèi)僅產(chǎn)生一次按下的鍵值 */
uint16_t Up_Repeat; /* 限制500毫秒內(nèi)僅產(chǎn)生一次彈起的鍵值 */
uint8_t Flag_KEY_Down_Process; /* KEY鍵按下處理標志 */
uint8_t Flag_KEY_Shift_Process; /* KEY粘滯鍵處理標志 */
uint8_t Flag_KEY_Up_Process; /* KEY鍵彈起處理標志 */
uint8_t Flag_KEY_Process; /* KEY鍵后續(xù)繼續(xù)處理標志 */
uint8_t Value; /* KEY當前鍵值 */
uint8_t Old_Value; /* KEY上一個鍵值 */
}KEY_TypeDef;
KEY_TypeDef KEY1, KEY2;
__IO uint8_t Flag_TIM2_Update = 0; /* 定時器2更新標志 */
/* 帶參數(shù)的宏功能(預(yù)編譯展開): 掃描GPIOx GPIO_PIN_x的單個按鍵 */
#define KEYX_SCAN(KEYx,GPIOx,GPIO_PIN_x) {\
KEYx.Value = HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_x);\
if(KEYx.Old_Value != KEYx.Value){\
if(KEYx.Old_Value == 1){\
if(KEYx.Down_Repeat == 0){\
KEYx.Flag_KEY_Down_Process = 1;\
KEYx.Down_Repeat = 500;\
}\
KEYx.Shift_Cnt = 800;\
} else {\
if(KEYx.Down_Repeat < 300){\
KEYx.Shift_Cnt = 0;\
KEYx.Up_Cnt = 0;\
if(KEYx.Up_Repeat == 0){\
KEYx.Flag_KEY_Up_Process = 1;\
KEYx.Up_Repeat = 500;\
}\
}\
}\
KEYx.Old_Value = KEYx.Value;\
}\
if(KEYx.Down_Repeat){--KEYx.Down_Repeat;}\
if(KEYx.Up_Repeat){--KEYx.Up_Repeat;}\
if(KEYx.Shift_Cnt){\
--KEYx.Shift_Cnt;\
if(KEYx.Shift_Cnt==0){\
KEYx.Value = HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_x);\
if(KEYx.Value == 0){\
KEYx.Flag_KEY_Shift_Process = 1;\
KEYx.Down_Repeat = 200;\
KEYx.Shift_Cnt = 200;\
} else {\
KEYx.Up_Cnt = 20;\
}\
KEYx.Old_Value = KEYx.Value;\
}\
}\
if(KEYx.Up_Cnt){\
--KEYx.Up_Cnt;\
if(KEYx.Up_Cnt==0){\
KEYx.Value = HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_x);\
if(KEYx.Value == 1){\
KEYx.Flag_KEY_Up_Process = 1;\
KEYx.Shift_Cnt = 0;\
KEYx.Up_Cnt = 0;\
}\
KEYx.Old_Value = KEYx.Value;\
}\
}\
}
/*
* @ KEY_SCAN
* @ Edit by wjandcf@gmail.com
* @ 2015-2-3
*/
void KEY_SCAN(void)
{
KEYX_SCAN(KEY1, GPIOB, GPIO_PIN_10); /* 掃描大蝦103開發(fā)板上的KEY1 */
KEYX_SCAN(KEY2, GPIOC, GPIO_PIN_2); /* 掃描大蝦103開發(fā)板上的KEY2 */
#if 0
/* 保留此段代碼,是為了讓大家了解按鍵掃描的基本流程 */
/* 按鍵掃描第一部分,快速的按下和彈起鍵值掃描 */
KEY1.Value = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
if(KEY1.Old_Value != KEY1.Value){
if(KEY1.Old_Value == 1){ /* 有鍵按下 */
if(KEY1.Down_Repeat == 0){
KEY1.Flag_KEY_Down_Process = 1; /* 按鍵按下標志 */
KEY1.Down_Repeat = 500; /* 500毫秒內(nèi)不再產(chǎn)生鍵按下標志 */
}
KEY1.Shift_Cnt = 800; /* 粘滯鍵產(chǎn)生的延遲時間,限制再產(chǎn)生向上按鍵 */
} else {
if(KEY1.Down_Repeat < 300){ /* (500-300)毫秒后才能產(chǎn)生向上按鍵 */
KEY1.Shift_Cnt = 0;
KEY1.Up_Cnt = 0;
if(KEY1.Up_Repeat == 0){
KEY1.Flag_KEY_Up_Process = 1; /* 按鍵彈起標志 */
KEY1.Up_Repeat = 500; /* 500毫秒內(nèi)不再產(chǎn)生鍵彈起標志 */
}
}
}
KEY1.Old_Value = KEY1.Value;
}
/* 按鍵掃描第二部分,粘滯鍵掃描,粘滯鍵后的彈起鍵掃描 */
if(KEY1.Down_Repeat){
--KEY1.Down_Repeat; /* 按鍵按下掃描時間限制,不為零限制再次生成 */
}
if(KEY1.Up_Repeat){
--KEY1.Up_Repeat; /* 按鍵彈起掃描時間限制,不為零限制再次生成 */
}
if(KEY1.Shift_Cnt){
--KEY1.Shift_Cnt; /* 粘滯鍵掃描延遲 */
if(KEY1.Shift_Cnt==0){
KEY1.Value = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
if(KEY1.Value == 0){
KEY1.Flag_KEY_Shift_Process = 1; /* 粘滯鍵標志 */
KEY1.Down_Repeat = 200; /* 粘滯鍵時,限制300毫秒內(nèi)不能生成按下鍵 */
KEY1.Shift_Cnt = 200; /* 200毫秒生成一次粘滯鍵 */
} else {
KEY1.Up_Cnt = 20; /* 發(fā)現(xiàn)有按鍵彈起,延遲20毫秒再檢查按鍵是否真正彈起 */
}
KEY1.Old_Value = KEY1.Value;
}
}
if(KEY1.Up_Cnt){ /* 在200毫秒的粘滯鍵生成時間限制里,每隔20毫秒檢查按鍵是否彈起 */
--KEY1.Up_Cnt;
if(KEY1.Up_Cnt==0){
KEY1.Value = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10);
if(KEY1.Value == 1){
KEY1.Flag_KEY_Up_Process = 1; /* 按鍵彈起標志 */
KEY1.Shift_Cnt = 0; /* 按鍵彈起,關(guān)閉粘滯鍵掃描 */
KEY1.Up_Cnt = 0; /* 按鍵彈起,關(guān)閉彈起鍵掃描 */
}
KEY1.Old_Value = KEY1.Value;
}
}
#endif
}
|