首页 >> 大全

基于STM32按键的防抖和松开处理:状态机

2023-08-08 大全 31 作者:考证青年

用延时和while();去处理按键很浪费资源,这里我们用定时器来做一个按键的处理-状态机;

typedef enum {KEY_RELEASED,KEY_PRESSED,KEY_PROCESSED}KEY_STATUS;//释放           按下          处理过的
typedef struct {uint8_t  byCounter;//按键是否有效KEY_STATUS eKeyStatus;//按键状态
}KEY_ATTRIB;
KEY_ATTRIB Key_up,Key0,Key1,Key2;

首先我们定义了一个枚举,里面有三个元素,这个三个元素代表按键的三种状态。,按键松开状态,,按键按下状态

,按键已被处理状态

然后我们在定义一个结构体,里面有两个类型一个按键检测标志(后面我们将通过这个标志来防抖及松开判断),一个为该按键当前状态。

定义四个按键,Key0,Key1,Key2

我们用的硬件为原子的阿波罗开发板,芯片是,上面有四个按键

这里我们将四个按键连接的引脚配置为输入,然后在开一个定时器4,周期为10ms。在将串口2打开。

这是我们的定时器回调函数

void HAL_TIM_PeriodElapsedCallback (TIM_HandleTypeDef *htim)
{if (htim->Instance == htim4.Instance){Key_up.byCounter <<= 1;Key0.byCounter   <<= 1;Key1.byCounter   <<= 1;Key2.byCounter   <<= 1;if ( HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==1)//KEYUP{Key_up.byCounter++;if (Key_up.byCounter==0xff)//检测按键是否有效{if (Key_up.eKeyStatus != KEY_PROCESSED)//判断是否为处理过的按键Key_up.eKeyStatus = KEY_PRESSED;//标记为一个未处理的按键}}else{if ((Key_up.byCounter == 0x00)&&(Key_up.eKeyStatus == KEY_PROCESSED))Key_up.eKeyStatus = KEY_RELEASED;//标记为一个被释放的按键}if ( HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_3)==0)//KEY0{Key0.byCounter++;if (Key0.byCounter==0xff)//检测按键是否有效{if (Key0.eKeyStatus != KEY_PROCESSED)//判断是否为处理过的按键Key0.eKeyStatus = KEY_PRESSED;//标记为一个未处理的按键}}else{if ((Key0.byCounter == 0x00)&&(Key0.eKeyStatus == KEY_PROCESSED))Key0.eKeyStatus = KEY_RELEASED;//标记为一个被释放的按键}if ( HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_2)==0)//KEY1{Key1.byCounter++;if (Key1.byCounter==0xff)//检测按键是否有效{if (Key1.eKeyStatus != KEY_PROCESSED)//判断是否为处理过的按键Key1.eKeyStatus = KEY_PRESSED;//标记为一个未处理的按键}}else{if ((Key1.byCounter == 0x00)&&(Key1.eKeyStatus == KEY_PROCESSED))Key1.eKeyStatus = KEY_RELEASED;//标记为一个被释放的按键}if ( HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==0)//KEY2{Key2.byCounter++;if (Key2.byCounter==0xff)//检测按键是否有效{if (Key2.eKeyStatus != KEY_PROCESSED)//判断是否为处理过的按键Key2.eKeyStatus = KEY_PRESSED;//标记为一个未处理的按键}}else{if ((Key2.byCounter == 0x00)&&(Key2.eKeyStatus == KEY_PROCESSED))Key2.eKeyStatus = KEY_RELEASED;//标记为一个被释放的按键}}}

在tim4的回调函数里我们将四个按键的向左1移动一位。

然后当有按键按下,比如键按下,

开始自增。

第一次进回调函数,

.左移一位,.值为0(初始默认为0)

然后.自增,

.为0x01,

第二次进入回调函数

.左移一位,.值为0x02

然后.自增,

.为0x03,

以此类推,第八次进入回调函数时.自增后为0xff,这时我们就判定他为有效按键,这样其实就是我们的防抖为80ms,在这里我们目前先将按键模式规定为按下后必须松开,再次按下才行,这样当我们判定为有效按键时,我们接着判断是不是一个处理过的按键,不是OK,标记为新的按键

if (. != )//判断按键是否被处理过

. = ;//标志为一个未处理的按键

然后当松开按键,因为每次进回调函数,都会左移,所以松开按键80ms后

会为0,也就是松开的防抖80ms。我们再去判断一下按键被处理了没,处理了就将按键标记为释放(其实这个也可以不用判断处理了没,当为0我们就可以直接标记为释放,因为80ms,对于芯片算很长一段时间了)。

Key1、Key2、Key3的原理同上。

然后就去处理按键

	  if(Key_up.eKeyStatus==KEY_PRESSED){HAL_UART_Transmit(&huart2, (uint8_t *)"Key_up", 6, 0xFFFF);Key_up.eKeyStatus=KEY_PROCESSED;}if(Key0.eKeyStatus==KEY_PRESSED){HAL_UART_Transmit(&huart2, (uint8_t *)"Key0", 4, 0xFFFF);Key0.eKeyStatus=KEY_PROCESSED;}if(Key1.eKeyStatus==KEY_PRESSED){HAL_UART_Transmit(&huart2, (uint8_t *)"Key1", 4, 0xFFFF);Key1.eKeyStatus=KEY_PROCESSED;}if(Key2.eKeyStatus==KEY_PRESSED){HAL_UART_Transmit(&huart2, (uint8_t *)"Key2", 4, 0xFFFF);Key2.eKeyStatus=KEY_PROCESSED;}

这里当检测到按键按下时,向串口发送其按键的名字,然后将按键标记为处理过的按键。

当然可能有些朋友觉得这样有点烦,假如我要从0加到100(假设就一个按键),就得按100下,那就是需要连续响应,这里只需你在处理完按键,将标记为处理过的按键步骤改为将清0然后,标记按键为释放。这样你一直按着就会不断的去响应,清0 主要起一个延时的作用,不然响应太快!

	  if(Key_up.eKeyStatus==KEY_PRESSED){test++;HAL_UART_Transmit(&huart2, (uint8_t *)&test, 1, 0xFFFF);Key_up.byCounter=0;Key_up.eKeyStatus=KEY_RELEASED;}

采用在这种机制,当按键一直在按下状态,也不会影响其他按键的操作。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了