找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2083|回复: 1
收起左侧

51单片机时间片段轮询按键扫描源码

[复制链接]
ID:324320 发表于 2018-5-7 16:42 | 显示全部楼层 |阅读模式
单片机源程序如下:
  1. #include <reg52.h>
  2. #define uchar unsigned char
  3. //按键端口定义
  4. sbit io_key_1 = P2^0 ;
  5. sbit io_key_2 = P2^1 ;
  6. sbit io_key_3 = P2^2 ;
  7. sbit io_key_4 = P2^3 ;
  8. sbit P30 = P3^0;
  9. sbit P31 = P3^1;
  10. sbit P32 = P3^2;
  11. sbit P33 = P3^3;

  12. //定义长按键的TICK数,以及连_发间隔的TICK数
  13. #define KEY_LONG_PERIOD         100
  14. #define KEY_CONTINUE_PERIOD     20
  15. #define KEY_DOUDONG             20
  16. //定义按键返回值状态(按下,长按,连_发,释放)
  17. #define KEY_DOWN            0x80
  18. #define KEY_LONG            0x40
  19. #define KEY_CONTINUE        0x20
  20. #define KEY_UP              0x10
  21. //定义按键状态
  22. #define KEY_STATE_INIT      0
  23. #define KEY_STATE_WOBBLE    1
  24. #define KEY_STATE_PRESS     2
  25. #define KEY_STATE_LONG      3
  26. #define KEY_STATE_CONTINUE  4
  27. #define KEY_STATE_RELEASE   5
  28. //按键值
  29. #define KEY_VALUE_1         0x0e
  30. #define KEY_VALUE_2         0x0d
  31. #define KEY_VALUE_3         0x0b
  32. #define KEY_VALUE_4         0x07
  33. #define KEY_NULL            0x0f
  34. static uchar s_u8KeyState = KEY_STATE_INIT;     //关键状态
  35. static uchar s_u8KeyTimeCount = 0;      //关键时间计数
  36. static uchar s_u8LastKey = KEY_NULL;   //保存按键释放时候的键值
  37. void delay_nms(unsigned char k)
  38. {
  39.     unsigned int i,j;
  40.     for(i=0;i<k;i++)
  41.         for(j=0;j<120;j++)
  42.             ;
  43. }
  44. //按键初始化
  45. void KeyInit(void)
  46. {
  47.      io_key_1 = 1;
  48.      io_key_2 = 1;
  49.      io_key_3 = 1;
  50.      io_key_4 = 1;
  51. }
  52. //按键扫描
  53. static uchar KeyScan(void)
  54. {
  55.      if(io_key_1 == 0)return KEY_VALUE_1;
  56.      if(io_key_2 == 0)return KEY_VALUE_2;
  57.      if(io_key_3 == 0)return KEY_VALUE_3;
  58.      if(io_key_4 == 0)return KEY_VALUE_4;
  59.      return KEY_NULL;
  60. }
  61. void GetKey(uchar *pKeyValue)
  62. {
  63.      static uchar s_u8KeyState = KEY_STATE_INIT ;
  64.      static uchar s_u8KeyTimeCount = 0 ;
  65.      static uchar s_u8LastKey = KEY_NULL ;   //保存按键释放时候的键值
  66.      static uchar s_doudong=0;
  67.      uchar KeyTemp = KEY_NULL ;
  68.      KeyTemp = KeyScan() ;         //获取键值
  69.      switch(s_u8KeyState)
  70.      {
  71.          case KEY_STATE_INIT :          //初始化S1状态
  72.                  {
  73.                      if(KEY_NULL != (KeyTemp))  //如果有按键按下 进入状态2
  74.                      {
  75.                          s_u8KeyState = KEY_STATE_WOBBLE ;
  76.                      }
  77.                  }
  78.          break ;
  79.          case KEY_STATE_WOBBLE :        //去抖动S2状态
  80.                  {
  81.                     if(++s_doudong==KEY_DOUDONG)
  82.                     {
  83.                         s_doudong=0;
  84.                         s_u8KeyState = KEY_STATE_PRESS ;
  85.                     }
  86.                     else
  87.                         s_u8KeyState = KEY_STATE_WOBBLE;
  88.                  }
  89.          break ;
  90.          case KEY_STATE_PRESS :         //确认有按键按下S3状态 并返回按键值
  91.                  {
  92.                      if(KEY_NULL != (KeyTemp))
  93.                      {
  94.                          s_u8LastKey = KeyTemp ; //保存键值,以便在释放按键状态返回键值
  95.                          KeyTemp |= KEY_DOWN ;   //按键按下
  96.                          s_u8KeyState = KEY_STATE_LONG ;    //保存下次进入长按状态
  97.                      }
  98.                      else   //如果没有按键按下 返回初始化S1
  99.                      {
  100.                          s_u8KeyState = KEY_STATE_INIT ;
  101.                      }
  102.                  }
  103.          break ;
  104.          case KEY_STATE_LONG :          //进入长按
  105.                  {
  106.                      if(KEY_NULL != (KeyTemp))  //确认有按键按下  计数
  107.                      {
  108.                          if(++s_u8KeyTimeCount > KEY_LONG_PERIOD)   //到达阀值 返回长按键值
  109.                          {
  110.                              s_u8KeyTimeCount = 0 ;
  111.                              KeyTemp |= KEY_LONG ;   //长按键事件发生
  112.                              s_u8KeyState = KEY_STATE_LONG ;    //保存下次进入
  113.                          }
  114.                      }
  115.                      else
  116.                      {
  117.                          s_u8KeyState = KEY_STATE_RELEASE ;         //长按状态 按键放开
  118.                      }
  119.                  }
  120.          break ;
  121.          case KEY_STATE_CONTINUE :                                  //连发状态
  122.                  {
  123.                      if(KEY_NULL != (KeyTemp))
  124.                      {
  125.                          if(++s_u8KeyTimeCount > KEY_CONTINUE_PERIOD)
  126.                          {
  127.                              s_u8KeyTimeCount = 0 ;
  128.                              KeyTemp |= KEY_CONTINUE ;
  129.                          }
  130.                      }
  131.                      else       //如果没有按键 直接返回按键
  132.                      {
  133.                          s_u8KeyState = KEY_STATE_RELEASE ;
  134.                      }
  135.                  }
  136.          break ;
  137.          case KEY_STATE_RELEASE :           //短按返回
  138.                  {
  139.                      s_u8LastKey |= KEY_UP ;
  140.                      KeyTemp = s_u8LastKey ;
  141.                      s_u8KeyState = KEY_STATE_INIT ;
  142.                  }
  143.          break ;
  144.          default : break ;
  145.      }
  146.      *pKeyValue = KeyTemp ; //返回键值
  147. }
  148. void Key_Proc(uchar key_value)
  149. {
  150.     switch(key_value)
  151.     {
  152.         case KEY_VALUE_1 | KEY_DOWN:
  153.             P3=0X0f;    //0000 1111
  154.             delay_nms(500);
  155.             break;
  156.         case KEY_VALUE_1 | KEY_LONG:
  157.             P3 = 0xf0;  //1111 0000
  158.             break;
  159.         case KEY_VALUE_1 | KEY_UP:
  160.             P3 = 0x33;  //0011 0011
  161.             break;
  162.         default:
  163.             break;
  164.     }
  165. }
  166. void main(void)
  167. {
  168.     uchar KeyValue = KEY_NULL;
  169.     KeyInit();
  170.     P2=0xff;
  171.     P3=0x00;
  172.     while(1)
  173.     {
  174.         GetKey(&KeyValue) ;
  175.         Key_Proc(KeyValue);
  176.     }
  177. }
复制代码

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:139222 发表于 2018-5-8 05:00 | 显示全部楼层
非常好的注释,不过我发现程序中可能出现了一个错误,请指正。


  1. case KEY_STATE_LONG :          //进入长按
  2.                  {
  3.                      if(KEY_NULL != (KeyTemp))  //确认有按键按下  计数
  4.                      {
  5.                          if(++s_u8KeyTimeCount > KEY_LONG_PERIOD)   //到达阀值 返回长按键值
  6.                          {
  7.                              s_u8KeyTimeCount = 0 ;
  8.                              KeyTemp |= KEY_LONG ;   //长按键事件发生
  9.                              s_u8KeyState = KEY_STATE_LONG ;    //保存下次进入
  10.                          }
  11.                      }
  12.                      else
  13.                      {
  14.                          s_u8KeyState = KEY_STATE_RELEASE ;         //长按状态 按键放开
  15.                      }
  16.                  }
复制代码


其中达到阀值以后,应该是进入连发状态。即
  1. s_u8KeyState = KEY_STATE_CONTINUE
复制代码

评分

参与人数 1黑币 +80 收起 理由
admin + 80 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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