当前位置:   article > 正文

STC32G单片机的开发 (4):定时器中断,以及拓展使用按键扫描定时器中断实现短按,长按和双击多个判断功能(完全定时中断实现)_stc用中断实现按键

stc用中断实现按键

前言

在我的博客STC32G单片机的开发(2)里说明了定时器延时函数的编写,这边我们对其进行对中断函数的编写,相信接触过单片机的朋友也对中断的了解,我们这里对中断的概念就不一一介绍了,主要谈谈寄存器的一些使用,以及对定时器来一个补充说明(毕竟我们在延时函数只用定时器0),我们来说说其它定时器,毕竟STC32G单片机有5个定时器;

最近的话,思考了一下按键的扫描有感,自己找到并编写了一个不错的扫描方式实现单片机的代码,结合本文定时器一起进行讲解

寄存器

定时器寄存器

(1)定时器2相关寄存器

AUXR:这是老朋友了,在前几章我们一直相遇,这里我们配置它的启动位和12T分频位

T2L/T2H:重载值设置,注意这里TIM2是16位自动重载,所以我们计完一个周期的数就不用再手动重装了哈,但是想设置重载值记得要定时器关闭的时候再设置,这和TIM0和TIM1的设置规则是一样的哈

(2)定时器3/4相关寄存器

这里定时器3和4定时器基本锁死,我们就说其中一个。

T4T3M:这个寄存器和AUXR类似,这里定时器我们使用一个12T模式控制分频和定时器启动位就可

T3L/T3H以及T4L/T4H和TIM2,TIM1和TIM0一个道理,换汤不换药。

中断寄存器

我们这边为了不让定时器在初始化设置马上进行中断,我们先清空中断请求标志位。

这边在官方手册的位置在中断部分的内容,5个定时器都是一样的,只是3,4,5没用到TCON寄存器

这边的中断配置路线我们就看官方的手册来配置了,这里我就不一一介绍这些寄存器了。

学过51单片机的朋友都制动 每个中断回调函数名后都有个interrupt Num(Num是中断号)查询中断号我们也可以通过手册的中断列表查询

定时器中断初始化代码

那话就不多说我们配置一下定时器初始化代码

  1. //初始化函数,设置为1ms中断
  2. void TIM2_Init(void)
  3. {
  4. AUXR|=0x04;//不分频 1T模式
  5. T2H=0xA2;
  6. T2L=0x40;
  7. T2IF=0;//清空标志位
  8. ET2=1;//使能定时器2中断
  9. EA=1;//使能全局中断
  10. AUXR|=0x10;//启动定时器2
  11. }
  12. void TIM3_Init(void)
  13. {
  14. T4T3M |= 0x02; //定时器时钟1T模式
  15. T3L = 0x40; //设置定时初始值
  16. T3H = 0xA2; //设置定时初始值
  17. T3IF=0; //清空标志位
  18. ET3=1;//使能定时器3中断
  19. EA=1;//使能全局中断
  20. T4T3M |= 0x08; //启动定时器3
  21. }
  22. //中断回调函数
  23. void TIM2_CB(void)interrupt 12
  24. {
  25. }
  26. void TIM3_CB(void)interrupt 19
  27. {
  28. }

按键短按,长按和双击扫描

原理

这里难点在于双击的判断,我们也要做到一定的消抖,消抖顺序切记要对上,否者判断会出现一些问题的

1,(短按+长按)运用到3态状态机

流程大致为(1)按键按下->(2)消抖->(3)判断是否长按和短按

2,(短按+长按+双击)运用到7态状态机

流程大致为(1)按键按下->(2)消抖->(3)判断是否长按->(4)判断松开->(5)判断短按->

(6)消抖->(7)判断双击

代码

这边消抖的时间我们为了保守使用设置为20ms

这边的话,我之前使用到了STM32单片机来写过于是就直接复制上了,我也懒得再移植就是了,这里我们用到个结构题来存储各个按键的一些值

  1. typedef struct Keys{
  2. uint8_t State;//状态
  3. uint8_t Short_Flag;//短按标志位
  4. uint8_t Long_Flag;//长按标志位
  5. uint8_t Double_Flag;//双击标志位
  6. uint8_t Count;//计数器,计数延时
  7. uint8_t Value;//存储按键按下为1还是0
  8. uint8_t Key_Up;//弹起标志位,防止反复触发
  9. }Keys;

然后我们设置一个结构体数组变量

Keys Key[4];//设置可以扫描四个按键且互不干扰

然后 Coding Time:

短按+长按(STM32实现)少量注释和下列是相同道理的哈

  1. void TIM8_TRG_COM_TIM14_IRQHandler(void)
  2. {
  3. if(TIM_GetITStatus(TIM14,TIM_IT_Update)==SET)
  4. {
  5. Key[0].Value=!(uint8_t)KEY1;
  6. Key[1].Value=(uint8_t)KEY2;
  7. Key[2].Value=(uint8_t)KEY3;
  8. Key[3].Value=(uint8_t)KEY4;
  9. for(uint8_t i=0;i<4;i++)
  10. {
  11. switch(Key[i].State)
  12. {
  13. case 0:
  14. {
  15. if(Key[i].Value==0&&Key[i].Key_Up)
  16. {
  17. Key[i].State=1;
  18. Key[i].Key_Up=0;
  19. }
  20. else Key[i].State=0;
  21. break;
  22. }
  23. case 1:
  24. {
  25. if(Key[i].Value==0)Key[i].State=2;//消抖处理
  26. else Key[i].State=0;
  27. break;
  28. }
  29. case 2:
  30. {
  31. if(Key[i].Count<0xFF)
  32. Key[i].Count++;
  33. if(Key[i].Value==1&&Key[i].Count<=40)//超过200毫秒
  34. {
  35. Key[i].Count=0;
  36. Key[i].Short_Flag=1;
  37. Key[i].State=0;
  38. }
  39. else if(Key[i].Value==0&&Key[i].Count>40)
  40. {
  41. Key[i].Count=0;
  42. Key[i].Long_Flag=1;
  43. Key[i].State=0;
  44. }
  45. break;
  46. }
  47. }
  48. if(Key[i].Value==1)Key[i].Key_Up=1;
  49. }
  50. Time14++;
  51. TIM_ClearITPendingBit(TIM14,TIM_IT_Update);
  52. }
  53. }

短按+长按+双击(STC32实现)

  1. void TIM2_CB(void)interrupt 12 //1ms延时
  2. {
  3. static uint8_t cnt=0;
  4. uint8_t i;
  5. if(cnt++==20)//20ms循环扫描一次按键
  6. {
  7. cnt=0;
  8. Key[0].Value=(uint8_t)KEY1;
  9. for(i=0;i<1;i++)
  10. {
  11. switch(Key[i].State)
  12. {
  13. case 0:
  14. {
  15. if(Key[i].Value==0&&Key[i].Key_Up)//Key_Up防止长按按下不放反复触发
  16. {
  17. Key[i].State=1;
  18. Key[i].Key_Up=0;
  19. }
  20. else Key[i].State=0;
  21. break;
  22. }
  23. case 1:
  24. {
  25. if(Key[i].Value==0)Key[i].State=2;//第一次消抖处理
  26. else Key[i].State=0;
  27. break;
  28. }
  29. case 2:
  30. {
  31. if(Key[i].Count<0xFF)
  32. Key[i].Count++;//开始计数一个数二十毫秒
  33. if(Key[i].Value==1)//按键弹起进入按键扫描双击判断
  34. {
  35. Key[i].Count=0;
  36. Key[i].State=3;
  37. }
  38. else if(Key[i].Value==0&&Key[i].Count>35)//超过700毫秒
  39. {
  40. Key[i].Count=0;
  41. Key[i].Long_Flag=1;
  42. Key[i].State=0;
  43. }
  44. break;
  45. }
  46. case 3://弹起消抖处理
  47. {
  48. if(Key[i].Value==1)Key[i].State=4;
  49. else Key[i].State=0;
  50. break;
  51. }
  52. case 4://判断长按短按
  53. {
  54. if(Key[i].Count<0xFF)
  55. Key[i].Count++;//开始计数一个数二十毫秒
  56. if(Key[i].Value==1&&Key[i].Count>10)//超过200毫秒
  57. {
  58. Key[i].Short_Flag=1;
  59. Key[i].Count=0;
  60. Key[i].State=0;
  61. }
  62. else if(Key[i].Value==0)//二次按下消抖处理
  63. {
  64. Key[i].State=5;
  65. Key[i].Count=0;
  66. }
  67. break;
  68. }
  69. case 5://二次按下消抖处理
  70. {
  71. if(Key[i].Value==0)
  72. Key[i].State=6;
  73. else Key[i].State=0;
  74. break;
  75. }
  76. case 6://弹起再做二次标志位,别问为什么,就是正常人快按两次都是弹起
  77. {
  78. if(Key[i].Value==1)
  79. {
  80. Key[i].Double_Flag=1;
  81. Key[i].State=0;
  82. }
  83. break;
  84. }
  85. }
  86. if(Key[i].Value==1)Key[i].Key_Up=1;//判断是否弹起
  87. }
  88. }
  89. }

main函数:完成一次按键在main中判断做完事记得清除标志位哈

  1. #include <STC32G.H>
  2. #define LED1 P40
  3. #define LED2 P41
  4. #define LED3 P42
  5. void main(void)
  6. {
  7. P4M1=0x00;
  8. P4M0=0xFF;
  9. P40=0;
  10. P41=0;
  11. P42=0;
  12. Key_Init();
  13. while(1)
  14. {
  15. if(Key[0].Short_Flag==1)
  16. {
  17. LED1=!LED1;
  18. Key[0].Short_Flag=0;
  19. }
  20. if(Key[0].Long_Flag==1)
  21. {
  22. LED2=!LED2;
  23. Key[0].Long_Flag=0;
  24. }
  25. if(Key[0].Double_Flag==1)
  26. {
  27. LED3=!LED3;
  28. Key[0].Double_Flag=0;
  29. }
  30. }
  31. }

实验现象

(STC32G)最后三个灯可仅靠一个按键来控制,按键200ms后没再按下判断为短按第一个灯亮,按键长按700ms后判断为第二个灯亮,按键200ms后再按下判断为双击第三个灯亮。

总结

要学会多思考,多应用,如果有错误不当的地方请大家指证哈

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/900069
推荐阅读
相关标签
  

闽ICP备14008679号