外部按键KEY中断
我板子上的按键是按键按下读取低电平抬起读取高电平
#ifndef _KEY_H
#define _KEY_H
#include "sys.h"
#define KEY_1 KEY_RET
#define KEY_2 KEY_VOID
#define KEY_3 KEY_SET
#define KEY_4 KEY_DOWN
#define KEY_5 KEY_RIGHT
#define KEY_6 KEY_INC
typedef enum
{
KEY_RET,
KEY_VOID,
KEY_SET,
KEY_RIGHT,
KEY_DOWN,
KEY_INC,
NONE,//没有任何键被按下
}KEY_VALUE;
typedef struct
{
int key_dpress_flag;
int key_dpress_count;
int key_duration_flag;
float key_duration;
}KEY_STATUS;
typedef struct
{
u8 key_suf;
u8 key_flag;
KEY_VALUE key_value_read;
}KEY_DETECT_T;
extern KEY_STATUS ks;
extern KEY_DETECT_T kd;
void GetKeyValue(void);
void KeyDeal(void);
#endif
#include "key.h"
#include "lcd_st7920.h"
#include "usart.h"
#include "low_pwr.h"
KEY_DETECT_T kd={0,0,NONE};
KEY_STATUS ks={1,0,1,0};
void GetKeyValue(void)
{
kd.key_suf=(GPIOE->IDR)&0xfc;
if(kd.key_suf!=0xfc)
{
if(kd.key_suf==0x7c)
{
kd.key_value_read=KEY_1;//KEY_RET
}
else if(kd.key_suf==0xbc)
{
kd.key_value_read=KEY_2;//KEY_VOID免装按键(WKUP键)
}
else if(kd.key_suf==0xdc)
{
kd.key_value_read=KEY_3;//KEY_SET
}
else if(kd.key_suf==0xec)
{
kd.key_value_read=KEY_4;//KEY_DOWN
}
else if(kd.key_suf==0xf4)
{
kd.key_value_read=KEY_5;//KEY_RIGHT
}
else if(kd.key_suf==0xf8)
{
kd.key_value_read=KEY_6;//KEY_INC
}
}
}
void KeyDeal(void)
{
if(kd.key_value_read==KEY_RET)
{
printf("KEY_RET PRESS\r\n");
kd.key_value_read=NONE;
}
if(kd.key_value_read==KEY_SET)
{
printf("KEY_SET PRESS\r\n");
kd.key_value_read=NONE;
}
if(kd.key_value_read==KEY_VOID)//WKUP低功耗唤醒键
{
printf("KEY_VOID PRESS\r\n");
kd.key_value_read=NONE;
low_pwr_struct.low_pwr_count=LOW_PWR_COUNTDOWN;//每次按下都更新countdown值
if(low_pwr_struct.low_pwr_flag)
{
low_pwr_struct.low_pwr_flag=0;
low_pwr_struct.low_pwr_count=LOW_PWR_COUNTDOWN;
LOW_PWR_Exit();
}
}
if(kd.key_value_read==KEY_DOWN)
{
printf("KEY_DOWN PRESS\r\n");
kd.key_value_read=NONE;
}
if(kd.key_value_read==KEY_RIGHT)
{
printf("KEY_RIGHT PRESS\r\n");
kd.key_value_read=NONE;
}
if(kd.key_value_read==KEY_INC)
{
printf("KEY_INC PRESS\r\n");
kd.key_value_read=NONE;
}
}
按键消抖和长短按检测
很多按键消抖的博客里说的在外部中断函数中做hal_delay,我认为这种方法不合理,在中断中做delay永远是不合理的因为中断肯定是要快进快出的,在里面做delay很容易出问题。所以我只在外部中断IRQ里置标志位,然后在定时器TIM2里面做加法定时,整个流程完全不用delay。
在初始化KEY_STATUS时ks.key_dpress_flag和ks.key_duration_flag被初始化为1,按键按下下降沿触发中断ks.key_dpress_flag置0
ks.key_dpress_flag置0后进入TIM2中断,ks.key_dpress_count++开始计数当ks.key_dpress_count++>=6也就是5*6=30ms之后才会进入读取电平确认是否已按下,换句话说就是按下之后的30ms是消抖时间。确定按键被按下之后将ks.key_dpress_flag置1同时将ks.key_dpress_count置0直到上升沿再次触发,接着将ks.key_duration_flag置0开始按下时间计时ks.key_duration++。
案件抬起消抖也一样,再次进入定时器中断函数30ms之后读取电平确定是否抬起,然后ks.key_dpress_flag置1,ks.key_dpress_count清零,ks.key_duration_flag置1停止计时,直到下次下降沿触发。然后读取ks.key_duration值并转化为单位秒
/* USER CODE BEGIN 1 */
/**********************************************
功能说明: 定时器中断回调函数
入口参数:
返回参数:
***********************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//5ms
if(htim == (&htim2))
{
//消抖+长短按检测
if(!ks.key_dpress_flag)
{
ks.key_dpress_count++;
if(ks.key_dpress_count>=6)//消抖6*5ms=30ms
{
if((HAL_GPIO_ReadPin(GPIOE,KEY_1_EXTI7_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_2_EXTI6_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_3_EXTI5_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_4_EXTI4_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_5_EXTI3_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_6_EXTI2_Pin))==GPIO_PIN_RESET)//按键按下消抖
{
ks.key_dpress_flag=1;//按键按下标志位置1直到上升沿再次触发
ks.key_dpress_count=0;
ks.key_duration_flag=0;
GetKeyValue();
KeyDeal();
}
if((HAL_GPIO_ReadPin(GPIOE,KEY_1_EXTI7_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_2_EXTI6_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_3_EXTI5_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_4_EXTI4_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_5_EXTI3_Pin)&\
HAL_GPIO_ReadPin(GPIOE,KEY_6_EXTI2_Pin))==GPIO_PIN_SET)//按键抬起消抖
{
ks.key_dpress_flag=1;//按键按下标志位置1直到下降沿再次触发
ks.key_dpress_count=0;
ks.key_duration_flag=1;
ks.key_duration*=0.005;
printf("key_duration:%05.2fs\r\n",ks.key_duration);
printf("\r\n");
}
}
}
//按键按下计时
if(!ks.key_duration_flag)
{
ks.key_duration++;
}
//低功耗计时
if(!low_pwr_struct.low_pwr_flag)
{
low_pwr_struct.low_pwr_count--;
if(low_pwr_struct.low_pwr_count<0)//1min
{
low_pwr_struct.low_pwr_flag=1;
low_pwr_struct.low_pwr_count=0;
LOW_PWR_Enter();
}
}
//LCD忙检测超时
if(lcd.lcd_busy_overtime>0)
{
lcd.lcd_busy_overtime--;
}
}
//100us
if(htim == (&htim3))
{
}
}
整个消抖流程不会对程序造成任何阻滞
执行效果