常用的按键触发方式采用延时消抖策略,比如如下:
u8 Key_Scan(void){
static u8 key_sta=1;
if(!key && key_sta){
delay_ms(10);
if(!key){
key_sta=0;
return 1;
}
}
if(key) key_sta=1;
return 0;
}
这种方式是轮询检测的,也是最简单的按键触发,不过按键触发采用了10ms的延时消抖,这部分时间对于要求系统高响应来说是比较大影响的。按键触发方式还有另外一种,就是外部中断触发,响应速度快,不占用太大的时间,我采用stm32的hal库设计如下:
GPIO_InitTypeDef GPIO_InitStruct;
void Key_Init(void){
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Mode=GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pin=GPIO_PIN_0;
GPIO_InitStruct.Pull=GPIO_PULLDOWN;
GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
}
void EXTI0_IRQHandler(void){
HAL_GPIO_EXTI_IRQHandler(GPIO_InitStruct.Pin);
}
void HAL_GPIO_EXTI_Callback(u16 GPIO_Pin){
if(GPIO_Pin==GPIO_PIN_0){
//代码实现
}
}
不过在代码实现区域有的时候也得加上一定的延时来防止重复触发,因此这种方法也占用了一定的系统时间。还有一种方法,就是使用计时代替延时,需要另外再初始化一个定时器,在其内部对按键触发的延时值做计时处理,如下:
u8 Key_Flag; //按键标记
u8 Key_DelayCnt; //按键延时值
#define C_Key_Delay 0x01 //延时状态
#define C_Key_Disable 0x02 //按键失效标记
#define key PAin(0) //按键GPIO口
//按键初始化,采用GPIOA的下拉输入
void Key_Init(void){
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Mode=GPIO_MODE_INPUT;
GPIO_InitStruct.Pin=GPIO_PIN_0;
GPIO_InitStruct.Pull=GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
Key_DelayCnt=0;
Key_Flag=0;
}
//按键扫描,放在主函数中,有按键触发时返回1
u8 Key_Scan(void){
if(Key_Flag & C_Key_Delay){ //判断按键是否进入延时状态
if(!Key_DelayCnt){ //判断按键延时值是否为0,即按键延时是否结束
Key_Flag &= ~C_Key_Delay; //按键延时结束,取消延时状态
if(key){ //按键仍然按下中,说明按键有效
Key_Flag |= C_Key_Disable; //按键标记失效
return 1;
}
}
else if(!key){ //如果按键延时未结束,且此时按键抬起,则按键无触发,清除所有标记(初始化按键)
Key_Flag=0;
}
}
else{ //按键未进入延时状态
if((Key_Flag & C_Key_Disable)==0){ //按键未失效,说明在此之前没有任何按键按下
if(key){ //如果此时按键被按下
Key_Flag |= C_Key_Delay; //按键进入延时状态
Key_DelayCnt=10; //按键延时值赋值
}
}else if(!key){ //按键在失效情况下检测到按键已经抬起,则清楚按键所有标记,初始化按键
Key_Flag=0;
}
}
return 0;
}
//按键1ms延时函数,必须将此函数放在1ms中断定时器中
void Key_1MS_IRQ(void){
if(Key_Flag & C_Key_Delay){ //按键已经进入延时状态
if(Key_DelayCnt) Key_DelayCnt--; //对延时值自减
}
}
采用Key_Flag的两位来做按键的标志,轮询的方式实时监测按键,其中Key_1MS_IRQ函数必须放在一个1ms的定时器中,也可以直接放在滴答定时器中断里面。该功能不采用delay函数进行延时,可以释放部分系统资源,对资源分配也比较友好。
如果系统采用RTOS多任务,则可以采用第一种延时方法,代码量小,在延时过程中进入阻塞状态,将系统资源分配给其他任务。
第一次写博文,内容有什么不对请指教,谢谢啦!