您的位置 首页 基础

单片机按键消抖程序

通常按键所用的开关都是机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上就稳定的接通,在断…

一般按键所用的开关都是机械弹性开关,当机械触点断开、闭合时,咱们机械触点的弹性作用,一个按键开关在闭合时不会立刻就安稳的接通,在断开时也不会一会儿完全断开,而是在闭合和断开的瞬间随同了一连串的颤动,如图 8-10 所示。

图 8-10 按键颤动状况图

按键安稳闭合时间长短是由操作人员决议的,一般都会在 100ms 以上,故意快速按的话能到达 40-50ms 左右,很难再低了。颤动时间是由按键的机械特性决议的,一般都会在 10ms以内,为了保证程序对按键的一次闭合或许一次断开只呼应一次,有必要进行按键的消抖处理。当检测到按键状况改动时,不是当即去呼应动作,而是先等候闭合或断开安稳后再进行处理。按键消抖可分为硬件消抖和软件消抖。

硬件消抖便是在按键上并联一个电容,如图 8-11 所示,运用电容的充放电特性来对颤动进程中产生的电压毛刺进行滑润处理,然后完成消抖。但实践运用中,这种办法的作用往往不是很好,而且还增加了本钱和电路复杂度,所以实践中运用的并不多。

图 8-11 硬件%&&&&&%消抖

在绝大多数状况下,咱们是用软件即程序来完成消抖的。最简略的消抖原理,便是当检测到按键状况改动后,先等候一个 10ms 左右的延时时间,让颤动消失后再进行一次按键状况检测,假设与方才检测到的状况相同,就能够结语按键现已安稳的动作了。将上一个的程序稍加改动,得到新的带消抖功用的程序如下。

纯文本新窗口

  1. #include
  2. sbit ADDR0 = P1^0;
  3. sbit ADDR1 = P1^1;
  4. sbit ADDR2 = P1^2;
  5. sbit ADDR3 = P1^3;
  6. sbit ENLED = P1^4;
  7. sbit KEY1 = P2^4;
  8. sbit KEY2 = P2^5;
  9. sbit KEY3 = P2^6;
  10. sbit KEY4 = P2^7;
  11. unsigned char code LedChar[] = { //数码管显现字符转化表
  12. 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
  13. 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
  14. };
  15. void delay();
  16. void main(){
  17. bit keybuf = 1; //按键值暂存,暂时保存按键的扫描值
  18. bit backup = 1; //按键值备份,保存前一次的扫描值
  19. unsigned char cnt = 0; //按键计数,记载按键按下的次数
  20. ENLED = 0; //挑选数码管 DS1 进行显现
  21. ADDR3 = 1;
  22. ADDR2 = 0;
  23. ADDR1 = 0;
  24. ADDR0 = 0;
  25. P2 = 0xF7; //P2.3 置 0,即 KeyOut1 输出低电平
  26. P0 = LedChar[cnt]; //显现按键次数初值
  27. while (1){
  28. keybuf = KEY4; //把当时扫描值暂存
  29. if (keybuf != backup){ //当时值与前次值不相等阐明此刻按键有动作
  30. delay(); //延时大约 10ms
  31. if (keybuf == KEY4){ //判别扫描值有没有产生改动,即按键颤动
  32. if (backup == 0){ //假设前次值为 0,则阐明当时是弹起动作
  33. cnt++; //按键次数+1
  34. //只用 1 个数码管显现,所以加到 10 就清零从头开始
  35. if (cnt >= 10){
  36. cnt = 0;
  37. }
  38. P0 = LedChar[cnt]; //计数值显现到数码管上
  39. }
  40. backup = keybuf; //更新备份为当时值,以备进行下次比较
  41. }
  42. }
  43. }
  44. }
  45. /* 软件延时函数,延时约 10ms */
  46. void delay(){
  47. unsigned int i = 1000;
  48. while (i–);
  49. }

咱们把这个程序下载到板子上再进行实验试试,按一下按键而数字加了屡次的问题是不是就这样处理了?把问题处理掉的感觉是不是很爽呢?

这个程序用了一个简略的算法完成了按键的消抖。作为这种很简略的演示程序,咱们能够这样来写,可是实践做项目开发的时分,程序量往往很大,各种状况值也许多, while(1)这个主循环要不断的扫描各种状况值是否有产生改动,及时的进行使命调度,假设程序中心加了这种 delay 延时操作后,很可能某一事情产生了,可是咱们程序还在进行 delay 延时操作中,当这个事情产生完了,程序还在 delay 操作中,当咱们 delay 完事再去查看的时分,现已晚了,现已检测不到那个事情了。为了防止这种状况的产生,咱们要尽量缩短 while(1)循环一次所用的时间,而需求进行长时间延时的操作,有必要想其它的办法来处理。

那么消抖操作所需求的延时该怎样处理呢?其实除了这种简略的延时,咱们还有更优异的办法来处理按键颤动问题。举个比如:咱们启用一个守时中止,每 2ms 进一次中止,扫描一次按键状况而且存储起来,接连扫描 8 次后,看看这接连 8 次的按键状况是否是共同的。8 次按键的时间大概是 16ms,这 16ms 内假设按键状况一向保持共同,那就能够确认现在按键处于安稳的阶段,而非处于颤动的阶段,如图 8-12。

图 8-12 按键接连扫描判别

假设左面时间是开始 0 时间,每经过 2ms 左移一次,每移动一次,判别当时接连的 8 次按键状况是不是全 1 或许全 0,假设是全 1 则断定为弹起,假设是全 0 则断定为按下,假设0 和 1 交织,就以为是颤动,不做任何断定。想一下,这样是不是比简略的延时愈加牢靠?

运用这种办法,就能够防止经过延时消抖占用单片机执行时间,而是转化成了一种按键状况断定而非按键进程断定,咱们只对当时按键的接连 16ms 的 8 次状况进行判别,而不再关怀它在这 16ms 内都做了什么事情,那么下面就依照这种思路用程序完成出来,相同只以K4 为例。

纯文本新窗口

  1. #include
  2. sbit ADDR0 = P1^0;
  3. sbit ADDR1 = P1^1;
  4. sbit ADDR2 = P1^2;
  5. sbit ADDR3 = P1^3;
  6. sbit ENLED = P1^4;
  7. sbit KEY1 = P2^4;
  8. sbit KEY2 = P2^5;
  9. sbit KEY3 = P2^6;
  10. sbit KEY4 = P2^7;
  11. unsigned char code LedChar[] = { //数码管显现字符转化表
  12. 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
  13. 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
  14. };
  15. bit KeySta = 1; //当时按键状况
  16. void main(){
  17. bit backup = 1; //按键值备份,保存前一次的扫描值
  18. unsigned char cnt = 0; //按键计数,记载按键按下的次数
  19. EA = 1; //使能总中止
  20. ENLED = 0; //挑选数码管 DS1 进行显现
  21. ADDR3 = 1;
  22. ADDR2 = 0;
  23. ADDR1 = 0;
  24. ADDR0 = 0;
  25. TMOD = 0x01; //设置 T0 为形式 1
  26. TH0 = 0xF8; //为 T0 赋初值 0xF8CD,守时 2ms
  27. TL0 = 0xCD;
  28. ET0 = 1; //使能 T0 中止
  29. TR0 = 1; //发动 T0
  30. P2 = 0xF7; //P2.3 置 0,即 KeyOut1 输出低电平
  31. P0 = LedChar[cnt]; //显现按键次数初值
  32. while (1){
  33. //KeySta = KEY4; //把当时扫描值暂存
  34. if (KeySta != backup){ //当时值与前次值不相等阐明此刻按键有动作
  35. if (backup == 0){ //假设前次值为 0,则阐明当时是弹起动作
  36. cnt++; //按键次数+1
  37. if (cnt >= 10){ //只用 1 个数码管显现,所以加到 10 就清零从头开始
  38. cnt = 0;
  39. }
  40. P0 = LedChar[cnt]; //计数值显现到数码管上
  41. }
  42. //更新备份为当时值,以备进行下次比较
  43. backup = KeySta;
  44. }
  45. }
  46. }
  47. /* T0 中止服务函数,用于按键状况的扫描并消抖 */
  48. void InterruptTimer0() interrupt 1{
  49. //扫描缓冲区,保存一段时间内的扫描值
  50. static unsigned char keybuf = 0xFF;
  51. TH0 = 0xF8; //从头加载初值
  52. TL0 = 0xCD;
  53. //缓冲区左移一位,并将当时扫描值移入最低位
  54. keybuf = (keybuf<<1) | KEY4;
  55. //接连 8 次扫描值都为 0,即 16ms 内都只检测到按下状况时,能够为按键已按下
  56. if (keybuf == 0x00){
  57. KeySta = 0;
  58. //接连 8 次扫描值都为 1,即 16ms 内都只检测到弹起状况时,能够为按键已弹起
  59. }else if (keybuf == 0xFF){
  60. KeySta = 1;
  61. }
  62. else{
  63. //其它状况则阐明按键状况没有安稳,则不对 KeySta 变量值进行更新
  64. }
  65. }

这个算法是咱们在实践工程中常常运用按键所总结的一个比较好的办法,介绍给咱们,往后都能够用这种办法消抖了。当然,按键消抖也还有其它的办法,程序完成更是多种多样,咱们也能够再多考虑下其它的算法,高兴下思路。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/jichu/265382.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部