好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

单片机按键程序的编写.pdf

14页
  • 卖家[上传人]:mg****85
  • 文档编号:44596087
  • 上传时间:2018-06-14
  • 文档格式:PDF
  • 文档大小:269.54KB
  • / 14 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • 对于一个由单片机为核心构成的系统而言, 输入通道是相当重要的, 可以看到几乎每一样基于单片机的产品都有人机交互的部分 如各种仪器设备上的各种按钮和开关, 以及我们上的键盘,MP3 上的按键等等最常见的输入部分,莫非就是按键了对于大多数初学者而言,编写一个好的按键程序是一件颇为头疼的事情于是乎在网上乱搜一气,程序倒是找到了不少,但是看了半天依然是不明白或者在某某论坛上面发帖“跪求 XX 按键程序,大虾帮忙……”如果你偶然间进了这个论坛, 又偶然看到了这个帖子, 而且恰好你对按键程序的写法也不是很清楚,那么我希望你能够静静的看完这个帖子如果你觉得对你很有帮助,那么我希望你能够在以后的日子中能够坚持到这个论坛来, 一起交流学习, 分享自己学习过程中的喜悦或者一起探讨棘手的问题,这是我写这个帖子的最大的初衷了OK,不能再说了,再说就变成水帖了那么我们开始吧 按键的种类很多不过原理基本相似下面我们以一种轻触开关为例讲解按键程序的写法 这种轻触开关大家不陌生吧^_^ 一般情况下,按键与单片机的连接如下面这幅图所示 (图中电阻值一般去 4.7k~10k 之间,对于内部端口有上拉电阻的单片机则可省略此电阻) 单片机对于按键的按下与否则是通过检测相应引脚上的电平来实现的。

      对于上图而言,当P17 引脚上面的电平为低时,则表示按键已经按下反之,则表明按键没有按下我们在程序中只要检测到了 P17 引脚上面的电平为低了, 就可以判断按键按下 呵呵, 简单吧 等会,您先别乐呵,话还没说完呢下面我们来看看,当按键按下时,P17 引脚上面的波形是怎么变化的 上图是一个理想波形图,当按键按下时,P17 口的电平马上被拉低到 0V 了当然理想的东西都是不现实的所以我们还是看看现实的波形图吧 看出什么区别来了没呵呵,只要你不是傻子我相信都能看出其中的区别由于按键的机械特性当按键闭合时,并不能马上保存良好的接触,而是来回弹跳这个时间很短,我们的手根本感觉不出来 但是对于一秒钟执行百万条指令的单片机而言, 这个时间是相当的长了那么在这段抖动的时间内,单片机可能读到多次高低电平的变化如果不加任何处理的话,就会认为已经按下,或者松开很多次了而事实上,我们的手一直按在按键上,并没有重复按动很多次要想能够正确的判断按键是否按下就要避开这段抖动的时间根据一般按键的机械特点,以及按键的新旧程度等而言,这段抖动的时间一般在 5MS~20MS 之间 看到这里你明白了该如何做了吧 看看下面的这个流程图,你应该不陌生吧。

      这个流程是好多教科书上的做法可惜,误导了好多人为什么呢因为它根本就没有考虑实际情况我们根据这幅流程图来写它的代码看看 unsigned char v_ReadKey_f( void ) { unsigned char KeyPress ; if( P17 == 0) { Delay(20) ; //延时 20MS If( P17 == 0) { KeyPress = 1 ; While( !P17) ; //等待释放 } else KeyPress = 0 ; } } 这样一个程序,相信对很多初学者而言都不陌生因为好多书上基本都是这样的一个流程和写法可是当有一天,我们想做一个数码管加按键调整的时钟,发现当我们按键按下去的时候,数码管就不亮了为什么呢原因就在这个键盘扫描函数平常没有按键按下还好一旦有键按下,它先是浪费了 CPU 的大部分时间(就是那个什么事情都没做的延时 20MS函数)然后,又霸占 CPU( 就是哪个死死等在那里的 while(P17);语句)直到按键释放对于这种情况我们是忍无可忍的, 那么就让我们彻底的抛弃它吧 那么到底按键扫描函数改如何写呢……..所谓众里寻她千百度,蓦然回首,那人却在灯火阑珊处。

      如果我们把 CPU 延时的那 20MS 拿出来去做其它事情,那么不就充分利用 CPU 的时间了吗而一般情况下我们只要前沿去抖动就可以了也就是说了,我们只需在按键按下后去抖就可以了,对于按键的释放抖动可以不必要过于关注 当然这主要和应用的场合有关 一个能有效识别按键按下并支持连发功能的按键已经能够应用到大多数的场合了 下面以四个独立按键的处理程序为例来讲解(支持单击和连发) #include“regx52.h“ sbit KeyOne = P1^0 ; sbit KeyTwo = P1^1 ; sbit KeyThree = P1^2 ; sbit KeyFour = P1^3 ; #define uint16 unsigned int #define uint8 unsigned char #define NOKEY 0xff #define KEY_WOBBLE_TIME 500 //去抖动时间(待定) #define KEY_OVER_TIME 15000 //等待进入连击时间(待定),该常数要比正常 //按键时间要长,防止非目的性进入连击模式 #define KEY_QUICK_TIME 1000 //等待按键抬起的连击时间(待定) void v_KeyInit_f( void ) { KeyOne = 1 ; //按键初始化(相应端口写 1) KeyTwo = 1 ; KeyThree = 1 ; KeyFour = 1 ; } uint8 u8_ReadKey_f(void) { static uint8 LastKey = NOKEY ; //保存上一次的键值 static uint16 KeyCount = 0 ; //按键延时计数器 static uint16 KeyOverTime = KEY_OVER_TIME ; //按键抬起时间 uint8 KeyTemp = NOKEY ; //临时保存读到的键值 KeyTemp = P1 //读键值 if( KeyTemp == 0x0f ) { KeyCount = 0 ; KeyOverTime = KEY_OVER_TIME ; return NOKEY ; //无键按下返回 NOKEY } else { if( KeyTemp == LastKey ) //是否第一次按下 { if( ++KeyCount == KEY_WOBBLE_TIME ) //不是第一次按下,则判断//抖动是否结束 { return KeyTemp ; //去抖动结束,返回键值 } else { if( KeyCount > KeyOverTime ) { KeyCount = 0 ; KeyOverTime = KEY_QUICK_TIME ; } return NOKEY ; } } else //是第一次按下则保存键值, 以便下次执行此函数时与读到的键值作比较 { LastKey = KeyTemp ; //保存第一次读到的键值 KeyCount = 0 ; //延时计数器清零 KeyOverTime = KEY_OVER_TIME ; return NOKEY ; } } } 下面是我测试用的主程序(相关头文件未列出,仅仅作测试演示用) void main(void) { uint8 KeyValue ; int16 Count ; v_LcdInit_f() ; v_KeyInit_f() ; CLS LOCATE(3, 1) PRINT(“Key Test“) LOCATE(6, 2) SHOW_ICON while(1) { KeyValue = u8_ReadKey_f() ; if( KeyValue != NOKEY ) { LOCATE(1, 2) if( KeyValue == 0x0e )Count++ ; if( KeyValue == 0x0d )Count-- ; if( KeyValue == 0x0b )Count = 0 ; if( KeyValue == 0x07 )Count = 0 ; HIDE_ICON PRINTD(Count, 5) LOCATE(6, 2) } else { //SHOW_ICON } } } 每次执行读键盘函数时,只是对一些标志进行判断,然后退出。

      因此能够充分的利用 CPU的资源同时可以处理连发按键此按键扫描按键函数可以直接放在主函数中如果感觉按键太过灵敏或者迟钝则改一下相关消抖动的宏定义即可 此函数也可以通过中断标志位进行定时的扫描此时,需要添加一个定时标志位,并将相关消抖动的和连击时间的宏定义改小即可然后在主程序类似下面这样写即可 if( KeyTime ) //定时扫描时间到 { KeyValue = u8_ReadKey_f() ; } 具体的工作就交给您去完成啦 看看效果: 按键单击 连发时候的截图 至此,关于单个按键的学习就告一段落了,您是否已经明白了如果您还不明白,那么把这个程序好好的看看, 并画下流程图, 分析分析估计您就会恍然大悟关键是思路要转换过来 下面我们来看看多个按键的情况吧 一般情况下, 如果多个按键每个都直接接在单片机的 I/O 上的话会占用很多的 I/O 资源 比较合理的一种做法是,按照行列接成矩阵的形式按键接在每一个的行列的相交处这样对于 m 行 n 列的矩阵,可以接的按键总数是 m*n这里我们以常见的 4*4 矩阵键盘来讲解矩阵键盘的编程 上图就是矩阵键盘的一般接法 这里我们要介绍一种快速的键盘扫描法:线反转法(或者称为行列翻转法)。

      具体流程如下首先,让单片机的行全部输出 0,列全部输出 1,读取列的值(假设行接 P3 口的高四位,列接低四位)即 P3= 0x0f ; 此时读列的值,如果有键按下,则相应的列读回来的值应该为低 譬如此时读回来的值为 0x0e ; 即按键列的位置已经确定 这时反过来, 把行作为输入,列作为输出,即 P0 = 0xf0 ;此时再读行的值,如果按键仍然被按下,则相应的行的值应该为低,如果此时读回来的值为 0xe0,则确定了行的位置 说到这里,您应该笑了,知道了一个按键被按下的行和列的位置, 那么就可以肯定确定它的位置了 我们把读回来的行值和列值进行或运算即 0xe0 | 0x 0e 即 0xee那么 0xee 就是我们按下的按键的键值了只需几步就可以判断所有的键值,简单吧下面再结合一个例子具体看看 /****************************************** * 此模块所需相关支持库 * ******************************************/ #include“regx52.h“ #define uint8 unsigned char #define uint16 unsigned int /**************************************** * 与硬件连接相关的定义及宏定义和操作宏 * *****************************************/ #define KEYBOARD P3 //键盘连接到单片机上的端口位置 #define READ_ROW_ENLABLE KEYBOARD = 0x0f ; //读端口之前先把相应口置位(由基本 51 单片机特性决定的) #define READ_COL_ENLABLE KEYBOARD = 0xf0 ;。

      点击阅读更多内容
      关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.