介绍
行列扫描键盘可以将多个独立按键(通常会大于等于8个)按照行、列的结构组合起来构成一个整体键盘从而减少对于单片机 I\O 使用引脚的数量。
行列扫描接盘将独立按线和列扫描线之间交叉独立按钮。M * N按钮需要M行线和N行线。
这个项目是利用的 4 *4 显示0的矩阵键盘 ~ F 十六进制数
键盘设计:
当接在P0口时需要连接拉电阻。
这里对行列的规定是为以后的键值做准备。
操作思路
1.
2.
3.
4.
方法
根据单片机扫描键盘的不同方式,我们可以有两种想法:一种是逐行扫描,另一种是行列整体扫描。我选择了行列整体扫描。
行、列分别扫描,整体扫描。
- 行线均为高电平,列线均为低电平。
- 如果没有按钮,行线处于高电平状态
- 如果按下按钮,至少有一条行线是低电平,以确定按钮在哪条行线上
- 列线均为高电平,行线均为低电平。
- 如果没有按钮,则列线处于高电平状态
- 如果按下按钮,至少有一个列线是低电平,以确定哪个列线上的按钮
- 将获得的坐标转换为按钮对应的数字,由数字管输出
虽然这种想法可以获得按钮的行列坐标,但如何使用程序将按钮的位置信息转换为数字输出。
根据之前的学习,可以将按钮的位置信息转换为数字,并使用存储数字管显示编码的数组输出显示数字。
数字管显示控制码:
unsigned char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0~F 共阴极
晶体控制代码
我们将第0 行 和第 0 列默认为初始列,以后会看到意义。定义变量keyValue
,这个变量keyValue
存储键盘的行列值。这种方法首先确定按钮的行值。当按钮在第0行时,将keyValue
赋0值,在第 1 行赋 1值,以此类推。确定列时,确定按钮在第一位 0 列,则keyValue
第一列值不变,keyValue
值 4 ,以此类推。
电路
电路图
电路器件:
AT86C52单片机
BUTTON
74LS245
7SEG-COM-CAT-GRN
CAP
CAP-ELEC
CRYSTAL
RESPACK-7(P0可选)
代码
#include "reg52.h" //#inlucde<AT89X52.h> typedef unsigned int u16; typedef unsigned char u8; #define GPIO_DIG P0 //P0口 数值输出口 #define GPIO_KEY P2 //P2口 键盘输入口 u8 keyValue;//存储行列键盘值 u8 code smgduan[17]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0~F 共阴极
晶体管控制编码 void delay(u16 i)//延迟函数 { while(i--); } void KeyDown(void) //行列扫描函数 { char a=0; GPIO_KEY=0x0f; //输出0 if(GPIO_KEY!=0x0f) //判断是否有键被按下 { delay(1000); //延迟10ms if(GPIO_KEY!=0x0f) //延时确认有键被按下 { //测试行 GPIO_KEY=0X0F; switch(GPIO_KEY) { case(0X0e): keyValue=0;break; case(0X0d): keyValue=1;break; case(0X0b): keyValue=2;break; case(0X07): keyValue=3;break; } //测试列 GPIO_KEY=0XF0; switch(GPIO_KEY) { case(0Xe0): keyValue=keyValue;break; case(0Xd0): keyValue=keyValue+4;break; case(0Xb0): keyValue=keyValue+8;break; case(0X70): keyValue=keyValue+12;break; } while((a<50)&&(GPIO_KEY!=0xf0)) //按键松手检测 { delay(1000); a++; } } } } void main() { while(1) { KeyDown(); //行列扫描函数 GPIO_DIG=smgduan[keyValue]; //发送显示代码 } }