51单片机外设之——独立按键的检测(传统法一)

我刚开始学的单片机的时候,一直会热枕于一个操作——就是希望我自己能按一下键盘,让单片机去执行我想要的操作命令。但是就是被这种热枕所向往,以至于我一直没有去想它是怎么一个工作环境(一开始居然忘记联想到 C 语言的 if 条件语句!)。所以这里我以自身经历去奉劝大家,我们在憧憬于一件事的时候,不要忘记去力所能及的实现它!
接下来,我将分批次的把我对“按键”的理解记行分享。其中,按键的存在形式主要有两种:独立按键、矩阵按键。对于按键的扫描(用于让单片机知道我们是按下哪一个按键)主要与三种方法:传统的按键识别、带有标志位的按键识别、快速识别。
在此,我把传统的按键检测分为:延时消抖检测、外部中断检测。
这里,我首先来介绍延时消抖检测。

按键的原理图(我们先只看独立按键):
这里写图片描述
这里 J5 是一个排针, 用跳帽连接 J5 的2脚与3脚即可将键盘设置为独立按键(只有S4~S7有效)。此时,S4~S7一端分别与P3^3~P3^0相连,另一端连向GND。这样,我们先给P3^0~P3^3赋高电平(其实单片机上电时, I/O 口默认输出高电平。但是为了严谨,在扫描之前还是先用软件实现赋高电平)即可通过检测P3^0~P3^3处的电平是否出现低电平的状态,去查看哪个按键是否被按下。(当有按键按下时,则此按键连接的P3引脚的 I/O 口会从高电平变为低电平的状态)

再附上按键按下时,接触点实际的电压变化:
这里写图片描述
我上面所说,只要检测 I/O 口电压的变化,即可判断按键是否被按下,对于理想情况是可以检测准确的。但是从图所示,可以看到对于实际的波形,存在着按下时按键抖动以及松手时的按键抖动,这都会产生上上下下的不定向的电压值。所以不能完全只通过检测 I/O 口判断。
对于按下抖动,根据前人所给出的经验值,其时间一般不会超过10ms;过于释放抖动的过程,我们可以用while语句进行检测,检测按键是否松开,也是就是 I/O 口否恢复为高电平(因为程序在按键扫描之前,就将 I/O 口的值赋为高电平,虽然它被按键通过 GND 拉低到低电平状态,但是只要按键松开, I/O 口仍会变化原来的高电平状态)。

实例为:通过每按一次按键,使得数码管第一位的显示值每次加 1 ,满十则从零开始重新计数。
核心代码如下(其中,数码管显示函数以及段码的定义等,都引用上节的数码管博文):

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();                 //数码管显示函数
    }
}

其实在这里可以看到,当按键一直处于按下之后,程序会卡死在 while(!s4) 处。在这个时候,由于没有调用display()函数,数码管是不能显示的。解决方法有:
1、改变按键的扫描方式;
2、将display()函数放入中断,不停进行数码管显示。
怎么改变按键的扫描方式呢?什么又是中断?

未完待续……

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于51单片机独立按键双击后长按的驱动代码,供参考: ``` #include <reg51.h> #define KEY P3_3 // 定义按键连接的引脚 sbit LED = P1_0; // 定义 LED 连接的引脚 unsigned char key_buf = 0; // 按键缓存 unsigned char key_count = 0; // 按键计数器 unsigned char key_flag = 0; // 按键标志位 void delay_ms(unsigned int n); // 延时函数 void main() { KEY = 1; // 设置按键为输入模式 while(1) { if(KEY == 0) // 检测按键是否按下 { delay_ms(10); // 延时去抖动 if(KEY == 0) // 再次检测按键是否按下 { key_buf++; // 储存按键按下的次数 key_flag = 1; // 标记按键按下 } while(!KEY); // 等待按键释放 } if(key_flag) // 如果按键被按下 { delay_ms(10); // 延时去抖动 if(KEY == 0) // 如果按键没有释放 { key_count++; // 计数器加 1 if(key_count >= 100) // 如果按下超过 1 秒 { LED = 1; // 点亮 LED } } else // 如果按键释放了 { if(key_buf == 1) // 如果只按了一次 { LED = !LED; // 点亮 LED } else if(key_buf == 2) // 如果按了两次 { LED = 0; // 熄灭 LED } key_buf = 0; // 清空按键缓存 key_count = 0; // 清空计数器 key_flag = 0; // 清除按键标志位 } } } } void delay_ms(unsigned int n) { unsigned int i, j; for(i = 0; i < n; i++) { for(j = 0; j < 125; j++); } } ``` 该代码实现了以下功能: - 检测独立按键的按下和释放; - 记录按键的按下次数; - 判断按键是单击还是双击; - 判断按键是否长按; - 在 LED 上进行相应操作。 需要注意的是,该代码中的延时函数可能需要根据实际情况进行调整。同时,该代码只能处理一个按键,如果需要处理多个按键,需要进行相应的修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值