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个按键的扫描码。
3 按键抖动
- 按键中有一个金属弹片,当按下按键时会挤压金属弹片来导通电流,而松手时金属弹片会弹归去,在其闭合、断开瞬间均有抖动过程,抖动时间一样寻常在5—10ms。
- 按下和松手都会让金属弹片有抖动,这个抖动的电流是不稳固的,会影响程序对按键的判断。
- 解决方法
- 硬件处理方法:利用另一种没用抖动或者抖动频率小的硬件。
- 软件处理方法:利用程序来超过这个抖动,也就是用一个延迟函数来将这个按下的抖动时间消除(消抖)。
4 按键原理图
- 先判断键是否按下,若按下了延时10 ms,跳过按下抖动期。
- 再判断按键是否按下,若是说明按键真的按下了,否则说明是干扰信号,如果键真的按下了,则等候键开释,如果键开释了,延时10 ms,
- 再判断键是否开释,若开释了,说明按键真的开释了,否则说明是干扰信号,如果按键真的开释了,说明一次完整的按键过程完成了。
3、项目实现
1 1个按键控制1个LED灯亮灭
- 实行要求
- 按下K2 则LED1亮,再次按下LED1灭,如此循环。
- 实行分析
- 实行代码
- #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:判断led的状态,如果是电平值为0,则设置为1,否则设置为0
- // if(led == 1){
- // led = 0;
- // }else{
- // led = 1;
- // }
-
- // 方法2:对LED状态值取反
- led = !led;
- }
- }
- }
- }
- // 延迟函数
- void delay(unsigned int v)
- {
- while(v--);
- }
复制代码
2 4个按键控制4个LED灯
- 实行要求
- 按下第1个独立按键K2 2个赤色的led灯亮
- 按下第2个独立按键K3 2个绿色的led灯亮
- 按下第3个独立按键K4 2个黄色的led灯亮
- 按下第4个独立按键K5 2个蓝色的led灯亮
- 实行分析
- 若分别独立判断K2-K5是否按下,则代码冗余,可以编写函数用于扫描哪个按键按下并返回,通过返回值判断,实现LED的亮灭控制。
- 实行代码
- #include <reg52.h>
-
- #define uint unsigned int
-
- // 定义端口:4个按键/LED
- sbit key2 = P3^4;
- sbit key3 = P3^5;
- sbit key4 = P3^6;
- sbit key5 = P3^7;
- sbit led1 = P1^0;
- sbit led2 = P1^2;
- sbit led3 = P1^4;
- sbit led4 = P1^6;
- // 定义按键的取值
- #define KEY2_PRESS 2
- #define KEY3_PRESS 3
- #define KEY4_PRESS 4
- #define KEY5_PRESS 5
- #define KEY_UNPRESS 0
- uint key_scan(uint mode);
- void delay(unsigned int v);
- void main()
- {
- while(1)
- {
- // 表示获取哪个按键被按下
- uint key_value = key_scan(1); // 返回值:0 2 3 4 5
-
- // 判断对应的按键来实现LED灯控制
- switch(key_value){
- case KEY2_PRESS: led1 = !led1; break;
- case KEY3_PRESS: led2 = !led2; break;
- case KEY4_PRESS: led3 = !led3; break;
- case KEY5_PRESS: led4 = !led4; break;
- }
- }
- }
- /*
- 功能:按键扫描函数
- 参数:
- mode: 表示按键扫描方式
- 0:单次扫描
- 1:连续扫描
- 返回值:
- 2 表示K2按下
- 3 表示K3按下
- 4 表示K4按下
- 5 表示K5按下
- 0 表示无按键按下
- */
- uint key_scan(uint mode)
- {
- // 定义按键的初始状态值
- static uint key = 1;
-
- // 对模式的判断
- if(mode) key=1;
-
- // 判断4个按键中是否按下
- if(key==1 && (key2 == 0 || key3 == 0 || key4 == 0 || key5 == 0))
- {
- // 消抖
- delay(1000);
- key = 0;
-
- // 判断具体是哪个按键按下
- if(key2 == 0) return KEY2_PRESS; // return 2
- if(key3 == 0) return KEY3_PRESS; // return 3
- if(key4 == 0) return KEY4_PRESS; // return 4
- if(key5 == 0) return KEY5_PRESS; // return 5
- }else if(key2 == 1 && key3 == 1 && key4 == 1 && key5 == 1){
- key = 1;
- }
- return KEY_UNPRESS;
- }
- // 延迟函数
- void delay(unsigned int v)
- {
- while(v--);
- }
复制代码 3 按键控制数码管显示
- 实行要求
- 按下按键1实现数码管+1;
- 按下按键2实现数码管-1;
- 按下按键3清零;
- 实行分析
- 先利用2位数码显示00-99,判断按键是否按下,则修改记录数据变量值加1,减1或者为0的设置,同时需当数值减为0则设置为0,当加到99则设置为99。
- #include <reg52.h>
- #include "delay.h"
- #define uint unsigned int
- // 定义位选与段选
- #define pos P2
- #define par P0
- // 定义端口:4个按键/LED
- sbit key2 = P3^4;
- sbit key3 = P3^5;
- sbit key4 = P3^6;
- sbit key5 = P3^7;
- // 定义按键的取值
- #define KEY2_PRESS 2
- #define KEY3_PRESS 3
- #define KEY4_PRESS 4
- #define KEY5_PRESS 5
- #define KEY_UNPRESS 0
- // 分别对应:0/1/2/3/4/5/6/7/8/9
- uint par_value[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
- // 记录数码管显示值
- uint number = 3;
- uint ge, shi;
- uint keyScan(uint mode);
- void delay(uint v);
- void main()
- {
- while(1)
- {
- uint key_value = keyScan(0);
-
- // 判断对应的按键来控制数值是否越界控制
- if(key_value == KEY2_PRESS)
- {
- if(number == 99)
- {
- number = 99;
- }else{
- number++;
- }
- }
- else if(key_value == KEY3_PRESS)
- {
- if(number == 0)
- {
- number = 0;
- }else{
- number--;
- }
- }
- else if(key_value == KEY4_PRESS)
- {
- number = 0;
- }
-
- shi = number / 10;
- ge = number % 10;
-
- // 显示十位
- pos = 0x18;
- par = par_value[shi];
- delay(100);
-
- // 显示个位
- pos = 0x28;
- par = par_value[ge];
- delay(100);
- }
- }
- uint keyScan(uint mode)
- {
- // 定义按键的初始状态值
- static uint key = 1;
-
- // 对模式的判断
- if(mode) key=1;
-
- // 判断4个按键中是否按下
- if(key==1 && (key2 == 0 || key3 == 0 || key4 == 0 || key5 == 0))
- {
- // 消抖
- delay(5000);
- key = 0;
-
- // 判断具体是哪个按键按下
- if(key2 == 0) return KEY2_PRESS; // return 2
- if(key3 == 0) return KEY3_PRESS; // return 3
- if(key4 == 0) return KEY4_PRESS; // return 4
- if(key5 == 0) return KEY5_PRESS; // return 5
- }else if(key2 == 1 && key3 == 1 && key4 == 1 && key5 == 1){
- key = 1;
- }
- return KEY_UNPRESS;
- }
- // 延迟函数
- void delay(unsigned int v)
- {
- while(v--);
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |