找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4554|回复: 2
收起左侧

PIC单片机单个按键实现多功能:长按、短按次数识别程序

[复制链接]
ID:297903 发表于 2022-2-5 10:15 | 显示全部楼层 |阅读模式
春节放假没有回老家,于是写了个多功能按键识别小程序!
按键分为长按识别(长按3秒),短按识别(记录识别当前按的次数),以节约单片I/O

用我自制的PIC16F887+I2C BD2004试验板测试如下图:

I2C BD2004显示按键执行状况

I2C BD2004显示按键执行状况

MPLABIDE编译状况

MPLABIDE编译状况


单片机源程序如下:
  1. #include<pic.h>  
  2. #define uint unsigned int
  3. #define uchar unsigned char

  4. //--------------//

  5. //配合8M频率
  6. //开关使用情况:
  7. //长按约2秒 生置键生效
  8. //单击 +  双击 -
  9. //三击及以上未使用

  10. //--------------//
  11. #define  sw1 RA4   //
  12. #define  long_time  200  //长按按键时间预设 约2秒
  13. #define  re_time1   46   //第一次按下开关等待第二次按下开关的时长
  14. #define  re_push    0    //第二次及之后的按住开关的时长 为零时双击效率增加
  15. #define  re_time2   55   //第二次及之后等待再次按下开关的时长
  16. bit     read_one;
  17. bit     push_one;
  18. bit     push_hold;
  19. bit     sw_one_flag;
  20. bit     re_push_lock;
  21. bit     key_long_flag;
  22. bit     push_one_flag;
  23. bit     jian_temp_flag;
  24. bit     long_lock_flag;
  25. bit     sec_push_flag;
  26. bit     long_flag;
  27. bit     sen;
  28. bit     set_sw_flag,short_temp_flag;
  29. bit    to_noli_flag;
  30. bit    thr_flag;
  31. bit    jiao_set_flag;

  32. bit   up_flag;        //加按键
  33. bit   dn_flag;        //减按键
  34. bit   se_flag;

  35. uint    cont;
  36. uchar   key_cont;
  37. uchar   key_num;
  38. uint   sw_open_cont,sw_open_cont1,re_push_cont;

  39. char     set_mode;  // 长按+

  40. void push_scan();   //长短及连按计次处理
  41. void key_scan();    //对应按次处理

  42. /*
  43. ////以下这段长短按键识别计数器 复制到TMR0中断内执行效率更高////////////
  44. //--------------------//
  45. if(sw1==0&&sw_one_flag==0&&cont<long_time)    //
  46. {
  47. cont++;if(cont>=long_time) long_flag=1;  //长按时间约2秒
  48. }
  49. else cont=0;
  50. //--------------------//
  51. if(push_one==1)
  52. {
  53. if(sw1==1&&push_hold==0) //第一次按下开关等待第二次按下开关的时长
  54. {sw_open_cont1++;
  55. }

  56. if(push_hold)
  57. {
  58. //if(sw1==0&&re_push_lock==0){re_push_cont++;}//再次按下时间限制,用于不能太快松开
  59. if(sw1==1&&re_push_lock==0)sw_open_cont++;//第二次及之后等待再次按下开关的时长
  60. }

  61. }
  62. //--------------------//
  63. ////长短按键识别计数end////////////
  64. */


  65. ///////////////////
  66. //----------------------------//
  67. //单按键长、短按识别
  68. //长按输出结果:key_long_flag 为1时有效,
  69. //短按计次输出:key_num; key_num=1~10     
  70. void push_scan(void)
  71. {
  72. /////长按键处理//////
  73. if(sw1==0&&push_hold==0)    //
  74. {
  75. //cont++;if(cont>=long_time) long_flag=1;  //长按时间约3秒 在中TMR0中断内执行提高计时稳定
  76. if(long_flag&&sw_one_flag==0)   //处理长按钮
  77. {
  78. key_long_flag=1;
  79. //didi(1);
  80. sw_one_flag=1;
  81. long_lock_flag=1;
  82. }  
  83. } else {if(sw1==1&&sw_one_flag){ cont=0;sw_one_flag=0;long_flag=0;}}
  84. /////长按键处理完成//////

  85. //------短按处理--//
  86. //---第一次按下后再放开按键的处理--//
  87. if(sw1==0&&push_one_flag==0){push_one_flag=1;key_num=0;}//第一次压下开关检测 并清除旧的key_num
  88. else if(push_one_flag==1&&sw1==1){push_one_flag=0;push_one=1;}//当第一次压下放开后置位压一次标志避免与长按冲突
  89. //---第一次按下后再放开按键完成--//

  90. //---当检测到第一次压下并放开后--//
  91. if(push_one)
  92. {
  93. //---是否有第二次按压处理--//
  94. if(sw1==0&&push_hold==0&&sec_push_flag==0)//检测有第二次压下
  95. {
  96. if(push_hold==0) key_cont=1;//有第二次压下时将上次的按键次数 先清零 导入开关后应关闭
  97. push_hold=1;                //有第二次压下开关时置位开关按过的标志,
  98. sec_push_flag=1;
  99. }

  100. else if(sw1==1&&push_hold==0) //若无第二次按开关 清零按过标志
  101. {//sw_open_cont1++;         //在中TMR0中断内执行提高计时稳定   
  102. if(sw_open_cont1>re_time1)//超过指定间隔时间未按开关
  103. {sec_push_flag=0;push_one=0;sw_open_cont1=0;
  104. if(long_lock_flag)
  105. {key_cont=0;long_lock_flag=0;}
  106. else {key_cont=1;}}
  107. }
  108. //---第二次是否按压处理完成--//

  109. //---第二次及之后按压计数处理--//
  110. if(push_hold)//第二次压下开始作业计数
  111. {
  112. if(sw1==0&&re_push_lock==0)//再次按压开关
  113. { sw_open_cont=0;//有再次按下开关则清零松开计数器
  114. re_push_cont++;
  115. if(re_push_cont>re_push)//再次按下时间限制,用于不能太快松开
  116. {key_cont++;re_push_lock=1;}
  117. }  
  118. else if(sw1==1&&re_push_lock==1){re_push_cont=0;re_push_lock=0;}

  119. else if(sw1==1)//标记有按过按键再放开时间判定
  120. {
  121. //sw_open_cont++;            //在中TMR0中断内执行提高计时稳定
  122. if(sw_open_cont>re_time2)
  123. { push_hold=0;sw_open_cont=0;//超过指定时间标记位
  124. push_one=0;sw_open_cont1=0;sec_push_flag=0;long_flag=0;
  125. }

  126. }

  127. }
  128. //---第二次及之后按压计数完成--//
  129. }   
  130. //---短按处理完成 提取健值--//
  131. if(sw1==1&&push_one_flag==0&&push_hold==0)//确认没有按键动作时
  132. {
  133. if(key_cont>0&&read_one==0)
  134. {
  135. key_num=key_cont;//dis=key_cont;
  136. key_cont=0;
  137. read_one=1;
  138. }else if(read_one==1)read_one=0;
  139. }
  140. //短按之后没有及时放开按键 当到达长按上限时当作按键结束
  141. else if(sw1==0&&key_cont>0&&push_hold==1&&long_flag==1)
  142. {
  143. if(key_cont>0&&read_one==0)
  144. {
  145. key_num=key_cont;//dis=key_cont;
  146. key_cont=0;
  147. read_one=1;
  148. //不清除会导致第二次单按时触发长按累计
  149. }else if(read_one==1){read_one=0;}long_flag=0;
  150. }
  151. ///

  152. }
  153. //////长短按键处理end///////

  154. void key_scan()
  155. {
  156. push_scan();
  157. se_flag=key_long_flag; key_long_flag=0; //设置键
  158. //if(key_num==1) {up_flag=1;key_num=0;}//加键
  159. //if(key_num==2) {dn_flag=1;key_num=0;}//减键
  160. //if(set_mode==0&&key_num==3) {thr_flag=1;key_num=0;}//按三次

  161. //----設置鍵-----//

  162. //---------------------//
  163. if(se_flag&&set_sw_flag==0)  //长按处理分別進入時分﹑年﹑月日的校正
  164. {
  165. set_mode++;
  166. if(set_mode>7)set_mode=0;
  167. set_sw_flag=1;
  168. se_flag=0;
  169. } else if(se_flag==0&&set_sw_flag==1) set_sw_flag=0;
  170. //---------------------//
  171. }
复制代码

以上图文的Word格式文档下载(内容和本网页上的一模一样,方便大家保存):
多功能按键.doc (598 KB, 下载次数: 30)

评分

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

查看全部评分

回复

使用道具 举报

ID:297903 发表于 2022-2-5 10:17 | 显示全部楼层
视频没法上传!
回复

使用道具 举报

ID:46750 发表于 2022-2-6 12:26 | 显示全部楼层
楼主开源精神敬佩,方便分享整个工程吗?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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