第十节:两个独立按键的组合按键触发。

开场白:
上一节讲了按键双击触发功能的程序,这一节讲类似电脑键盘组合按键触发的功能,要教会大家一个知识点:如何在上一节的基础上,略作修改,就可以实现两个独立按键的组合按键触发功能。

具体内容,请看源代码讲解。

(1)硬件平台:基于朱兆祺51单片机学习板。用矩阵键盘中的S1和S5号键作为独立按键,记得把输出线P0.4一直输出低电平,模拟独立按键的触发地GND。

(2)实现功能:有两个独立按键,当把两个独立按键都按下后,蜂鸣器发出“滴”的一声后就停。直到松开任一个按键后,才能重新进行下一次的组合按键触发。

(3)源代码讲解如下:

 

  1. #include "REG52.H"  
  2.   
  3. #define const_voice_short  40   //蜂鸣器短叫的持续时间  
  4.   
  5.   
  6. /* 注释一: 
  7. * 调整抖动时间阀值的大小,可以更改按键的触发灵敏度。 
  8. * 去抖动的时间本质上等于累计定时中断次数的时间。 
  9. */  
  10. #define const_key_time12  20    //按键去抖动延时的时间  
  11.   
  12.   
  13. void initial_myself();      
  14. void initial_peripheral();  
  15. void delay_long(unsigned int uiDelaylong);  
  16. void T0_time();  //定时中断函数  
  17. void key_service(); //按键服务的应用程序  
  18. void key_scan(); //按键扫描函数 放在定时中断里  
  19.   
  20. sbit key_sr1=P0^0; //对应朱兆祺学习板的S1键  
  21. sbit key_sr2=P0^1; //对应朱兆祺学习板的S5键  
  22. sbit key_gnd_dr=P0^4; //模拟独立按键的地GND,因此必须一直输出低电平  
  23.   
  24. sbit beep_dr=P2^7; //蜂鸣器的驱动IO口  
  25.   
  26. unsigned char ucKeySec=0;   //被触发的按键编号  
  27.   
  28. unsigned int  uiKeyTimeCnt12=0; //按键去抖动延时计数器  
  29. unsigned char ucKeyLock12=0; //按键触发后自锁的变量标志  
  30.   
  31.   
  32. unsigned int  uiVoiceCnt=0;  //蜂鸣器鸣叫的持续时间计数器  
  33.   
  34. void main()   
  35.   {  
  36.    initial_myself();    
  37.    delay_long(100);     
  38.    initial_peripheral();   
  39.    while(1)    
  40.    {   
  41.        key_service(); //按键服务的应用程序  
  42.    }  
  43.   
  44. }  
  45.   
  46. void key_scan()//按键扫描函数 放在定时中断里  
  47. {    
  48. /* 注释二: 
  49. * 独立组合按键扫描的详细过程: 
  50. * 第一步:平时只要两个按键中有一个没有被按下时,按键的自锁标志,去抖动延时计数器一直被清零。 
  51. * 第二步:一旦两个按键都被按下,去抖动延时计数器开始在定时中断函数里累加,在还没累加到 
  52. *         阀值const_key_time12时,如果在这期间由于受外界干扰或者按键抖动,而使 
  53. *         IO口突然瞬间触发成高电平,这个时候马上把延时计数器uiKeyTimeCnt12 
  54. *         清零了,这个过程非常巧妙,非常有效地去除瞬间的杂波干扰。这是我实战中摸索出来的。 
  55. *         以后凡是用到开关感应器的时候,都可以用类似这样的方法去干扰。 
  56. * 第三步:如果按键按下的时间超过了阀值const_key_time12,马上把自锁标志ucKeyLock12置位, 
  57. *         防止按住按键不松手后一直触发。并把编号ucKeySec赋值。 组合按键触发 
  58. * 第四步:等按键松开后,自锁标志ucKeyLock12及时清零,为下一次自锁做准备。 
  59. * 第五步:以上整个过程,就是识别按键IO口下降沿触发的过程。 
  60. */  
  61.   if(key_sr1==1||key_sr2==1)//IO是高电平,说明两个按键没有全部被按下,这时要及时清零一些标志位  
  62.   {  
  63.          ucKeyLock12=0; //按键自锁标志清零  
  64.          uiKeyTimeCnt12=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。        
  65.   }  
  66.   else if(ucKeyLock12==0)//有按键按下,且是第一次被按下  
  67.   {  
  68.      uiKeyTimeCnt12++; //累加定时中断次数  
  69.      if(uiKeyTimeCnt12>const_key_time12)  
  70.      {  
  71.         uiKeyTimeCnt12=0;   
  72.         ucKeyLock12=1;  //自锁按键置位,避免一直触发  
  73.         ucKeySec=1;    //触发1号键  
  74.                 
  75.      }  
  76.   }  
  77.   
  78.   
  79.   
  80.   
  81. }  
  82.   
  83.   
  84. void key_service() //第三区 按键服务的应用程序  
  85. {  
  86.   switch(ucKeySec) //按键服务状态切换  
  87.   {  
  88.     case 1:// 1号键 组合按键  对应朱兆祺学习板的S1键和S5键  
  89.   
  90.               uiVoiceCnt=const_voice_short; //按键声音触发,滴一声就停。  
  91.               ucKeySec=0;  //响应按键服务处理程序后,按键编号清零,避免一致触发  
  92.           break;          
  93.                 
  94.   }                  
  95. }  
  96.   
  97.   
  98.   
  99. void T0_time() interrupt 1  
  100. {  
  101.   TF0=0;  //清除中断标志  
  102.   TR0=0; //关中断  
  103.   
  104.   key_scan(); //按键扫描函数  
  105.   
  106.   if(uiVoiceCnt!=0)  
  107.   {  
  108.      uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫  
  109.          beep_dr=0;  //蜂鸣器是PNP三极管控制,低电平就开始鸣叫。  
  110.   }  
  111.   else  
  112.   {  
  113.      ; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。  
  114.            beep_dr=1;  //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。  
  115.   }  
  116.   
  117.   
  118.   TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f  
  119.   TL0=0x2f;  
  120.   TR0=1;  //开中断  
  121. }  
  122.   
  123.   
  124. void delay_long(unsigned int uiDelayLong)  
  125. {  
  126.    unsigned int i;  
  127.    unsigned int j;  
  128.    for(i=0;i<uiDelayLong;i++)  
  129.    {  
  130.       for(j=0;j<500;j++)  //内嵌循环的空指令数量  
  131.           {  
  132.              ; //一个分号相当于执行一条空语句  
  133.           }  
  134.    }  
  135. }  
  136.   
  137.   
  138. void initial_myself()  //第一区 初始化单片机  
  139. {  
  140. /* 注释三: 
  141. * 矩阵键盘也可以做独立按键,前提是把某一根公共输出线输出低电平, 
  142. * 模拟独立按键的触发地,本程序中,把key_gnd_dr输出低电平。 
  143. * 朱兆祺51学习板的S1和S5两个按键就是本程序中用到的两个独立按键。 
  144. */  
  145.   key_gnd_dr=0; //模拟独立按键的地GND,因此必须一直输出低电平  
  146.   
  147.   
  148.   beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。  
  149.   
  150.   
  151.   TMOD=0x01;  //设置定时器0为工作方式1  
  152.   
  153.   
  154.   TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f  
  155.   TL0=0x2f;  
  156.   
  157. }  
  158. void initial_peripheral() //第二区 初始化外围  
  159. {  
  160.   EA=1;     //开总中断  
  161.   ET0=1;    //允许定时中断  
  162.   TR0=1;    //启动定时中断  
  163.   
  164. }  

总结陈词:
以前寻呼机流行的时候,寻呼机往往只有一个设置按键,它要求用一个按键来设置不同的参数,这个时候就要用到同一个按键来实现短按和长按的区别触发功能。要现实这种功能,我们该怎么写程序?欲知详情,请听下回分解-----同一个按键短按与长按的区别触发。

永不止步步 发表于11-19 21:38 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

永不止步步
金币:67410个|学分:308217个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号