历史上的今天
今天是: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_
上一篇:PIC单片机基础1
史海拾趣
|
问:请TI公司的DSP技术专家GeorgeShen先生和AccountManager王剑先生做一下自我介绍。(10:36:50 AM)答:大家好,这里是TI公司的盛戎华、王剣,很高兴和大家一起讨论TI的DSP产品。 Good morning! Hello this is George Sheng, an Field Application Eng ...… 查看全部问答> |
|
首次发帖---国内最详细的linux基础教程(不过是第一版)---网域时代的教程 确实详细,只是版本有点老,贡献一下,供参考。 点击此处下载 或粘帖:http://download.eeworld.net/source/2251570… 查看全部问答> |
|
2410 内部 1 ram起始地址被映射到哪里?容量有多大? 2 rom起始地址被映射到哪里?容量有多大? 2410 启动方式: 3 2410外启动时,第一条指令时在哪里执行的? & ...… 查看全部问答> |
|
大家好! 我们要开发一个sim卡的读卡器 gsm协议中提到了dialling number的概念,但是并没有明确提出通讯录是如何存储的, 请教大家dialling number和通讯录之间是什么关系?是不是通过读取dialling number就 可以读取通讯录了? 谢谢! … 查看全部问答> |
|
我用高精度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 ...… 查看全部问答> |




