1、项目分析
- 单片机也需要人机交互,掌握常用的输入和输出设备非常必要。
- 本章选取了最常用的输入模块键盘来演示其典型程序的编制方法。
2、技术准备
1 独立键盘输入
-
P3口第二功能表
-
P3.0—P3.7: 双功能口(内置了上拉电阻) 它具有特定的第二功能。
-
在不使用它的第二功能时它就是普通的通用准双向I/O口。
- 读端口和读引脚
- 读端口:就是读Pn端口寄存器;
- 读引脚:就是读该引脚在Pn端口寄存器中的对应位,通过引用Pn端口寄存器的值,或者引用Pn端口寄存器中的对应位,就可以实现读端口或者读引脚。
2 认识按键
- 轻触开关是一种电子开关,使用时,轻轻按开关按钮就可使开关接通,当松开手时,开关断开。
3 按键分类
- 键盘输入检测的基本方法:
- 轮询法。
1. 独立按键
- 每一个按键对应每一个引脚,相当于一个按键控制一个引脚
2. 矩阵按键
- 矩阵按键能控制的东西比较多,使用的引脚也比较多,如果每一个按键控制一个引脚,那么需要16个引脚,若使用矩阵式键盘,则仅需1个引脚组即可,但程序设计相对复杂一些。
- 矩阵式键盘的识别方法
1. 逐列扫描法
- 判断键盘是否按键按下,方法是向所有列线上输入低电平,再读入所有行信号,如果16个按键中任意一个按键被按下,则读入的行电平则不全为高;反之如无按键按下,则读入的行电平全为高。若S10被按下,则S10按键所在的行线2与列线1导通,则行线的电平被拉低,读入的行信号为低电平,则表示按键已经被按下(现还无法判断是S9、S10、S11、S12被按下)。
- 逐列扫描判断具体的按键,方法是向列线上逐列送低电平,现送到列线0,列线1、2、3为高电平,读入的行电平的状态就显示了位于列线0的S1、S5、S9、S13四个按键的按键的状态。若键入的行值为全高,则表示无按键按下;在送到列线1,列线0、2、3为高电平,读入的行电平状态则显示S2、S6、S10、S14四个按键的按键的状态,依次类推,直到全部扫描完毕。
2. 行列反转法
-
基本原则:通过给行列端口输出两次相反的值,再分别读入的行值和列值进行 求和 或按位 或 运算,得到每个键的扫描码。
- 向所有的列线上输入低电平,列线输入2次相反的值。
- 读入行信号,如果16个按键中任意一个按键被按下,读入的行信号则不全为高,反之,则行信号则全为高,记录此刻的值。
- 向所有的列线上出高电平,行线输入低电平(行列反转),读入所有的列信号,记录此刻的值。
- 将行和列的值合并成扫描码。通过查找扫描码表的方法得出 “哪个按键被按下”。
-
具体实现过程:
- 首先,给P1口输入0xf0,即:11110000,若S10按键被按下,则读入的P1的值为:11010000,在给P1赋相反的值0x0f,即:11110000,此时读入的P1口的值为:00001011,再次把读入的P1的值进行相加或按位 “或” 操作,得到:11011011,即0xdb,这个值是按键S1的扫描码,以此类推,得到其余15个按键的扫描码。
- 首先,给P1口输入0xf0,即:11110000,若S10按键被按下,则读入的P1的值为:11010000,在给P1赋相反的值0x0f,即:11110000,此时读入的P1口的值为:00001011,再次把读入的P1的值进行相加或按位 “或” 操作,得到:11011011,即0xdb,这个值是按键S1的扫描码,以此类推,得到其余15个按键的扫描码。
3 按键抖动
- 按键中有一个金属弹片,当按下按键时会挤压金属弹片来导通电流,而松手时金属弹片会弹回去,在其闭合、断开瞬间均有抖动过程,抖动时间一般在5—10ms。
- 按下和松手都会让金属弹片有抖动,这个抖动的电流是不稳定的,会影响程序对按键的判断。
- 解决方法
- 硬件处理方法:使用另一种没用抖动或者抖动频率小的硬件。
- 软件处理方法:使用程序来超过这个抖动,也就是用一个延迟函数来将这个按下的抖动时间消除(消抖)。
4 按键原理图
-
判断按键按下的实现方法
- 先判断键是否按下,若按下了延时10 ms,跳过按下抖动期。
- 再判断按键是否按下,若是说明按键真的按下了,否则说明是干扰信号,如果键真的按下了,则等待键释放,如果键释放了,延时10 ms,
- 再判断键是否释放,若释放了,说明按键真的释放了,否则说明是干扰信号,如果按键真的释放了,说明一次完整的按键过程完成了。
3、项目实现
1 1个按键控制1个LED灯亮灭
- 实验要求
- 按下K2 则LED1亮,再次按下LED1灭,如此循环。
- 按下K2 则LED1亮,再次按下LED1灭,如此循环。
- 实验分析
- 判断按键是否按下,按下则对LED灯的状态取反。
- 判断按键是否按下,按下则对LED灯的状态取反。
- 实验代码
#include <reg52.h> // 2、定义端口:按键/LED sbit key = P3^4; sbit led = P1^0; void delay(unsigned int v); void main() { while(1) { // 3、判断按键是否按下:按下key对应的电平值为0 if(key == 0) { // 消抖 - 10ms delay(1000); // 再次判断按键是否按下 if(key == 0) { // 按键是按下:电平值为0趋于稳定 // 方法1:判断le