分享

【单片机笔记】单个按键实现单击、双击、长按的实现

 昱雄藏书 2018-08-21

直接贴上源码和测试例程,附带的都有中文注释不多做解释。

底层驱动:

  1. #define key_state_0 0
  2. #define key_state_1 1
  3. #define key_state_2 2
  4. #define key_state_3 3
  5. #define key_no 0
  6. #define key_click 1
  7. #define key_double 2
  8. #define key_long 3
  9. #define key_input P30
  10. /***************************************************************************
  11. 程序功能:一个按键的单击、双击、长按。三种按键方式,然后做不同的处理。
  12. ***************************************************************************/
  13. static unsigned char key_driver(void)
  14. {
  15. static unsigned char key_state_buffer1 = key_state_0;
  16. static unsigned char key_timer_cnt1 = 0;
  17. unsigned char key_return = key_no;
  18. unsigned char key;
  19. key = key_input; //read the I/O states
  20. switch(key_state_buffer1)
  21. {
  22. case key_state_0:
  23. if(key == 0)
  24. key_state_buffer1 = key_state_1;
  25. //按键被按下,状态转换到按键消抖和确认状态//
  26. break;
  27. case key_state_1:
  28. if(key == 0)
  29. {
  30. key_timer_cnt1 = 0;
  31. key_state_buffer1 = key_state_2;
  32. //按键仍然处于按下状态
  33. //消抖完成,key_timer开始准备计时
  34. //状态切换到按下时间计时状态
  35. }
  36. else
  37. key_state_buffer1 = key_state_0;
  38. //按键已经抬起,回到按键初始状态
  39. break; //完成软件消抖
  40. case key_state_2:
  41. if(key == 1)
  42. {
  43. key_return = key_click; //按键抬起,产生一次click操作
  44. key_state_buffer1 = key_state_0; //转换到按键初始状态
  45. }
  46. else if(++key_timer_cnt1 >= 100) //按键继续按下,计时超过1000ms
  47. {
  48. key_return = key_long; //送回长按事件
  49. key_state_buffer1 = key_state_3; //转换到等待按键释放状态
  50. }
  51. break;
  52. case key_state_3: //等待按键释放
  53. if(key == 1) //按键释放
  54. key_state_buffer1 = key_state_0; //切回按键初始状态
  55. break;
  56. }
  57. return key_return;
  58. }
  59. /***************************************************************************
  60. 函数功能:中层按键处理函数,调用底层函数一次,处理双击事件的判断,
  61. 返回上层正确的无键、单击、双击、长按四种状态
  62. 本函数由上层循环调用,间隔10ms
  63. ***************************************************************************/
  64. unsigned char key_read(void)
  65. {
  66. static unsigned char key_state_buffer2 = key_state_0;
  67. static unsigned char key_timer_cnt2 = 0;
  68. unsigned char key_return = key_no;
  69. unsigned char key;
  70. key = key_driver();
  71. switch(key_state_buffer2)
  72. {
  73. case key_state_0:
  74. if(key == key_click)
  75. {
  76. key_timer_cnt2 = 0; //第一次单击,不返回,到下个状态判断是否会出现双击
  77. key_state_buffer2 = key_state_1;
  78. }
  79. else
  80. key_return = key; //对于无键、长按,返回原事件
  81. break;
  82. case key_state_1:
  83. if(key == key_click) //又一次单击,时间间隔小于500ms
  84. {
  85. key_return = key_double; //返回双击事件,回到初始状态
  86. key_state_buffer2 = key_state_0;
  87. }
  88. else if(++key_timer_cnt2 >= 50)
  89. {
  90. //这里500ms内肯定读到的都是无键事件,因为长按大于1000ms
  91. //在1s前底层返回的都是无键
  92. key_return = key_click; //500ms内没有再次出现单击事件,返回单击事件
  93. key_state_buffer2 = key_state_0; //返回初始状态
  94. }
  95. break;
  96. }
  97. return key_return;
  98. }

测试例程(基于51内核)

  1. void main(void)
  2. {
  3. u8 cnt_1ms=0,cnt_100ms=0;
  4. u8 key_value = 0;
  5. u8 led_flash=0;
  6. GPIO_Configuration();
  7. P3M1 &= ~(1<<0);P3M2 &= ~(1<<0); //P30准双向
  8. P1M1 &= ~(1<<2);P1M2 |= (1<<2); //P12推挽
  9. P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed();
  10. P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed();
  11. P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed();
  12. P12=0;Delay_ms(500);P12=1;Delay_ms(500);IWDG_Feed();
  13. enableInterrupts();
  14. IWDG_Configuration();
  15. while(1)
  16. {
  17. if(++cnt_1ms>=10)
  18. {
  19. cnt_1ms=0;
  20. key_value = key_read();
  21. if(key_value != key_no) led_flash = key_value*2;
  22. }
  23. if(++cnt_100ms>=100)
  24. {
  25. cnt_100ms=0;
  26. if(led_flash)
  27. {
  28. led_flash--;
  29. P12 = ~P12;
  30. }
  31. }
  32. }
  33. }

By Urien 2018年6月7日 11:29:47

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多