数码之家

 找回密码
 立即注册
搜索
查看: 1903|回复: 7

[C51] 单片机入门杂谈(三):按键

[复制链接]
发表于 2023-6-4 17:41:27 | 显示全部楼层 |阅读模式
本帖最后由 mmxx2015 于 2023-6-4 18:18 编辑

单片机入门杂谈(一):调试器
https://www.mydigit.cn/thread-384952-1-1.html
单片机入门杂谈(二):程序结构
https://www.mydigit.cn/thread-386258-1-1.html



    按键是单片机最常见的人机交互接口之一,按键的形式有多种,根据工作原理大致分为两种:直接改变检测输入端在高低电平之间切换的机械按键,如轻触按键、薄膜按键、导电胶按键;检测感应量变化的按键,如检测电容/电阻/压力等变化的按键。机械轻触按键是原理最简单、成本最低、最常用的按键,下面就以轻触按键为例讲一下按键在单片机中的使用方法。

    机械按键输入端在按键未按下前需要保持固定的低电平/高电平,根据检测电平分为下拉输入和上拉输入,两种电路原理如下图,两种电路没有优劣之分,根据单片机引脚功能和设计者的喜好使用,如单片机输入端口有内部下拉/上拉电阻、端口只能上升沿/下降沿唤醒等。下面以上拉输入检测低电平方式讲一下轻触按键的处理。



    按键按下,单片机引脚输入信号是怎样的呢?根据上面的示意图,大家都知道输入信号由高电平变成低电平,信号大致如下图。

   
    按键按下瞬间,输入引脚信号是怎么变化的呢?好的按键按下时信号大致大致如下图。


   
    轻触按键是通过下压按键里的金属弹片使按键两个触点连通从而改变按键输入脚的状态,用久了里面的触点接触电阻变大,输出信号在按下时或按下过程中可能发生多次变化,如下图。

   
    要减少或消除这种状态短时间跳变的影响,按键扫描时可多次读取引脚状态,取半数以上的状态为输入状态,如读取5次,读到2次高电平、3次低电平,判定输入状态为低电平,单次按键扫描过程大致如下图。


   实现上述逻辑的程序大致如下:

  1.         实现上述逻辑的程序大致如下:

  2. #define        C_KEY_SCAN_READ_TIMES        10        //按键扫描读I/O次数

  3. unsigned char Keyscan(void)
  4. {
  5.         unsigned char        i;
  6.         unsigned char        Key_Down_Count[4];
  7.         unsigned char        Key_Value;
  8.         
  9.         
  10.         Key_Down_Count[0]=0;
  11.         Key_Down_Count[1]=0;
  12.         Key_Down_Count[2]=0;
  13.         Key_Down_Count[3]=0;
  14.         
  15.         Key_Value=0;
  16.         
  17.         i=C_KEY_SCAN_READ_TIMES;        //每次按键扫描读取若干次状态
  18.         
  19.         do
  20.         {
  21.                 if(!Key_S1())
  22.                 {
  23.                         Key_Down_Count[0]++;        //按下计数+1
  24.                 }
  25.                
  26.                 if(!Key_S2())
  27.                 {
  28.                         Key_Down_Count[1]++;
  29.                 }
  30.         
  31.                 if(!Key_S3())
  32.                 {
  33.                         Key_Down_Count[2]++;
  34.                 }
  35.         
  36.                 if(!Key_S4())
  37.                 {
  38.                         Key_Down_Count[3]++;
  39.                 }
  40.         }while(--i);
  41.         
  42.         if(Key_Down_Count[0]>=((C_KEY_SCAN_READ_TIMES+1)/2))        //半数以上状态为按下状态
  43.         {
  44.                 Key_Value|=0x01;
  45.         }

  46.         if(Key_Down_Count[1]>=((C_KEY_SCAN_READ_TIMES+1)/2))
  47.         {
  48.                 Key_Value|=0x02;
  49.         }
  50.         
  51.         if(Key_Down_Count[2]>=((C_KEY_SCAN_READ_TIMES+1)/2))
  52.         {
  53.                 Key_Value|=0x04;
  54.         }
  55.         
  56.         if(Key_Down_Count[3]>=((C_KEY_SCAN_READ_TIMES+1)/2))
  57.         {
  58.                 Key_Value|=0x08;
  59.         }
  60.         
  61.         return        Key_Value;
  62. }
复制代码

    要可靠地检测按键动作,不能以一次信号状态判定按键按下/释放,需要多次采集、判断,也就是通常说的按键消抖。按键消抖有人喜欢检测到一次按键信号后延时一段时间再确认一次,但多数程序的消抖方法是多次状态确认,这种方法可以方便可靠地改变按键确认时间,做长按单次响应、长按多次响应、按下释放再响应也很方便。按键短按多次确认逻辑大致如下图。





    实现上述逻辑的程序大致如下:

  1. #define        C_DEBOUNCE_SHORT                (30/10)                //轻触按键消抖时间(单位:10毫秒)
  2. #define C_DEBOUNCE_LONG                        (2000/10)        //长按键时间(单位:10毫秒)
  3. #define C_DEBOUNCE_CONTINUE_FIRST        (2000/10)        //首次连按时间(单位:10毫秒)
  4. #define C_DEBOUNCE_CONTINUE_INTERVAL        (100/10)        //连按键间隔时间(单位:10毫秒)
  5.         
  6. void Key_Debounce(unsigned char Key_Value)
  7. {
  8.         Short_Key_Flag=0;        //短按
  9.         Long_Key_Flag=0;        //长按
  10.         Continue_Key_Flag=0;        //连按

  11.         if((Key_Value==0)||(Key_Value!=Key_Debounce_Save))
  12.         {
  13.                 Key_Debounce_Short=0;                //短按键消抖计时
  14.                 Key_Debounce_Long=0;                //长按键消抖计时
  15.                 Key_Debounce_Continue=0;        //连按键消抖计时
  16.         }
  17.         else
  18.         {
  19.                 Key_Debounce_Short++;
  20.                 if(Key_Debounce_Short==C_DEBOUNCE_SHORT)
  21.                 {
  22.                         Key_Debounce_Short=C_DEBOUNCE_SHORT;
  23.                         Short_Key_Flag=1;        //短按键
  24.                 }

  25.                 Key_Debounce_Long++;
  26.                 if(Key_Debounce_Long==C_DEBOUNCE_LONG)
  27.                 {
  28.                         Long_Key_Flag=1;        //长按键
  29.                 }
  30.                 else if(Key_Debounce_Long>C_DEBOUNCE_LONG)
  31.                 {
  32.                         Key_Debounce_Long=C_DEBOUNCE_LONG;        //长按只响应一次
  33.                 }

  34.                 Key_Debounce_Continue++;
  35.                 if(Key_Debounce_Continue==(C_DEBOUNCE_CONTINUE_FIRST+C_DEBOUNCE_CONTINUE_INTERVAL))
  36.                 {
  37.                         Key_Debounce_Continue-=C_DEBOUNCE_CONTINUE_INTERVAL;

  38.                         Continue_Key_Flag=1;        //连按键
  39.                 }
  40.         }

  41.         Key_Debounce_Save=Key_Value;        // 保存本次键值
  42. }
复制代码

    有时我们需要按键短按、长按分别执行不同的功能,如短按开灯、长按关灯,这时就需要把短按键改为按键释放时响应。程序大致如下:

  1.         if(Short_Key_Flag)        //短按键按下,标记
  2.         {
  3.                 Key_Down_Flag=1;
  4.         }
  5.         
  6.         if(Long_Key_Flag)        //长按键按下,清除标记
  7.         {
  8.                 Long_key_Process();        //长按键处理
  9.                
  10.                 Key_Down_Flag=0;
  11.         }
  12.         
  13.         if(Key_Value==0)        //所有按键释放
  14.         {
  15.                 if(Key_Down_Flag)
  16.                 {
  17.                         Short_key_Process();        //短按键处理
  18.                         
  19.                         Key_Down_Flag=0;
  20.                 }
  21.         }
复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 1家元 +30 收起 理由
IlovePLC + 30 原創內容

查看全部打赏

发表于 2023-6-4 18:36:54 来自手机浏览器 | 显示全部楼层
技术贴都得赞一个!!
回复 支持 反对

使用道具 举报

发表于 2023-6-4 19:23:34 | 显示全部楼层
开个系统定时器做任务调度,或系统监测,如5mS 反思自己一次,对按键连续10次就算有效
如STC8/STC32的定时器0的模式三,是不可屏蔽的中断,专门设计来做:按键处理任务调度




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

发表于 2023-6-4 19:28:50 | 显示全部楼层
详尽。不过从实用角度讲,3毛钱的 触摸按钮 可以平替物理按键,不需要消抖,只需要判断单双击 https://www.bilibili.com/video/BV1nM4y1e7Um/
回复 支持 反对

使用道具 举报

发表于 2023-6-4 21:33:49 | 显示全部楼层
终于看到楼主的续贴了,学到了新的按键判断理念。
回复 支持 反对

使用道具 举报

发表于 2023-6-4 22:40:42 | 显示全部楼层
我还没学会状态机结构,楼主讲一下按键状态机程序结构吧
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-4 22:57:17 来自手机浏览器 | 显示全部楼层
IlovePLC 发表于 2023-6-4 22:40
我还没学会状态机结构,楼主讲一下按键状态机程序结构吧

说具体些。
回复 支持 反对

使用道具 举报

发表于 2023-6-5 13:50:30 来自手机浏览器 | 显示全部楼层
我也想了解一下简单的状态机…
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-21 04:28 , Processed in 0.140400 second(s), 11 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表