IT评测·应用市场-qidao123.com
标题:
51单片机教程(十)- 独立按键输入
[打印本页]
作者:
农妇山泉一亩田
时间:
2024-12-2 15:04
标题:
51单片机教程(十)- 独立按键输入
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灭,如此循环。
实行分析
判断按键是否按下,按下则对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:判断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企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4