一.键盘
1.键盘
键盘是电子系统中人机对话的重要组成部分,是人向机器发出指令、输入信息的必须设备
键盘在单片机应用系统中是使用最广泛的一种数据输入设备。键盘是由多个按键组成的。
2.按键
按键通常是一种常开型开关,常态下按键的两个触点处于断开状态,按下按键时它们才闭合。
通常键盘有编码键盘和非编码键盘两种。编码键盘通过硬件电路产生被按按键的键值码,这种键盘使用方便,所需程序简单,但硬件电路复杂,
如计算机的键盘,单片机则通常不采用编码键盘。而软件编程来识别的称为非编码键盘,非编码键盘硬件电路简单。在单片机组成的各种系统中,最常用的是非编码键盘。
3.独立键盘与矩阵键盘
非编码键盘分为独立键盘和矩阵键盘。
- 独立键盘:每个按键占用一个IO口,当按键数量较多时,lO口利用效率不高,但程序简单,适用于所需按键较少的场合。
- 矩阵键盘:电路连按复杂,但提高了IO口利用率,软件编程较复杂。适用于使用大量按键的场合。

讯享网
二.独立键盘
1.抖动
了解了独立键盘的原理图之后,我们知道如果键盘按下,那么线路导通IO口会接触到GND从而电压为0,所以我们可以通过IO口电压的变换来判断独立按键是否被按下。
结合上一篇控制单片机数码管的显示,我们很自然的想到如果按键按下实现数字加1显示的实验,为了好实验这里选择数码管的静态显示实验。
那么,有初始的源代码:
#include <reg52.h> //51头文件 #define uchar unsigned char //宏定义 #define uint unsigned int //宏定义 sbit we = P2^7; //位定义数码管位选锁存器接口 sbit du = P2^6; //位定义数码管段选锁存器接口 sbit key_s2 = P3^0; //定义独立键盘S2的IO口 uchar num = 0; //数码管段选表 uchar code leddata[]={
0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; void main() {
we = 1;//打开位选 P0 = 0xfe;//左边第一位数码管显示 we = 0; //关闭位选 while(1) {
if(key_s2 == 0){
num++; if(num == 10) num == 0 } du = 1; //打开段选 P0 = leddata[num]; //显示num du = 0; //关闭段选 }; }
讯享网
执行上面的代码后,你会发现单片机并没有按照我们想要的结果去运行,每当你按下时,数码管显示的结果并不是上一个加1,这是因为按键本身按下或释放存在抖动的原因,要想取得正确的结果,必须消除抖动。

结合实际的波形,我们可以知道按下的过程中,下降沿的波形并不出现一次,自然而然的我们就必须把它变成理想的波形,方法就是采用延时函数。
2.松手检测
消除抖动的常见方法是使用延时函数,延时函数一般选择延时20ms左右即可完成。

讯享网#include <reg52.h> //51头文件 #define uchar unsigned char //宏定义 #define uint unsigned int //宏定义 sbit we = P2^7; //位定义数码管位选锁存器接口 sbit du = P2^6; //位定义数码管段选锁存器接口 sbit key_s2 = P3^0; //定义独立键盘S2的IO口 uchar num = 0; //数码管段选表 uchar code leddata[]={
0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; //毫秒级延时函数 void delay(uint z) {
uint x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } void main() {
we = 1;//打开位选 P0 = 0xfe;//左边第一位数码管显示 we = 0; //关闭位选 while(1) {
delay(20);//消除抖动 if(key_s2 == 0){
num++; if(num == 10) num == 0 } du = 1; //打开段选 P0 = leddata[num]; //显示num du = 0; //关闭段选 }; }
消除抖动你以为就完成了吗,继续运行,实际过程中,你会发现随着按下的时间,它还是并不是加1的运行,仔细思考你的代码,按键按下,num++一直在运行,显示的值也就不断变换,所以我们还需要进行松手检测,让每次按下只实现加1。
最后的代码为:
#include <reg52.h> //51头文件 #define uchar unsigned char //宏定义 #define uint unsigned int //宏定义 sbit we = P2^7; //位定义数码管位选锁存器接口 sbit du = P2^6; //位定义数码管段选锁存器接口 sbit key_s2 = P3^0; //定义独立键盘S2的IO口 uchar num = 0; //数码管段选表 uchar code leddata[]={
0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; //毫秒级延时函数 void delay(uint z) {
uint x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } void main() {
we = 1;//打开位选 P0 = 0xfe;//左边第一位数码管显示 we = 0; //关闭位选 while(1) {
delay(20);//消除抖动 if(key_s2 == 0){
num++; while(!key_s2);//松手检测 } if(num == 10) num=0; du = 1; //打开段选 P0 = leddata[num]; //显示num du = 0; //关闭段选 }; }
3.拓展
讯享网#include <reg52.h> //51头文件 #define uchar unsigned char //宏定义 #define uint unsigned int //宏定义 sbit we = P2^7; //位定义数码管位选锁存器接口 sbit du = P2^6; //位定义数码管段选锁存器接口 sbit key_s2 = P3^0; //定义独立键盘S2的IO口 sbit key_s3 = P3^1; //定义独立键盘S2的IO口 uchar num = 0; //数码管段选表 uchar code leddata[]={
0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; //毫秒级延时函数 void delay(uint z) {
uint x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } void main() {
we = 1;//打开位选 P0 = 0xfe;//左边第一位数码管显示 we = 0; //关闭位选 while(1) {
delay(20);//消除抖动 if(key_s2 == 0){
num++; while(!key_s2);//松手检测 } if(key_s3 == 0){
if(num > 0) num--; while(!key_s3); } if(num == 10) num=0; du = 1; //打开段选 P0 = leddata[num]; //显示num du = 0; //关闭段选 }; }
三.矩阵键盘
1.识别方法
矩阵键盘识别相对于独立键盘要复杂一些。右图矩阵键盘一共有4行和4列一共16个按键组成。
确定矩阵键盘上哪一个按键被按下可以采用列扫描和行扫描。列扫描时先把接在列上面的所有IO口拉高接在行上的所有IO置低。当其中有一列内任何一个按键按下那么整条列线都会被拉低。同理,行扫描时先把接在行上面的所有IO口拉高,接在列上的所有IO置低。当其中有一行内任何一个按键按下那么整条列线都会被拉低。
这是一个数学问题,总共16个按键分为四行四列,我们只需要知道哪一列和哪一行就知道了哪个按键。所以列扫描就是确定列,行扫描就是确定行。
2.程序编写
知道矩阵键盘的识别方法后,当按下不同的按键,数码管显示不同的值:
#include <reg52.h> //51头文件 #define uchar unsigned char //宏定义 #define uint unsigned int //宏定义 sbit we = P2^7; //位定义数码管位选锁存器接口 sbit du = P2^6; //位定义数码管段选锁存器接口 uchar keyvalue = 20; //按键的值 //数码管段选表 uchar code leddata[]={
0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; //毫秒级延时函数 void delay(uint z) {
uint x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } //扫描函数 void keyscanf(){
P3 = 0xF0; //列扫描 if(P3!=0xF0){
//判断按键是否被按下 delay(10); //延时消除抖动 if(P3!=0xF0) {
switch(P3) {
case 0xe0: keyvalue=0;break; case 0xd0: keyvalue=1;break; case 0xb0: keyvalue=2;break; case 0x70: keyvalue=3;break; } P3=0x0f; //行扫描 switch(P3) {
case 0x0e: keyvalue=keyvalue;break; case 0x0d: keyvalue=keyvalue+4;break; case 0x0b: keyvalue=keyvalue+8;break; case 0x07: keyvalue=keyvalue+12;break; } while(P3!=0x0f); //松手检测 } } } void main() {
we = 1;//打开位选 P0 = 0xfe;//左边第一位数码管显示 we = 0; //锁存位选数据 while(1) {
keyscanf(); //不停检查键盘 du = 1;//打开段选 P0 = leddata[keyvalue]; du = 0;//锁存段选数据 } }
3.联合编写
学习了独立按键和矩阵键盘后,有一个问题,如果在一个程序中既用到独立按键又用到矩阵键盘的时候,该怎么办?我们的单片机原理图中,独立按键和矩阵键盘使用的都是P3端口。
讯享网#include <reg52.h> //51头文件 #define uchar unsigned char //宏定义 #define uint unsigned int //宏定义 sbit we = P2^7; //位定义数码管位选锁存器接口 sbit du = P2^6; //位定义数码管段选锁存器接口 uchar keyvalue = 22; //按键的值 //数码管段选表 uchar code leddata[]={
0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; //毫秒级延时函数 void delay(uint z) {
uint x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } //扫描函数 void keyscanf(){
//4*4矩阵键盘扫描函数 P3 = 0xF0; //列扫描 if(P3!=0xF0){
//判断按键是否被按下 delay(10); //延时消除抖动 if(P3!=0xF0) {
switch(P3) {
case 0xe0: keyvalue=0;break; case 0xd0: keyvalue=1;break; case 0xb0: keyvalue=2;break; case 0x70: keyvalue=3;break; } P3=0x0f; //行扫描 switch(P3) {
case 0x0e: keyvalue=keyvalue;break; case 0x0d: keyvalue=keyvalue+4;break; case 0x0b: keyvalue=keyvalue+8;break; case 0x07: keyvalue=keyvalue+12;break; } while(P3!=0x0f); //松手检测 } } //独立键盘扫描函数 P3 = 0xff; if(P3!=0xff) {
delay(10);//软件消抖 if(P3!=0xff) {
switch(P3) {
case 0xfe: keyvalue=16;break;//S2 case 0xfd: keyvalue=17;break;//S3 case 0xfb: keyvalue=18;break;//S4 case 0xf7: keyvalue=19;break;//S5 } while(P3!=0xff); //松手检测 } } } void main() {
we = 1;//打开位选 P0 = 0xfe;//左边第一位数码管显示 we = 0; //锁存位选数据 while(1) {
keyscanf(); //不停检查键盘 du = 1;//打开段选 P0 = leddata[keyvalue]; du = 0;//锁存段选数据 } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/125339.html