zoukankan      html  css  js  c++  java
  • 单片机按键学习总结

    基本的按键程序结构分析:

     1 void key_scan(void)
     2 {
     3       if (!key)                           //检测按键是否按下
     4       {
     5           delay_ms(20);                   //延时去抖,一般20ms
     6           if(!key)
     7           {
     8                ......
     9           }
    10           while (!key);                   //等待按键释放
    11      }       
    12 }            

    注意:以上基本按键程序中,在按键执行之后必须要加上等待按键释放,否则程序会出现一些奇怪的问题,比如说按键累加时按键一次,却累加了多次。

    可识别长击和短击按键程序(有限状态机):

    主函数文件:

    main.c

     1 #include "key.h"
     2 
     3 sbit LED = P2^0;
     4 
     5 u8 timer0_flag;                                    //定时器10ms计时标记
     6 
     7 
     8 void timer0_init(void)
     9 {
    10     TMOD |= 0x01;                                 //定时器0的方式1(16位定时器)
    11     TH0 = 0xDC;                                    //定时10ms初值
    12     TL0 = 0x00;
    13     
    14     ET0 = 1;
    15     TR0 = 1;
    16     EA  = 1;
    17 }
    18 
    19 void main(void)
    20 {
    21     key_init();                                    //按键初始化,51单片机在读取某个端口的值时,先拉高
    22     timer0_init();                                 //定时器初始化
    23     
    24     for (;;)    
    25     {
    26         if (timer0_flag)
    27         {
    28             timer0_flag = 0;
    29             
    30             switch (key_driver())    
    31             {
    32                 case KEY_SHORT: LED = 0; break;    //短击点亮LED灯
    33                 case KEY_LONG : LED = 1; break;    //长击熄灭LED灯
    34             }
    35         }
    36     }
    37 }
    38 
    39 void timer0_int(void) interrupt 1                //中断处理函数
    40 {
    41     TH0 = 0xDC;
    42     TL0 = 0x00;
    43     timer0_flag = 1;
    44 }

    主文件里非常重要的有两处:

    1、时间粒度控制:本程序以10ms做时间单位,类似于时间片轮询的方式,每隔10ms对按键状态扫描一次,对应代码为:

    void timer0_int(void) interrupt 1                //中断处理函数

    {     

      TH0 = 0xDC;     

      TL0 = 0x00;     

      timer0_flag = 1;       //10ms时间

     }

    2对按键驱动函数返回值的判断,根据按键返回值,识别按键操作是短击还是长击后,执行相应的动作,对应代码为:

    switch (key_driver())    

    {      case KEY_SHORT: LED = 0; break;    //短击点亮LED
          case KEY_LONG : LED = 1; break;    //长击熄灭LED

    }

    按键驱动文件:

    key.c

     1 #include "key.h"
     2 
     3 sbit KEY_INPUT = P3^3;                                         //独立按键
     4 
     5 key custom_key;                                                //按键的数据结构体
     6 
     7 void key_init(void)                                            //按键初始化
     8 {
     9     KEY_INPUT = 1;
    10 }
    11 
    12 u8 key_driver(void)                                            //按键驱动函数
    13 {
    14     custom_key.press = KEY_INPUT;                              //读取按键接口值
    15     custom_key.value = KEY_NONE;                               //返回值初始化为无值
    16     
    17     switch(custom_key.state)                                   //按键状态判断
    18     {
    19         case KEY_STATE_JUDGE:                                  //判断有无按键按下状态
    20             if (!custom_key.press)                             //有按键按下
    21             {
    22                 custom_key.state = KEY_STATE_DEBOUNCE;         //转入消抖状态
    23                 custom_key.count = 0;                          //计数器清零
    24             }
    25         break;
    26         
    27         case KEY_STATE_DEBOUNCE:                               //消抖状态
    28             if (!custom_key.press)
    29             {
    30                 custom_key.count ++;
    31                 if (custom_key.count >= SINGLE_KEY_TIME)
    32                 {
    33                     custom_key.state = KEY_STATE_SPAN;         //消抖确认是有效按键,转入短击和长击判断状态
    34                 }
    35             }
    36             else 
    37                 custom_key.state = KEY_STATE_JUDGE;            //按键误动作,返回判断有无按键按下状态
    38         break;
    39         
    40         case KEY_STATE_SPAN:                                   //短击和长击判断状态
    41             if (custom_key.press)                              //在长击临界值之前释放按键,判断为短击
    42             {
    43                 custom_key.value = KEY_SHORT;
    44                 custom_key.state = KEY_STATE_JUDGE;            //返回判断有无按键按下状态
    45             }
    46             else                                               //计数器值超过长击临界值,判断为长击
    47             {
    48                 custom_key.count ++;
    49                 if (custom_key.count >= LONG_KEY_TIME)
    50                 {
    51                     custom_key.value = KEY_LONG;
    52                     custom_key.state = KEY_STATE_RELEASE;      //进入按键释放状态
    53                 }
    54             }
    55         break;
    56         
    57         case KEY_STATE_RELEASE:                                //按键释放状态
    58             if (custom_key.press)
    59             {
    60                 custom_key.state = KEY_STATE_JUDGE;            //返回判断有无按键按下状态
    61             }
    62         break;
    63         
    64         default:                                               //默认返回判断有无按键按下状态
    65             custom_key.state = KEY_STATE_JUDGE;
    66             break;
    67     }
    68     return custom_key.value;                                   //返回按键值
    69 }

     代码中做了详细的注释,需要说明的是按键的四种状态:

    KEY_STATE_JUDGE:用来检测是否有按键按下, 当有按键按下后,转移到消抖状态,否则每次时间片扫描时都处于此状态  
    KEY_STATE_DEBOUNCE:消抖状态,用来检测按键有效还是误触发,假如只是误触发,则返回到按键等待状态
    KEY_STATE_SPAN:判断按键是长击还是短击,如果在延时消抖后,按键在长按的临界值之前释放,则判断为短击,否则判断为长击,此处的临界值为2s
    KEY_STATE_RELEASE:按键释放状态,摆脱用while循环等待按键释放,当判断为长击以后,程序将进入此状态,在此之后只需在每次时间片到了以后判断是否释放即可

    此处需要理解的是“并行”的思想:主程序一直在for(;;)循环中运行,同时定时器也在不断累加计数,当达到定时器中断触发条件后,定时器中断当前的循环,进入定时器服务程序。因此,
    这四种状态在每次定时器中断触发后就会检测判断一次,相隔时间为10ms。

    头文件:

    key.h

     1 #ifndef _KEY_H_
     2 #define _KEY_H_
     3 
     4 #include "reg52.h"
     5 
     6 typedef unsigned char u8;
     7 typedef unsigned int  u16;
     8 
     9 #define KEY_STATE_JUDGE         0        //判断有无按键按下状态
    10 #define KEY_STATE_DEBOUNCE      1        //消抖状态
    11 #define KEY_STATE_SPAN          2        //判断是短按还是长按
    12 #define KEY_STATE_RELEASE       3        //按键释放
    13 
    14 #define LONG_KEY_TIME            200     //按键持续超过2s,判断为长击
    15 #define SINGLE_KEY_TIME         2        //消抖
    16 
    17 #define KEY_NONE                0        //没有按下按键
    18 #define KEY_SHORT                1       //短击
    19 #define KEY_LONG                2        //长击
    20 
    21 typedef struct 
    22 {
    23     u8    press;                         //读取按键接口
    24     u8    state;                         //按键状态
    25     u8    value;                         //按键返回值
    26     u16   count;                         //按键时间计数器
    27 }key;
    28 
    29 //extern key custom_key;
    30 
    31 void key_init(void);                     //按键初始化函数            
    32 u8 key_driver(void);                     //按键驱动函数
    33 
    34 #endif

     文件中定义了需要的变量、数据结构,以及函数声明。

  • 相关阅读:
    【python实现卷积神经网络】池化层实现
    【python实现卷积神经网络】批量归一化层实现
    在CentOS Linux系统上,添加新的端口,启用ssh服务
    linux各文件夹的作用
    断网环境下利用pip安装Python离线安装包
    Python数据分析入门之pandas基础总结
    Git入门私房菜
    python处理json
    Json概述以及python对json的相关操作
    将Sublime Text 添加到鼠标右键菜单的教程方法
  • 原文地址:https://www.cnblogs.com/xbook-ben/p/7073974.html
Copyright © 2011-2022 走看看