更多单片机学习笔记:
单片机学习笔记 1. 点亮一个LED灯
单片机学习笔记 2. LED灯闪烁
单片机学习笔记 3. LED灯流水灯
单片机学习笔记 4. 蜂鸣器滴~滴~滴~
单片机学习笔记 5. 数码管静态显示
单片机学习笔记 6. 数码管动态显示
单片机学习笔记 7. 独立键盘
目录
0、实现的功能
1、Keil工程
1-1 矩阵键盘识别方法
1-2 swich语句
2、代码实现
0、实现的功能
4*4矩阵键盘+独立键盘的按键检测,可拓展为四管显示
1、Keil工程
1-1 矩阵键盘识别方法
主要采用列扫描(1111 0000)和行扫描(0000 1111)的方法。
列扫描的初始操作是输入P3口为0xF0,当S6被按下时,P34由1会变为0,此时P3口为0xE0;同理,S10被按下时,P3也为0xE0。所以第一列被按下时,P3为1110 0000;第二列被按下时,P3为1101 0000;第三列被按下时,P3为1011 0000;第四列被按下时,P3为0111 0000。
所以P30--P33为行线,P34--P37为列线
再做行扫描,P3初始为0x0F。当S6被按下时,P30会从1变为0,P3为0000 1110.最后再和列扫描的结果相加:1110 0000 + 0000 1110 = 1110 1110,得到确切的位置(第一列,第一行)
所以P3的数据中,前四位为哪一列,后四位为哪一行。谁为0就是哪一行列
1-2 swich语句
主要涉及到c语言中的switch语句
2、代码实现
显示的按键序号和对应显示数字表如下:
只要是涉及到按键的,都要进行软件消抖+松手检测。赋值P3=0xf0进行列扫描,找到是哪一列,KeyValue可以直接为0 1 2 3------赋值P3=0x0f进行行扫描,每行之间相差4,此时KeyValue对应的+4即可
独立按键扫描的话,赋值P3=0xff,这样就不是列扫描和行扫描了。按下哪个,哪一位就为0,找到对应的显示数字即可
代码实现:
#include <reg52.h>
#include <intrins.h>#define uchar unsigned char
#define uint unsigned intsbit WE = P2^7; //锁存器位选,U8的LE,选择哪个数码管
sbit DU = P2^6; //锁存器段选,U9的LE,控制亮什么数字uchar KeyValue = 6; //按键显示值//共阴极数码管段选表0-9
uchar code table1[] = {
//0 1 2 3 4 5 6 7 8
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f,
//9 A B C D E F H L
0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x76, 0x38,
//n u - 熄灭
0x37, 0x3e, 0x40, 0x00} ;//延时模块
void delay(uint z)
{uint x;uint y;for(x = z; x > 0; x--)for(y = 114; y > 0; y--);
}void KeyScan()
{//4*4矩阵键盘扫描P3 = 0xf0; //列扫描初始化if(P3 != 0xf0) //判断按键是否被按下{delay(10); //软件消抖10msif(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); //软件消抖10msif(P3 != 0xff){switch(P3) //判断哪一行被按下{case 0xfe: KeyValue = 16; break; //S2case 0xfd: KeyValue = 17; break; //S3case 0xfb: KeyValue = 18; break; //S4case 0xf7: KeyValue = 19; break; //S5}while(P3 != 0xff); //松手检测 }}
}void main()
{//指定第一个数码管,不用放在循环里P0 = 0xff;//清除断码,让位锁存器哪个都不选WE = 1;//位选锁存打开P0 = 0xfe;//选第一个管WE = 0; //进入锁存while(1){KeyScan(); //20个按键扫描DU = 1;//段选锁存打开P0 = table1[KeyValue];DU = 0;//进入锁存}
}
可以结合数码管动态显示,弄点好玩的
#include <reg52.h>
#include <intrins.h>#define uchar unsigned char
#define uint unsigned intsbit WE = P2^7; //锁存器位选,U8的LE,选择哪个数码管
sbit DU = P2^6; //锁存器段选,U9的LE,控制亮什么数字uchar KeyValue = 6; //按键显示值//共阴极数码管段选表0-9
uchar code table1[] = {
//0 1 2 3 4 5 6 7 8
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f,
//9 A B C D E F H K
0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x76, 0x76,
//n u - 熄灭
0x37, 0x3e, 0x40, 0x00} ;//延时模块
void delay(uint z)
{uint x;uint y;for(x = z; x > 0; x--)for(y = 114; y > 0; y--);
}void KeyScan()
{//4*4矩阵键盘扫描P3 = 0xf0; //列扫描初始化if(P3 != 0xf0) //判断按键是否被按下{delay(10); //软件消抖10msif(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); //软件消抖10msif(P3 != 0xff){switch(P3) //判断哪一行被按下{case 0xfe: KeyValue = 16; break; //S2case 0xfd: KeyValue = 17; break; //S3case 0xfb: KeyValue = 18; break; //S4case 0xf7: KeyValue = 19; break; //S5}while(P3 != 0xff); //松手检测 }}
}void main()
{while(1){KeyScan(); //20个按键扫描P0 = 0xff;//清除断码,让位锁存器哪个都不选WE = 1;//位选锁存打开P0 = 0xfe;//选第一个管WE = 0; //进入锁存DU = 1;//段选锁存打开P0 = table1[KeyValue];DU = 0;//进入锁存delay(5);P0 = 0xff;//清除断码,让位锁存器哪个都不选WE = 1;//位选锁存打开P0 = 0xfd;//选第2个管WE = 0; //进入锁存DU = 1;//段选锁存打开P0 = table1[KeyValue+4];DU = 0;//进入锁存delay(5);P0 = 0xff;//清除断码,让位锁存器哪个都不选WE = 1;//位选锁存打开P0 = 0xfb;//选第3个管WE = 0; //进入锁存DU = 1;//段选锁存打开P0 = table1[KeyValue-3];DU = 0;//进入锁存delay(5);P0 = 0xff;//清除断码,让位锁存器哪个都不选WE = 1;//位选锁存打开P0 = 0xf7;//选第4个管WE = 0; //进入锁存DU = 1;//段选锁存打开P0 = table1[KeyValue+2];DU = 0;//进入锁存delay(5);}
}
实物展示: