51单片机外设篇:按键
关于按键
按键相当于是一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实现接通和断开。
最基础的就是使用死循环来对按键动作做轮询判断。
比如,监测如果某个按键按下,某个LED就会亮。
对于机械开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开,所以在开关闭合及断开的瞬间会伴随一连串的抖动:
可以通过延时来做消抖。
上拉电阻
上拉电阻:
将一个不确定的信号(高或低电平),通过一个电阻与电源VCC相连,固定在高电平。
下拉电阻:
将一个不确定的信号(高或低电平),通过一个电阻与地GND相连,固定在低电平。
当上拉电阻和下拉电阻共同作用时,表现为接地端的低电平状态。
查看原理图
独立按键:
代码实现
此处,我将JP5引脚接到P1端口,将LED灯接到P0端口。
1、按一个按键,就亮对应的LED灯。
/***@file key.c*@author Timi*@date 2022.07.21*/#include <reg51.h>#define uchar unsigned charvoid KeyLightLed();//函数入口 void main(void) { KeyLightLed(); }/***@brief*@param[in]*@param[out]*@return*/ void KeyLightLed() {uchar portData[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};while(1){int i = 0;for (i; i < 8; i++){if(P1 == portData[i]){P0 = ~portData[i];} }} }
2、点击一个按钮,控制其中一个LED灯,再次点击该按钮,则又熄灭,再按又亮起,如此循环往复。即每个按钮都会改变对应LED灯的状态。
/***@file key.c*@author Timi*@date 2022.07.21*/#include <reg51.h>#define uchar unsigned charsbit P00 = P0^0; sbit P01 = P0^1; sbit P02 = P0^2; sbit P03 = P0^3; sbit P04 = P0^4; sbit P05 = P0^5; sbit P06 = P0^6; sbit P07 = P0^7;sbit P10 = P1^0; sbit P11 = P1^1; sbit P12 = P1^2; sbit P13 = P1^3; sbit P14 = P1^4; sbit P15 = P1^5; sbit P16 = P1^6; sbit P17 = P1^7;void KeyLightLed();//函数入口 void main(void) { KeyLightLed(); }/***@brief*@param[in]*@param[out]*@return*/ void KeyLightLed() {P0 = 0x0;while(1){ if(P10 == 0){P00 = ~P00;}if(P11 == 0){P01 = ~P01;}if(P12 == 0){P02 = ~P02;}if(P13 == 0){P03 = ~P03;}if(P14 == 0){P04 = ~P04;}if(P15 == 0){P05 = ~P05;}if(P16 == 0){P06 = ~P06;}if(P17 == 0){P07 = ~P07;}} }
关于这种方式的灵敏度问题。
当按键数量少的时候,其实不太明显,如果按键数量太多,就会导致在按下某个按键的时候,CPU还在执行其他部分的代码,因此检测按键不及时。
3、按键消抖
上面提到过按键在按下和弹起的过程中会有抖动,这会引起一些问题,比如按键在按下和弹起时会有闪烁,更明显的是,比如按键控制数码管数字依次增加,如果不消抖,就有可能按下时因为抖动,导致检测到多次的低电平,所以明明只按下一次按键,数字却是无规律地增长,比如有时增加1,有时又增加不止1。
所以常常都需要消抖,消抖有两方面,一方面是硬件消抖(比如利用电容器来使抖动变得更平滑),另一方面是软件消抖,即在检测到一次某种电平时,不急着进行某种操作,而是延时一段时间,因为这种电平有可能是抖动期间引起的,并不稳定。
通常,消抖的延时时间在5—20毫秒之间,一般选择10毫秒就行。示例代码如下:
/***@file key.c*@author Timi*@date 2022.07.21*/#include <reg51.h>#define uchar unsigned charsbit P00 = P0^0;sbit P10 = P1^0;void KeyLightLed(void); void Delay10ms(void);//函数入口 void main(void) { KeyLightLed(); }/***@brief*@param[in]*@param[out]*@return*/ void KeyLightLed(void) {P0 = 0x0;while(1){ if(P10 == 0){//先不着急点亮LED,延时10ms后再判断,如果还是一样的状态则点亮Delay10ms();if (P10 == 0){P00 = 1;}}else{//先不着急点亮LED,延时10ms后再判断,如果还是一样的状态则点亮Delay10ms();if (P10 == 1){P00 = 0;}}} }/***@brief*@param[in]*@param[out]*@return*/ void Delay10ms(void) //误差 0us {uchar a, b, c;for(c=5; c > 0; c--){for(b=4;b>0;b--){for(a=248;a>0;a--);}} }
中断的引入
任务:独立数码管循环显示0-F,同时按键控制LED亮灭。
要想实现这两个功能,都需要CPU执行死循环,怎么办呢?最简单的就是将这两个程序都放在同一个死循环中。可以在一定程度上解决这个问题。
但是这样也存在一个问题,那就是按键检测可能不及时,导致按键不灵敏。
为什么呢?因为只有在执行完t1时间后,来到t2时间才能执行按键检测代码,所以如果按键一直按着等待检测,还能起作用;要是快速按下按键,就有大概率处于t1时间,那么就检测不到了。
这两个任务需要实现宏观上的并行执行。其中,t1时间远大于t2的时间,t1可以是秒级,t2几乎是微秒级,差距还是较大的。
此时,数码管循环显示就可以看做是主线任务。“主线任务”为常规任务,默认运行。
可以将类似按键检测的这种任务绑定到中断。中断发生后CPU暂停主线任务转去处理中断任务,完成后再回来接着执行主线任务。由于中断处理程序所耗费的时间较短,所以几乎不会对主线任务产生影响。
中断流程:
中断处理能力让CPU可以全力处理主线任务而不用担心会错过中断任务(举例:看电影和收快递)
中断式比轮询式更适合处理异步事件,效率更高。
中断中处理的事件的特点是:无法预料、处理时间短、响应要求急。
中断能力是CPU本身设计时支持的,并不是编程制造出来的
程序员只要负责2件事即可:主程序中初始化中断、定义中断处理程序。
当中断条件发生时,硬件会自动检测到并且通知CPU,CPU会自动去执行中断处理程序,这一切都是CPU设计时定下的,不需要编程干预。
51单片机的中断
内容较多,具体内容阅读数据手册,中断系统相关章节。
外部中断0使用示例如下:
我们这里就用INT0来进行简单的按键处理。
在电路连接上,需要将按键的一端连接到中断引脚上,INT0的引脚为P3.2
如果中断没有打开并使能,那么P3.2就是一个普通的GPIO。
这里我有个疑惑,那就是,INT0只有一个引脚,那么不就只有1个按键能触发中断了?这也太少了吧。
暂且不管,后面再说。~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
中断代码实现
实现功能如下:按键K1触发外部中断0,然后就执行相应的代码,点亮LED。
/***@file key.c*@author Timi*@date 2022.07.21*/#include <reg51.h>#define uchar unsigned charsbit P00 = P0^0;sbit P10 = P1^0;void KeyLightLed(void); void Delay10ms(void);//函数入口 void main(void) { IT0 = 1; //选择下降沿触发EX0 = 1; //使能INT0EA = 1; //打开中断开关while(1); }/***@brief*@param[in]*@param[out]*@return*/ void KeyLightLed(void) interrupt 0 {P0 = 0xAA; }
矩阵键盘
按键作为最基本的输入设备,有独立按键和矩阵按键两种。
和LED类似的理念,独立按键就是两个引脚都有单独的线连接。矩阵按键则是将许多按键的同一端连接在一起,然后通过扫描来检测哪个按键被按下。
独立按键与单片机连接时, 每一个按键都需要单片机的一个 I/O 口, 若某单片机系统需较多按键, 用独立按键便会占用过多的 I/O 口资源。 单片机系统中 I/O 口资源往往比较宝贵, 当用到多个按键时为了减少 I/O 口引脚, 引入了矩阵按键,一般叫做矩阵键盘。
可以看到是将16个按键排成4行4列,前面的四行分别连接io口的每一行,后面的四行分别连接io口的每一列,这样就实现了每个io口都连接四个按键,同样通过这样的方式也可以实现3X3,5X5等这样的布局。
那么在检测的时候又是如何实现的呢,这种按键的检测一般是通过扫描来实现的。
具体原理解析如下:
首先,假定p10-p13接地,p14-p17接电源,则可以通过检测p14-p17是否有电平被拉低,因为扫描的速度够快,所以能检测到按键按下,但这种情况只能确定有哪一行被按下了,并不能定位到具体的按键。
要想定位到具体的按键,那么就需要用到二维检测。
首先,让p10置低电平,p11-p13置高电平,同时检测p14-p17是否有电平被拉低,假如此时检测到p14有电平变化,则肯定是s1按键被按下了。同理,可以检测到任意一个按键是否被按下。
矩阵键盘:
优点:省单片机IO
缺点:不能同时按下多个按键数码管扫描(输出扫描)
原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果;
矩阵键盘扫描(输入扫描)
原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果。
查看原理图
代码实现
将JP4连接到P1端口,P1端口全部为高电平。
/***@file key.c*@author Timi*@date 2022.07.21*/#include <reg51.h>#define uchar unsigned charsbit P10 = P1^0; sbit P11 = P1^1; sbit P12 = P1^2; sbit P13 = P1^3; sbit P14 = P1^4; sbit P15 = P1^5; sbit P16 = P1^6; sbit P17 = P1^7;void KeyLightLed(void); void FeelKey();//函数入口 void main(void) { KeyLightLed(); }/***@brief*@param[in]*@param[out]*@return*/ void KeyLightLed(void) {while(1){ P1 = 0xFE; //经测试,最后一列是P1.7控制的FeelKey();P1 = 0xFD; //经测试,最后一列是P1.7控制的FeelKey();P1 = 0xFB; //经测试,最后一列是P1.7控制的FeelKey();P1 = 0xF7; //经测试,最后一列是P1.7控制的FeelKey();} }/***@brief*@param[in]*@param[out]*@return*/ void FeelKey() {if(P14 == 0){P0 = 0x01;}if(P15 == 0){P0 = 0x02;}if(P16 == 0){P0 = 0x04;}if(P17 == 0){P0 = 0x08;} }
51单片机外设篇:按键相关推荐
- 51单片机外设篇:蜂鸣器
蜂鸣器 蜂鸣器是一种将电信号转换为声音信号的器件,常用来产生设备的按键音.报警音等提示信号. 蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器: 有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发 ...
- 51单片机外设篇:点阵式LCD
什么是LCD LCD(Liquid Crystal Display)俗称液晶. 液晶是一种材料,液晶这种材料具有一种特点:可以在电信号的驱动下液晶分子进行旋转,旋转时会影响透光性,因此我们可以在整个液 ...
- 51单片机外设篇:数码管
数码管简介 LED数码管:数码管是一种简单.廉价的显示器,是由多个发光二极管封装在一起组成"8"字型的器件.比如红绿灯. 单个数码管: 多个数码管: 这些引脚由对应的寄存器控制着, ...
- 学习笔记之51单片机键盘篇(非编码键盘与编码键盘、非编码键盘的扫描方式、独立键盘、矩阵键盘)
这篇博文主要记录51单片机键盘篇(非编码键盘与编码键盘.非编码键盘的扫描方式.独立键盘.矩阵键盘.键盘消抖等)包含原理图.代码等 (一)基础补充 1.键盘的任务 2.键盘的识别 3.如何消除按键的抖动 ...
- 51单片机 玩转按键加减切换+数码管+Proteus仿真
51单片机 玩转按键加减切换+数码管+Proteus仿真 实例代码 /* 实验说明:实验接线:1,动态数码管模块-->单片机管脚2,独立按键模块-->单片机管脚 K1-->P10K2 ...
- 51单片机:独立按键控制数码管计数
//按键动作的前沿和后沿会都有大约10ms的抖动,人在按下按键到松开至少需要50ms以上(待考证).此代码实现的功能为给按键计数,并给按键消抖 //欢迎邮箱交流:bglei@foxmail.com 作 ...
- 蓝桥杯51单片机之独立按键控制数码管【单片机开发初学者必学会】
文章目录 一.写在前面 二.无中断控制数码管 三.外部中断控制数码管 一.写在前面 关于数码管的控制与显示,在文章51单片机之数码管从点亮到动态时钟的实现[单片机开发初学者通俗易懂]已经有详细介绍了, ...
- 51单片机多路独立按键开关程序
51单片机8路独立按键开关程序 每一个按键对应一个led灯,实现独立开关灯. 源程序: ** #include <reg51.h> #define uint unsigned int #d ...
- 【51单片机】矩阵按键实现数码管显示
目录 前言 数码管 共阴极数码管 共阳极数码管 共阴极数码管表 数码管硬件设计 数码管显示软件设计 矩阵按键 按键介绍 按键消抖 矩阵按键硬件设计 矩阵按键实现数码管显示软件设计 总结 前言 闲的没事 ...
- (三)51单片机基础——独立按键与数码管
从小就对电器元件比较感兴趣吧,经常拿坏的电器里面的芯片拆下来玩,甚至那些没坏的电器,比如我家的电视,也会希望它能坏掉,我好去看看里面是什么样子的,为什么能播放节目--,所以我第一眼看到51单片机的时候 ...
最新文章
- BZOJ3930: [CQOI2015]选数
- Android开发优化之——对界面UI的优化(经验分享)
- make memuconfig的问题:'make menuconfig' requires the ncurses libraries
- popoupwindow 点击背景消失_欺骗13亿人 国产剧的“假房子”什么时候消失?
- 【操作】Json取value时,为什么得到的是undefined?
- 惠普omen测试软件,双GTX1080奢华魔方PC 惠普OMEN X评测
- 2021年互联网婚庆行业洞察
- 深入解读 MySQL 底层原理,让性能“飞起来”的方法总结
- Battle Encoder Shirase一款能限制进程CPU占有率的小东西
- hdu 1802 Black and white painting(置换群)
- Laravel5.2队列驱动expire参数设置带来的重复执行问题 数据库驱动
- Linux之scsi网络存储
- 高分屏笔记本,如何处理程序提示“文本缩放比率要求为100%”
- Win10系统怎么映射网络驱动器?
- 农村三资管理平台app_农村三资管理系统功能
- 微信公众号模板消息设置
- [ 英语 ] 语法重塑 之 英语学习的核心框架 —— 英语兔学习笔记(1)
- 软件服务化:管理当先
- node.js基于微信小程序的外卖订餐系统 uniapp 小程序
- 数据分析常用名称、统计分析模型 SUS、CLV、VOC、认知失调、 体验度量
热门文章
- 我为什么放弃使用MyBatis3的Mapper注解
- Unity3D开发之unity和js通信交互
- linux中终端进入目录太多时造成终端路径显示太长的路径影响观看的解决方法
- 计算机 工程伦理论文题目,北京工业大学研究生院
- java基于JSP+Servlet的员工绩效考核系统
- SVN客户端和中文包的安装
- office 2003 兼容包 (兼容 office 2007 office 2010)
- java中word转pdf实现
- ASP.NET实现简单的聊天室
- HTML5期末大作业:中华美德文化网站设计——中华美德文化(6页) HTML+CSS+JavaScript 中国传统美德文化网页HTML代码