一个按键程序的思考
来源:互联网 发布:ipad淘宝购物车打不开 编辑:程序博客网 时间:2024/06/05 22:53
2017.07.26 程序笔记
今天思考一个关于按键的程序:结构体如下
if(PC_Get_Key(&key)==TURE){ if(key==0x1B) { PC_DOSReturen(); }}
思考了一下,这个可以作为电堆按键检测的一个大体的框架,结合基本的按键处理程序,就可以实现功能
If(0 == io_KeyEnter) //如果有键按下了 { Delayms(20) ; //先延时20ms避开抖动时期 If(0 == io_KeyEnter) //然后再检测,如果还是检测到有键按下 { return KeyValue ; //是真的按下了,返回键值 } else { return KEY_NULL //是抖动,返回空的键值 } while(0 == io_KeyEnter) ; //等待按键释放 }
下面是基本的C51处理按键的一部分
因为51单片机I/O口内部结构的限制,在读取外部引脚状态的时候,需要向端口写1,在51单片机复位后,不需要进行此操作也可以进行读取外部引脚的操作。因此,在按键的端口没有复用的情况下,可以省略此步骤。而对于其它一些真正双向I/O口的单片机来说,将引脚设置成输入状态,是必不可少的一个步骤。
//初始化引脚为输入 void KeyInit(void) { io_key_1 = 1; io_key_2 = 1; io_key_3 = 1; io_key_4 = 1; } //根据按键硬件连接定义按键键值 #define KEY_VALUE_1 0x0e #define KEY_VALUE_2 0x0d #define KEY_VALUE_3 0x0b #define KEY_VALUE_4 0x07 #define KEY_NULL 0x0f
下面我们来编写按键的硬件驱动程序。根据第一章所描述的按键检测原理,我们可以很容易的得出如下的代码:
static uint8 KeyScan(void) { if(io_key_1 == 0)return KEY_VALUE_1 ; if(io_key_2 == 0)return KEY_VALUE_2 ; if(io_key_3 == 0)return KEY_VALUE_3 ; if(io_key_4 == 0)return KEY_VALUE_4 ;
return KEY_NULL ; }
其中io_key_1等是我们按键端口的定义,如下所示:
sbit io_key_1 = P3 ^ 0 ; sbit io_key_2 = P3 ^ 1 ; sbit io_key_3 = P3 ^ 2 ; sbit io_key_4 = P3 ^ 3 ;
KeyScan()作为底层按键的驱动程序,为上层按键扫描提供一个接口,这样我们编写的上层按键扫描函数可以几乎不用修改就可以拿到我们的其它程序中去使用,使得程序复用性大大提高。同时,通过有意识
的将与底层硬件连接紧密的程序和与硬件无关的代码分开写,使得程序结构层次清晰,可移植性也更好。对于单片机类的程序而言,能够做到函数级别的代码重用已经足够了。在编写我们的上层按键扫描函数之前,需要先完成一些宏定义。
//定义长按键的TICK数,以及连发间隔的TICK数 #define KEY_LONG_PERIOD 100 #define KEY_CONTINUE_PERIOD 25 //定义按键返回值状态(按下,长按,连发,释放) #define KEY_DOWN 0x80 #define KEY_LONG 0x40 #define KEY_CONTINUE 0x20 #define KEY_UP 0x10 //定义按键状态 #define KEY_STATE_INIT 0 #define KEY_STATE_WOBBLE 1 #define KEY_STATE_PRESS 2 #define KEY_STATE_LONG 3 #define KEY_STATE_CONTINUE 4 #define KEY_STATE_RELEASE 5 接着我们开始编写完整的上层按键扫描函数,按键的短按,长按,连按,释放等等状态的判断均是在此函数中完成。对照状态流程转移图,然后再看下面的函数代码,可以更容易的去理解函数的执行流程。完整的函数代码如下: void GetKey(uint8 *pKeyValue) { static uint8 s_u8KeyState = KEY_STATE_INIT; static uint8 s_u8KeyTimeCount = 0; static uint8 s_u8LastKey = KEY_NULL; //保存按键释放时候的键值 uint8 KeyTemp = KEY_NULL; KeyTemp = KeyScan(); //获取键值 switch(s_u8KeyState) { case KEY_STATE_INIT: {
if(KEY_NULL != (KeyTemp)) { s_u8KeyState = KEY_STATE_WOBBLE; } } break; case KEY_STATE_WOBBLE: //消抖 { s_u8KeyState = KEY_STATE_PRESS; } break; case KEY_STATE_PRESS: { if(KEY_NULL != (KeyTemp)) { s_u8LastKey = KeyTemp; //保存键值,以便在释放按键状态返回键值 KeyTemp |= KEY_DOWN; //按键按下 s_u8KeyState = KEY_STATE_LONG; } else { s_u8KeyState = KEY_STATE_INIT; } } break; case KEY_STATE_LONG: { if(KEY_NULL != (KeyTemp)) { if(++s_u8KeyTimeCount > KEY_LONG_PERIOD) { s_u8KeyTimeCount = 0; KeyTemp |= KEY_LONG; //长按键事件发生 s_u8KeyState = KEY_STATE_CONTINUE; } } else { s_u8KeyState = KEY_STATE_RELEASE; } } break; case KEY_STATE_CONTINUE:
{ if(KEY_NULL != (KeyTemp)) { if(++s_u8KeyTimeCount > KEY_CONTINUE_PERIOD) { s_u8KeyTimeCount = 0; KeyTemp |= KEY_CONTINUE; } } else { s_u8KeyState = KEY_STATE_RELEASE; } } break; case KEY_STATE_RELEASE: { s_u8LastKey |= KEY_UP; KeyTemp = s_u8LastKey; s_u8KeyState = KEY_STATE_INIT; } break; default: break; } *pKeyValue = KeyTemp; //返回键值 } 关于这个函数内部的细节我并不打算花过多笔墨去讲解。对照着按键状态流程转移图,然后去看程序代码,你会发现其实思路非常清晰。最能让人理解透彻的,莫非就是将整个程序自己看懂,然后想象为什么这个地方要这样写,抱着思考的态度去阅读程序,你会发现自己的程序水平会慢慢的提高。所以我更希望的是你能够认认真真的看完,然后思考。也许你会收获更多。不管怎么样,这样的一个程序已经完成了本章开始时候要求的功能:按下,长按,连按,释放。事实上,如果掌握了这种基于状态转移的思想,你会发现要求实现其它按键功能,譬如,多键按下,功能键等等,亦相当简单,在下一章,我们就去实现它。
阅读全文
0 0
- 一个按键程序的思考
- 一个双色球模拟程序引发的思考
- 一个VB(Net)程序的思考
- 一个串口程序引起的思考
- 一个很好按键检测程序
- 关于独立按键扫描程序的思考(整合两种算法)
- 关于独立按键扫描程序的思考(整合两种算法)
- 关于独立按键扫描程序的思考(整合两种算法)
- 关于独立按键扫描程序的思考(整合两种算法)
- 独立按键扫描程序的思考(整合两种算法)
- 一个手咪按键,检测抬起和按下的思考
- 一个十几行简单的C程序引发的思考
- 一个关于c++数值转换的小程序的思考
- 一个C++程序编译失败引发的思考
- 我对JAVA中一个多线程程序的思考
- 屌丝程序猿对一个产品的思考
- 屌丝程序猿对一个产品的思考
- 学习思考(5):如何开发一个完整的程序?
- HANA基础篇 YTD实例
- js中this的使用
- C++中的静态绑定和动态绑定
- Base64Encoder编码和解码
- 微信小程序如何实现底部导航栏
- 一个按键程序的思考
- note_cloud--笔记本加载功能
- PAT 1060爱丁顿数
- iOS 仿直播321倒计时动画
- 机器学习实战笔记(1)——kNN(k Nearest Neighbor)算法
- Centos 6.9 Redis 4.0.1 高可用配置
- java代码规范
- ssm练习(发送信息)
- linux grep 命令详解及示例