历史上的今天
返回首页

历史上的今天

今天是:2024年11月27日(星期三)

正在发生

2019年11月27日 | 单片机按键学习总结

2019-11-27 来源:eefocus

基本的按键程序结构分析:


 1 void key_scan(void)

 2 {

 3       if (!key)                           //检测按键是否按下

 4       {

 5           delay_ms(20);                   //延时去抖,一般20ms

 6           if(!key)

 7           {

 8                ......

 9           }

10           while (!key);                   //等待按键释放

11      }       

12 }   


注意:以上基本按键程序中,在按键执行之后必须要加上等待按键释放,否则程序会出现一些奇怪的问题,比如说按键累加时按键一次,却累加了多次。


可识别长击和短击按键程序(有限状态机):


主函数文件:


main.c


 1 #include "key.h"

 2 

 3 sbit LED = P2^0;

 4 

 5 u8 timer0_flag;                                    //定时器10ms计时标记

 6 

 7 

 8 void timer0_init(void)

 9 {

10     TMOD |= 0x01;                                 //定时器0的方式1(16位定时器)

11     TH0 = 0xDC;                                    //定时10ms初值

12     TL0 = 0x00;

13     

14     ET0 = 1;

15     TR0 = 1;

16     EA  = 1;

17 }

18 

19 void main(void)

20 {

21     key_init();                                    //按键初始化,51单片机在读取某个端口的值时,先拉高

22     timer0_init();                                 //定时器初始化

23     

24     for (;;)    

25     {

26         if (timer0_flag)

27         {

28             timer0_flag = 0;

29             

30             switch (key_driver())    

31             {

32                 case KEY_SHORT: LED = 0; break;    //短击点亮LED灯

33                 case KEY_LONG : LED = 1; break;    //长击熄灭LED灯

34             }

35         }

36     }

37 }

38 

39 void timer0_int(void) interrupt 1                //中断处理函数

40 {

41     TH0 = 0xDC;

42     TL0 = 0x00;

43     timer0_flag = 1;

44 }


主文件里非常重要的有两处:


1、时间粒度控制:本程序以10ms做时间单位,类似于时间片轮询的方式,每隔10ms对按键状态扫描一次,对应代码为:


void timer0_int(void) interrupt 1                //中断处理函数


{     


  TH0 = 0xDC;     


  TL0 = 0x00;     


  timer0_flag = 1;       //10ms时间


 }


2、对按键驱动函数返回值的判断,根据按键返回值,识别按键操作是短击还是长击后,执行相应的动作,对应代码为:


switch (key_driver())    


{      case KEY_SHORT: LED = 0; break;    //短击点亮LED灯

      case KEY_LONG : LED = 1; break;    //长击熄灭LED灯


}


按键驱动文件:


key.c


 1 #include "key.h"

 2 

 3 sbit KEY_INPUT = P3^3;                                         //独立按键

 4 

 5 key custom_key;                                                //按键的数据结构体

 6 

 7 void key_init(void)                                            //按键初始化

 8 {

 9     KEY_INPUT = 1;

10 }

11 

12 u8 key_driver(void)                                            //按键驱动函数

13 {

14     custom_key.press = KEY_INPUT;                              //读取按键接口值

15     custom_key.value = KEY_NONE;                               //返回值初始化为无值

16     

17     switch(custom_key.state)                                   //按键状态判断

18     {

19         case KEY_STATE_JUDGE:                                  //判断有无按键按下状态

20             if (!custom_key.press)                             //有按键按下

21             {

22                 custom_key.state = KEY_STATE_DEBOUNCE;         //转入消抖状态

23                 custom_key.count = 0;                          //计数器清零

24             }

25         break;

26         

27         case KEY_STATE_DEBOUNCE:                               //消抖状态

28             if (!custom_key.press)

29             {

30                 custom_key.count ++;

31                 if (custom_key.count >= SINGLE_KEY_TIME)

32                 {

33                     custom_key.state = KEY_STATE_SPAN;         //消抖确认是有效按键,转入短击和长击判断状态

34                 }

35             }

36             else 

37                 custom_key.state = KEY_STATE_JUDGE;            //按键误动作,返回判断有无按键按下状态

38         break;

39         

40         case KEY_STATE_SPAN:                                   //短击和长击判断状态

41             if (custom_key.press)                              //在长击临界值之前释放按键,判断为短击

42             {

43                 custom_key.value = KEY_SHORT;

44                 custom_key.state = KEY_STATE_JUDGE;            //返回判断有无按键按下状态

45             }

46             else                                               //计数器值超过长击临界值,判断为长击

47             {

48                 custom_key.count ++;

49                 if (custom_key.count >= LONG_KEY_TIME)

50                 {

51                     custom_key.value = KEY_LONG;

52                     custom_key.state = KEY_STATE_RELEASE;      //进入按键释放状态

53                 }

54             }

55         break;

56         

57         case KEY_STATE_RELEASE:                                //按键释放状态

58             if (custom_key.press)

59             {

60                 custom_key.state = KEY_STATE_JUDGE;            //返回判断有无按键按下状态

61             }

62         break;

63         

64         default:                                               //默认返回判断有无按键按下状态

65             custom_key.state = KEY_STATE_JUDGE;

66             break;

67     }

68     return custom_key.value;                                   //返回按键值

69 }


代码中做了详细的注释,需要说明的是按键的四种状态:


KEY_STATE_JUDGE:用来检测是否有按键按下, 当有按键按下后,转移到消抖状态,否则每次时间片扫描时都处于此状态  


KEY_STATE_DEBOUNCE:消抖状态,用来检测按键有效还是误触发,假如只是误触发,则返回到按键等待状态


KEY_STATE_SPAN:判断按键是长击还是短击,如果在延时消抖后,按键在长按的临界值之前释放,则判断为短击,否则判断为长击,此处的临界值为2s

KEY_STATE_RELEASE:按键释放状态,摆脱用while循环等待按键释放,当判断为长击以后,程序将进入此状态,在此之后只需在每次时间片到了以后判断是否释放即可


此处需要理解的是“并行”的思想:主程序一直在for(;;)循环中运行,同时定时器也在不断累加计数,当达到定时器中断触发条件后,定时器中断当前的循环,进入定时器服务程序。因此,这四种状态在每次定时器中断触发后就会检测判断一次,相隔时间为10ms。


头文件:

key.h


 1 #ifndef _KEY_H_

 2 #define _KEY_H_

推荐阅读

史海拾趣

Computer Conversions Corp公司的发展小趣事

随着云计算和大数据技术的兴起,计算机行业迎来了新一轮的变革。Computer Conversions Corp公司迅速调整战略,开始研发与云计算相结合的新型转换设备。通过不断地技术革新和产品迭代,公司成功推出了一系列高效、稳定的云计算转换解决方案,帮助众多企业顺利迁移到了云平台,从而保持了在行业中的领先地位。

Advanced Photonix公司的发展小趣事

在电子行业的早期,Advanced Photonix以其卓越的光学技术脱颖而出。公司创始团队由一群富有远见的科学家和工程师组成,他们专注于研发高速光电子和高性能的光纤测试产品。经过无数次的实验和试错,团队终于成功开发出一种具有创新性的光纤传感技术,这一技术为电信行业提供了前所未有的分布式光纤传感解决方案。这一技术突破不仅为Advanced Photonix赢得了市场声誉,也奠定了公司在电子行业的重要地位。

ADL [ADL Embedded Solutions Inc]公司的发展小趣事

Advanced Photonix一直注重研发团队的建设和培养。公司投入大量资源用于研发创新,鼓励团队成员不断探索新技术和新应用。在这种氛围下,公司的研发团队不断取得新的突破和进展。他们成功开发出了一系列具有自主知识产权的光电产品和解决方案,这些产品不仅提升了公司的技术实力,也为公司的长期发展奠定了坚实的基础。

FTDI [Future Technology Devices International Ltd.]公司的发展小趣事

2013年,FTDI推出了最新的嵌入式视频引擎(EVE)技术产品,这一创新标志着公司进入了一个新的技术领域。EVE技术将高度先进的图形控制器、显示器、音频和触摸功能集成到单一芯片中,为智能显示器在各种终端应用中的实现提供了强大支持。这一技术的推出不仅展示了FTDI在图像处理和显示领域的深厚积累,也为其后续在更多领域的拓展奠定了基础。

EOZ S.A.S公司的发展小趣事

EOZ S.A.S公司非常重视企业文化和团队建设。公司倡导“创新、协作、共赢”的价值观,鼓励员工积极参与创新活动并分享创新成果。同时,公司还注重员工的培训和发展,为员工提供丰富的培训资源和晋升机会。这些举措不仅激发了员工的积极性和创造力,也为企业的发展提供了有力的人才保障。在EOZ S.A.S公司的发展历程中,优秀的企业文化和团队成为公司最宝贵的财富之一。

GREATECS公司的发展小趣事

随着5G技术的普及,EOZ S.A.S公司意识到这将为电子行业带来革命性的变化。公司迅速调整战略,将研发重心转向5G相关技术和产品。通过与运营商合作,EOZ S.A.S成功推出了一系列基于5G技术的智能家居和物联网产品,如智能音箱、智能门锁等。这些产品凭借高速、低延迟的特点,满足了消费者对智能家居的多样化需求,进一步巩固了公司在市场中的地位。

问答坊 | AI 解惑

TI 公司DSP产品相关FAQ整理

问:请TI公司的DSP技术专家GeorgeShen先生和AccountManager王剑先生做一下自我介绍。(10:36:50 AM)答:大家好,这里是TI公司的盛戎华、王剣,很高兴和大家一起讨论TI的DSP产品。 Good morning! Hello this is George Sheng, an Field Application Eng ...…

查看全部问答>

贴片元器件(密引脚IC)焊接教程

贴片元器件(密引脚IC)焊接教程…

查看全部问答>

首次发帖---国内最详细的linux基础教程(不过是第一版)---网域时代的教程

确实详细,只是版本有点老,贡献一下,供参考。 点击此处下载 或粘帖:http://download.eeworld.net/source/2251570…

查看全部问答>

如何去理解NTFS格式

如题,如何了解NTFS格式(各方面)。。。 有什么推荐的书?…

查看全部问答>

2410 的存储器以及有关启动的问题????????

2410 内部     1  ram起始地址被映射到哪里?容量有多大?     2  rom起始地址被映射到哪里?容量有多大? 2410 启动方式:     3  2410外启动时,第一条指令时在哪里执行的? & ...…

查看全部问答>

[求助]请教sim卡中通讯录的存储问题

大家好! 我们要开发一个sim卡的读卡器 gsm协议中提到了dialling number的概念,但是并没有明确提出通讯录是如何存储的, 请教大家dialling number和通讯录之间是什么关系?是不是通过读取dialling number就 可以读取通讯录了? 谢谢! …

查看全部问答>

OP放大器的双极性与FET连接的概念

什么是OP放大器的双极性连接 什么有是FET连接呢?谢谢…

查看全部问答>

求教LVDT传感器问题

我用高精度LVDT传感器测位移,LVDT信号调理电路是厂家自带的,我现在保持测头固定不动,隔半分钟测量一次,每次测量值(一次采样100个数据求平均值)下降一个mV,请问这是怎么回事?就算是LVDT受温度影响也不至于变化这么快吧?难道信号调理电路有 ...…

查看全部问答>

用ATMEGA16控制NRF905进行简单的收发,调了一周了,希望哪位大侠能帮俺播开云雾!!

发送段代码: #include <iom16v.h>#include <macros.h>#define uint  unsigned int#define uchar unsigned char#define   Low_TX_EN      PORTD&=~(1 << PD7)#define   High ...…

查看全部问答>