我们在单片机开发的时候,因为各种因素,一个按键肯定不能只有一个功能,所以,我们应该怎么判断它到底是什么功能呢?
这里我们需要想想一下按键按下的过程,我们按下按键,因为按键有弹性,所以会有一段时间的波动,这个时间大概是几十us,在这个过程中,当前IO口会有几次高低电频转换,我们都知道单片机开发的时候都是在判断IO口是高电频还是低电频来判断案件是否按下,这里这个过程就会导致按键多次促发,所以一般初学者都会给按键按键以后一段时间的延时再来判断按键是否按下,就像下面这段代码
uint8_t Key_Scan(void)
{
uint8_t key_flag = 0;
if(!KEY1)
{
delay_us(20);
if(!KEY1)
{
key_falg = 1;
}
while(!KEY1);
delay_us(20);
}
return key_flag;
}
这个代码用延时来消除案件的抖动,但是按键如果是低电频就会一直促发,可是我们只需要按键处理一次,所以用一个while来等待按键释放,再延时等待释放过程中的抖动,但是这个代码会打断我们本身过程中的代码,会让我们的代码卡在这里不会执行后面的代码,所以我们就要用一种循环消抖的方法来消除抖动,并且用标志位来防止按键不会多次促发,如果标志位为1,我们就证明按键按下就不再读取按键或者是处理其他事件,首先我们用模块化的建一个.h文件
#ifndef _button_h_
#define _button_h_
#define KEY_DEBOUNCE_TIME 20
typedef struct{
uint8_t Key_Flag : 1;
uint16_t Key_Out;
} KeyState;
uint8_t Key_Output(uint8_t Key_Input, KeyState *keystate, uint8_t key_num_size);
#endif
我们用一个结构体来封装按键的标志位等各种需要封装的东西,然后我们定义一个函数
来进行按键的消抖操作,这里我们需要一个参数,这个参数传递当前io口的状态
下面我们开始编写函数内容
#include "button.h"
uint8_t Key_output(uint8_t Key_Input, KeyState *keystate, uint8_t key_num_size)
{
uint_t key_num = 0;
if (Key_Input)
{
keystate->key_out = 0;
keystate->Key_Flag = 0;
} else if (!keystate->Key_Flag) {
keystate->Key_Out++;
if (keystate->Key_Out == KEY_DEBOUNCE_TIME)
{
keystate->Key_Flag = 1;
key_num = key_num_size;
}
}
return key_num;
}
这里我们集中解释一下代码,首先我们判断一下案件是否按下,如果没有按下,我们就把标志位和计数位清零,否则就是按键按下,然后我们在判断一下标志位是否位1,如果为1就证明按键按下,就不用继续计数了,等待按键释放标志位重载为0,如果为0,就会对计数位进行累加,直到它加到循环次数足够,就会给标志位值1,然后赋键值给key_num,然后返回出去,然后再进来,key_num就会重载初值,不会再继续给案件赋值
那么循环消抖的内容就这么多,下次我们继续介绍长按的判断