找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3551|回复: 4
收起左侧

一种全新的单片机按键程序写法思路,请大家指教,点评

[复制链接]
ID:207882 发表于 2019-7-21 01:11 | 显示全部楼层 |阅读模式
        最近帖子已经有人在此提到充分利用CPU中断的重要性,,再次我就不要说了。此按键demo支持短按,长按,多个按键同时按下,由于是用扫描的方式,各个按键的按下和松独立处理,不互相干扰,避免要按键死等的情况。对于特殊的按键消抖时间可单独一条线扫描检测。。由于是各个按键,一位位检测,检测到一位就进行处理,之后再进行处理下一位,所以有先后顺序。废话不多说,下面讲思路,有错误的地方大家可以一起学习,探讨,,,,,,,,
      按键的最终状态无非就两种,按下或者松开。我用的是STC8单片机,现在的一些增强型或许新型号应该内部都有上拉电阻,,所以我们是按键低电平触发。
对于只作为输入口用于按键检测,,我们可以默认他的IO口状态,不要去操作IO寄存器,,,(如果是即作为输入又作为输出的话,,在读取状态的时候记得先写1,延时2个NOP,再去读,保证读取的准确性),,假设按键没按下去默认就是1了,按键按下去就是0,也就是1->0的过程,,松开的话就是0->1,恢复到最初状态。这里就有两个变化1->0,和0->1,,理解这个之后我们就定义两个变量 value 变化值 buf 最终状态值  我们两个变化1->0,和0->1进行异或就是1,,说明了按键有按下或松开的动作,我们就去执行对应的函数,,执行完后按键的最终只buf也跟着更新,也就是0(按下) 1(松开),,(一直按下的过程)此时端口值0 和buf0  异或就是0 ,咱就不再去执行按键按下的程序,,(松开后的过程)此时端口值1 和buf1 异或就是0 ,咱就不再去执行按键松开的程序,,这样就保证了按下 或者松开 只执行一次动作,,因此加入一些标志位。,结合中断就可以做一些长按功能了。提供的demo里有做了一个实例是长按2秒开关蜂鸣器,,其他的按键按下或者松开的子函数用户自己增加自己需要的功能,,里面只是写了一些简单的点灯功能用于调试,,自己验证了一下程序是可行,,所以提供出来,,大部分都有注释,看看有什么不足之处,在进行修改,,后面会在此基础加入矩阵扫描,原理一样,接着进一步完善demo,做成一个能实现操作常见的外设demo出来,,程序不足之处多多见谅,大家多多批评,一起学习,,,,,下面按键的流程图,也不知道这个画得不到,老感觉自己的表达能力有待提高,,或者也会多发贴,把自己的一些表达能力加强,,

按键流程图

按键流程图

1 file文件夹为项目的硬件端口表 功能书 原理图等资料

2 inc文件 为系统配置文件

3 lib文件 各个外设文件

4 program文件 为项目文件

单片机源程序如下:
  1. #include<stc8.h>
  2. #include <intrins.h>
  3. sbit         led1=P0^4;
  4. sbit         led2=P0^5;
  5. sbit         led3=P0^6;
  6. sbit         led4=P0^7;
  7. sbit         led5=P1^3;
  8. sbit         led6=P1^4;
  9. sbit         led7=P1^5;
  10. sbit         led8=P1^6;

  11. sbit         beep=P1^7;

  12. #define        D_ScanLine                2                        //定义扫描线的数量,
  13. #define        D_ESTTime                10                        //单位ms,消除抖动时间。实际以为你外设消抖时间为准

  14. #define        P0_key                0xFc                        //定义用到的端口按键(低电平有效,用到p00 p01)
  15. //#define        P1_key                0x00                        //定义用到的端口按键(低电平有效,用到8个)
  16. #define        P2_key                0x00                        //定义用到的端口按键(低电平有效,用到8个)
  17. //#define        P3_key                0x00                        //定义用到的端口按键(低电平有效,用到8个)

  18. u8                R_key_buf[D_ScanLine];                //定义存储每一行按键变化后最终的数值
  19. u8            R_key_value[D_ScanLine];    //定义存储每一行按键变化中的数值



  20. u8                R_key_douce;                                   //按键消抖时基
  21. u8                R_key_num;                                        //按键编号(对应各个按键函数)
  22. u8                D_ScanLineDec;                                //当前扫描线

  23. u8                beep_flag;                                        //蜂鸣器标志
  24. u16                beep_time;                                        //计时
  25. //按键消抖
  26. void        F_key_douce()                  
  27. {
  28.                 if(R_key_douce!=0)
  29.                 {
  30.                          R_key_douce=R_key_douce-1;
  31.                 }
  32. }
  33. //蜂鸣器计时

  34. void        F_beep_time()
  35. {
  36.         if(beep_flag==1)
  37.         {
  38.                  if(beep_time!=0)
  39.                  beep_time=beep_time-1;
  40.         }
  41. }
  42. //蜂鸣器检测

  43. void        F_beep_check()
  44. {
  45.         if(beep_flag==1)
  46.         {
  47.                  if(beep_time==0)
  48.                    {
  49.                               beep=~beep ;
  50.                            beep_flag=0;
  51.                    }
  52.         }
  53. }


  54. //对应按键按下子函数
  55. void        F_key1_dn()
  56. {
  57.          
  58.           led1=~led1;
  59. }
  60. void        F_key2_dn()
  61. {
  62.           led2=~led2;
  63. }                          
  64. void        F_key3_dn()
  65. {
  66.           led3=~led3;
  67. }
  68. void        F_key4_dn()
  69. {
  70.           led4=~led4;
  71. }
  72. void        F_key5_dn()
  73. {

  74. }
  75. void        F_key6_dn()
  76. {

  77. }
  78. void        F_key7_dn()
  79. {

  80. }
  81. void        F_key8_dn()
  82. {

  83. }
  84. void        F_key9_dn()
  85. {
  86.        
  87.           led5=~led5;
  88. }
  89. void        F_key10_dn()
  90. {
  91.           led6=~led6;
  92. }
  93. void        F_key11_dn()
  94. {
  95.          led7=~led7;
  96. }
  97. void        F_key12_dn()
  98. {
  99.          led8=~led8;
  100. }
  101. void        F_key13_dn()
  102. {
  103.                 beep_flag=1;
  104.                 beep_time=0x07d0;        //2秒
  105. }
  106. void        F_key14_dn()
  107. {

  108. }
  109. void        F_key15_dn()
  110. {

  111. }
  112. void        F_key16_dn()
  113. {

  114. }


  115. //------------------------------------------------------
  116. //对应按键松开子函数
  117. void        F_key1_up()
  118. {

  119. }
  120. void        F_key2_up()
  121. {
  122. //          R_key_num=8;
  123. //          led=~led;
  124. }
  125. void        F_key3_up()
  126. {
  127. //          R_key_num=8;
  128. //          led=~led;
  129. }
  130. void        F_key4_up()
  131. {
  132. //          R_key_num=8;
  133. //          led=~led;
  134. }
  135. void        F_key5_up()
  136. {
  137. //          R_key_num=8;
  138. //          led=~led;
  139. }
  140. void        F_key6_up()
  141. {
  142. //          R_key_num=8;
  143. //          led=~led;
  144. }
  145. void        F_key7_up()
  146. {
  147. //          R_key_num=8;
  148. //          led=~led;
  149. }
  150. void        F_key8_up()
  151. {
  152. //          R_key_num=8;
  153. //          led1=~led1;
  154. }
  155. void        F_key9_up()
  156. {
  157. //          R_key_num=8;
  158. //          led1=~led1;
  159. }
  160. void        F_key10_up()
  161. {
  162. //          R_key_num=8;
  163. //          led=~led;
  164. }
  165. void        F_key11_up()
  166. {
  167. //          R_key_num=8;
  168. //          led=~led;
  169. }
  170. void        F_key12_up()
  171. {
  172. //          R_key_num=8;
  173. //          led=~led;
  174. }
  175. void        F_key13_up()
  176. {
  177.                 beep_flag=0;
  178.                 beep_time=0x07d0;        //2秒
  179. }
  180. void        F_key14_up()
  181. {
  182. //          R_key_num=8;
  183. //          led=~led;
  184. }
  185. void        F_key15_up()
  186. {
  187. //          R_key_num=8;
  188. //          led=~led;
  189. }
  190. void        F_key16_up()
  191. {
  192. //          R_key_num=8;
  193. //          led=~led;
  194. }



  195. //按键按下总函数
  196. void        key_dn()
  197. {

  198.                 switch(R_key_num+1)
  199.              {                  


  200.                            case 1:       
  201.                                         F_key1_dn();                                 
  202.                                            break;
  203.                            case 2:       
  204.                                         F_key2_dn();                                 
  205.                                            break;
  206.                            case 3:       
  207.                                         F_key3_dn();                                 
  208.                                            break;
  209.                            case 4:       
  210.                                         F_key4_dn();                                 
  211.                                            break;
  212.                            case 5:       
  213.                                         F_key5_dn();                                 
  214.                                            break;
  215.                            case 6:       
  216.                                         F_key6_dn();                                 
  217.                                            break;
  218.                            case 7:       
  219.                                         F_key7_dn();                                 
  220.                                            break;
  221.                            case 8:       
  222.                                         F_key8_dn();                                 
  223.                                            break;
  224.                            case 9:       
  225.                                         F_key9_dn();                                 
  226.                                            break;
  227.                            case 10:       
  228.                                         F_key10_dn();                                 
  229.                                            break;
  230.                            case 11:       
  231.                                         F_key11_dn();                                 
  232.                                            break;
  233.                            case 12:       
  234.                                         F_key12_dn();                                 
  235.                                            break;
  236.                            case 13:       
  237.                                         F_key13_dn();                                 
  238.                                            break;
  239.                            case 14:       
  240.                                         F_key14_dn();                                 
  241.                                            break;
  242.                            case 15:       
  243.                                         F_key15_dn();                                 
  244.                                            break;
  245.                            case 16:       
  246.                                         F_key16_dn();                                 
  247.                                            break;


  248.                            default:       
  249.                      break;
  250.                 }
  251.        
  252. }
  253. //按键松开总函数
  254. void        key_up()
  255. {

  256.                 switch(R_key_num+1)
  257.              {                  


  258.                            case 1:       
  259.                                         F_key1_up();                                 
  260.                                            break;
  261.                            case 2:       
  262.                                         F_key2_up();                                 
  263.                                            break;
  264.                            case 3:       
  265.                                         F_key3_up();                                 
  266.                                            break;
  267.                            case 4:       
  268.                                         F_key4_up();                                 
  269.                                            break;
  270.                            case 5:       
  271.                                         F_key5_up();                                 
  272.                                            break;
  273.                            case 6:       
  274.                                         F_key6_up();                                 
  275.                                            break;
  276.                            case 7:       
  277.                                         F_key7_up();                                 
  278.                                            break;
  279.                            case 8:       
  280.                                         F_key8_up();                                 
  281.                                            break;
  282.                            case 9:       
  283.                                         F_key9_up();                                 
  284.                                            break;
  285.                            case 10:       
  286.                                         F_key10_up();                                 
  287.                                            break;
  288.                            case 11:       
  289.                                         F_key11_up();                                 
  290.                                            break;
  291.                            case 12:       
  292.                                         F_key12_up();                                 
  293.                                            break;
  294.                            case 13:       
  295.                                         F_key13_up();                                 
  296.                                            break;
  297.                            case 14:       
  298.                                         F_key14_up();                                 
  299.                                            break;
  300.                            case 15:       
  301.                                         F_key15_up();                                 
  302.                                            break;
  303.                            case 16:       
  304.                                         F_key16_up();                                 
  305.                                            break;


  306.                            default:       
  307.                      break;
  308.                 }
  309.        
  310. }

  311. void        Keyscan_task()
  312. {
  313.          u8                ar;
  314.      u8                ax;
  315.      u8                i;

  316.           D_ScanLineDec=D_ScanLineDec+1;
  317.           if(D_ScanLineDec==1)                                           //扫描第一条线
  318.           {
  319.                           ar=P0;
  320.                           ax=P0_key;
  321.                           ar=ar^ax;
  322.                           ar=ar|ax;                                                  //获取按键值

  323.           }
  324.           if(D_ScanLineDec==2)                                   //扫描第二条线
  325.           {
  326.                           ar=P2;
  327.                           ax=P2_key;
  328.                           ar=ar^ax;
  329.                           ar=ar|ax;                                                 //获取按键值
  330.           }



  331.           ax=R_key_value[D_ScanLineDec-1];                //跟变化的按键值比较
  332.           ax=ar-ax;
  333.           if(ax!=0)                                                                 //不等于0说按键有动作(按下或者松开)
  334.           {

  335.                 R_key_value[D_ScanLineDec-1]=ar;        //记录当前的按键值,然后进行消抖
  336.                 R_key_douce=D_ESTTime;                            //设置消抖时间

  337.                 D_ScanLineDec=D_ScanLine;                    //重新更新扫描线,重新开始扫描

  338.           }
  339.           else
  340.           {
  341.                            if(R_key_douce==0)                                 //中断消抖,,判断消抖时间到了?
  342.                         {
  343.                                  ax=R_key_buf[D_ScanLineDec-1];                          //把按键变化后值拿出来
  344.                                  ar=R_key_value[D_ScanLineDec-1];                 //把变化中的按键值拿出来
  345.                                  ar=ar^ax;
  346.                                  if(ar!=0)                                                                //按键发生变化 ar
  347.                                  {
  348.                                                 ax=ar&ax;
  349.                                                 if(ax!=0)                                           //按键按下
  350.                                                 {
  351.                                                         for(i=0;i<8;i ++)                          
  352.                                                        
  353.                                                         {
  354.                                                                 ax=(ar>>i)&1;                           //取出具体是哪一位的按键有变化,一次只取一位
  355.                                                                 if(ax==1)
  356.                                                                 {
  357.                                                                         R_key_num=i;
  358.                                                                         ar=0x01<<i;
  359.                                                                         R_key_buf[D_ScanLineDec-1]=R_key_buf[D_ScanLineDec-1]^ar;   //保存最终的按键值
  360.                                                                         R_key_value[D_ScanLineDec-1]=R_key_buf[D_ScanLineDec-1];        //保存最终的按键变化值  
  361.                                                                         for(ar=1;ar<=D_ScanLineDec-1;ar++)
  362.                                                                         {
  363.                                                                                 R_key_num=R_key_num+8;
  364.                                                                         }
  365.                                                
  366.                                                                      key_dn();
  367.                                                                 }
  368.                                                         }



  369.                                                 }
  370.                                                 else            //按键松开原理同按键按下一样
  371.                                                 {
  372.                                                                 for(i=0;i<8;i ++)
  373.                                                        
  374.                                                         {
  375.                                                                 ax=(ar>>i)&1;
  376.                                                                 if(ax==1)
  377.                                                                 {
  378.                                                                         R_key_num=i;
  379.                                                                         ar=0x01<<i;
  380.                                                                         R_key_buf[D_ScanLineDec-1]=R_key_buf[D_ScanLineDec-1]^ar;   //保存最终的按键值
  381.                                                                         R_key_value[D_ScanLineDec-1]=R_key_buf[D_ScanLineDec-1];          
  382.                                                                         for(ar=1;ar<=D_ScanLineDec-1;ar++)
  383.                                                                         {
  384.                                                                                 R_key_num=R_key_num+8;
  385.                                                                         }
  386.                                                                      key_up();
  387.                                                                 }
  388.                                                         }       
  389.                                                 }

  390.                                  }
  391.                                
  392.                                 else
  393.                                 {
  394.                                        
  395.                                 }        /////按键没按下

  396.                         }                               
  397.                   
  398.                   
  399.           }

  400. }                                                

  401. void        F_Keyscan()
  402. {
  403.         D_ScanLineDec=0;


  404.         while(D_ScanLine-D_ScanLineDec)
  405.         {
  406.                 Keyscan_task();
  407.         }
  408. }
  409.           
  410. void        F_Key_buf_value_init()
  411. {
  412.     u8                i;
  413.         for(i=0;i<D_ScanLine;i ++)
  414.         {
  415.                 R_key_buf[i]=0xff;
  416.                 R_key_value[i]=0xff;                                                       
  417.         }
  418.                
  419. }
复制代码

所有程序51hei打包下载:
STC8 实验3 -按键.rar (92.31 KB, 下载次数: 19)

评分

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

查看全部评分

回复

使用道具 举报

ID:282095 发表于 2019-7-21 10:33 | 显示全部楼层
希望可以更简单明了一些
回复

使用道具 举报

ID:207882 发表于 2019-7-21 14:59 | 显示全部楼层
鹏博士PBs 发表于 2019-7-21 10:33
希望可以更简单明了一些

程序上还可以在优化一下,但这个按键思路跟常见的按键触发方法比,我觉得是是比较好的,嘻嘻
回复

使用道具 举报

ID:253767 发表于 2019-7-22 07:10 | 显示全部楼层
谢谢分享!!!
回复

使用道具 举报

ID:138453 发表于 2019-7-22 08:38 | 显示全部楼层
NICE!!!!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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