51模块_按键检测

按键检测

按键检测步骤:

  1. 判断按下
  2. 消抖(一般为5ms~10ms)
  3. 等待按键松开(可略)
  4. 检测松开

传统法

if 检测按键的按下, delay 来消抖, while 等待按键松开 。

程序:

sbit s4 = P3^3;            //单独使用一个 I/O 口,则需要使用 sbit 进行位定义 

void main() {
    while(1)
    {
        if(s4 == 0)              //检测是否有键按下
        {
            delay10ms();         //经过10ms的延时函数进行消抖
            if(s4 == 0)          //若P3^3仍然为低电平,则确实有键(s4)按下
            {
                dspbuf[0]++;       //第一位数码管的段码值 +1
                while(!s4);        //等待按键松开,等价于while(s4 == 0)
            }   
        }
        display();                 //数码管显示函数
    } }
    
//源码:https://blog.csdn.net/xiaocheng_sky/article/details/52124568

传统法使用了 whlie() 来等待按键松开,容易卡死程序,使后面的代码无法执行。


带有标志位的按键识别法

先定义一个 key_flag 作为按键标志位, if 检测按键的按下(当前按键与标识位 key_flag 对比), delay 来消抖,取反标识位 key_flag 的值,if 再次确认当前按键, 进行事件处理 , 通过mian函数的循环来检测按键的松开。
其中: 代码“key_flag = 1”的作用是:下次即便按键没有松手,程序跑完一圈之后,也不会再满足if((s4 == 0) && (!key_flag))的条件;同样,亦不会满足else if(s4 != 0)的条件,那么key_flag 不会被赋为0。综合以上情况,一次按键只会进行一次处理。当按键被释放后,以后的扫描则会满足else if(s4 != 0)的条件,那么key_flag 会被赋为0,则可以进行接下来的按键扫描了,如此反复……
程序:

sbit s4 = P3^3;
uchar key_flag = 0;                             //首先定义按键的标志位,并初始化为0
void key_scan()                                 //按键扫描函数
{
    if((s4 == 0) && (!key_flag))                //如果有键按下,则条件成立(有键按下,则s4为0;而 !key_flag为1)
    {
        delay10ms();                            //延时消抖
        key_flag = 1;                           //把标志位置为1
        if(s4 == 0)                             //如果确定有键按下
        {                      
            dspbuf[0]++;                        //进行事件处理(数码管显示值加1)
        }
    }
    else if(s4 != 0)                            //未按下按键
    {
        key_flag = 0;
    }
}

//源码:https://blog.csdn.net/xiaocheng_sky/article/details/52139480 

以上可以避免使用 while 函数造成的卡程序,但依旧使用了 delay 函数进行延时消抖,不够高效。


快速识别法

知识点:符号“^”为“异或”的计算机语言。
如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

先定义三个标志位: key_nowkey_flagkey_old
然后保证三个值的初始值与三个值的初始化状态相同。
下面程序中,当按键没按下时,now为1;flag为0;old为1。
当按键按下时,now为0;flag为(0 ^ 1) ^ 0 = 1;old为0;与没按下时不同。
当按键释放后,now为1;flag为(1 ^ 1) ^ 0 = 0;old为0;

uchar key_now = 1;                         //用处存储按键本次的状态(0表示按下,1表示未按下)
uchar key_flag = 0;                        //按键是否按下的标志(0表示按键未被按下,1表示按键被按下)
uchar key_old = 1;                         //用于存储按键上次的状态(0表示上次按下,1表示上次未按下)
sbit s4 = P3^3;
void key_scan()
{
    key_now = s4;
    key_flag = (key_now ^ key_old) ^ key_flag;
    key_old = key_now;
}

//计算key_flag为1的次数,消抖

//源码:https://blog.csdn.net/xiaocheng_sky/article/details/52146083 

简洁快速识别法(可识别长按)|建议使用

知识点1:c语言中&与&&的区别
&:按照位与操作,例如:0010&1101,结果为0000
&是java中的位逻辑运算:
eg: 2&3=2;
分析如下: 2的二进制为10 ;3的二进制为11 ; 逻辑&之后为10
&&:短路与,表示如果两个条件都成立则执行之后的逻辑;
例如:if(a0&&b0),意思就是if a为0并且b为0的时候,进行下一步操作。
|| 短路或。 A||B,只有当A为假的时候才会对B进行判断。若A为真,则不继续对B进行判断。
| 逻辑或。 A|B,会对A, B都进行判断
! 逻辑非,当操作数为true时,返回false,否则返回true。

知识点2:位异或运算:A ^ 0xff。代表操作数A逐位和0xff异或,它的结果是~A。
任何数与全0异或,值不变。
任何数与全1异或,值取反。
任何数与自己异或,值为0。

先定义两个标志位: TrgCont
保证三个值的初始值与三个值的初始化状态相同。
下面程序中,当按键没按下时,ReadData = 1 ^ 0xff = 0x00 ; Trg = 0 & (0 ^ 0)= 0 ; Cont = 0。三值分别为0,0,0。
当按键按下时,ReadData = 0 ^ 0xff = 1 ;Trg = 1 & (1 ^ 0) = 1 ; Cont = 1。          三值分别为1,1,1。
当按键长按时,ReadData = 0 ^ 0xff = 1 ; Trg = 1 & (1 ^ 1) = 0; Cont = 1。        三值一直保持为1,0,1。
当按键释放后,ReadData = 1 ^ 0xff = 0 ;Trg = 0 & (0 ^ 0) = 0 ; Cont = 0。          三值分别为0,0,0。

unsigned char Trg;
unsigned char Cont;
void KeyRead( void )
{
      unsigned char ReadData = PINB ^ 0xff; // 1
      Trg = ReadData & (ReadData ^ Cont); // 2
      Cont = ReadData; // 3
}
  • 16
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值