vx:【嵌入式工程师成长日记】
具体功能实现
当我们按下矩阵按键中不同的按键时,在LCD1602显示相应的内容,同时一个按键按下多次可以切换不同的字母或数字,并且LED灯会闪烁。最后当我们按下确认时,蜂鸣器会发出不同频率的声音。
器件
蜂鸣器,AT89C51,若干按键,LCD1602,两支LED灯,排阻
仿真展示图
仿真前
仿真后
知识介绍
矩阵按键控制原理
如果使用独立按键与单片机连接, 每一个按键都需要单片机的一个 I/O 口, 若某单片机系统需较多按键, 用独立按键便会占用过多的 I/O 口资源。 单片机系统中 I/O 口资源往往比较宝贵, 当用到多个按键时为了减少 I/O 口引脚, 引入了矩阵按键。
矩阵按键检测原理
按键检测一般通过扫描来实现,先使某一列变为低电平,其余几列为高电平,后检测每行是否出现低电平。若没有出现,则某行按键没有被按下,若出现则说明按键被按下,即可锁定位置。
矩阵按键控制方法
①行列式法:
上图将第一列全部置0,其余位置均为1
将第一行全部置0,其余位全部置1。
因此我们可以得出按键按下的正是第一行第一列的
②线翻转法:
首先使所有行置为0,然后检测列是否含有低电平,如果有,则记录列的位置;之后再翻转,使所有列置为0,检测行是否有低电平,如果有,则记录行的位置(本文采用的是线翻转法)
主函数代码(C语言)KEIL5实现
#include <reg51.h>
#include <intrins.h>
void delay(unsigned char ms);
void delay2(int i);
void lcd_wcmd(unsigned char cmd);
void lcd_pos(unsigned char pos);
void lcd_wdat(unsigned char dat);
void lcd_init();
void xianshi();
void KeyDown();
void la_ba();
sbit rs= P2^6;
sbit rw = P2^5;
sbit ep = P2^7;
sbit d=P3^0;
sbit d1=P3^1;
sbit lb=P3^2;
int b,c,s=0,q=0,w=0;
#define GPIO_KEY P1
unsigned char dis1[32];
unsigned char dis2[9]={',','A','D','G','J','M','P','T','W'};
unsigned char dis3[9]={'1','2','3','4','5','6','7','8','9'};
unsigned int code laba[36][5]={
1,2,3,3,3,//A
2,1,1,1,3,//B
2,1,2,1,3,//C
2,1,1,3,3,//D
1,3,3,3,3,//E
1,1,2,1,3,//F
2,2,1,3,3,//G
1,1,1,1,3,//H
1,1,3,3,3,//I
1,2,2,2,3,//J
2,1,2,3,3,//K
1,2,1,1,3,//L
2,2,3,3,3,//M
2,1,3,3,3,//N
2,2,2,3,3,//0
1,2,2,1,3,//P
2,2,1,2,3,//Q
1,2,1,3,3,//R
1,1,1,3,3,//S
2,3,3,3,3,//T
1,1,2,3,3,//U
1,1,1,2,3,//V
1,2,2,3,3,//W
2,1,1,2,3,//X
2,1,2,2,3,//Y
2,2,1,1,3,//Z
2,2,2,2,2,//0
1,2,2,2,2,//1
1,1,2,2,2,//2
1,1,1,2,2,//3
1,1,1,1,2,//4
1,1,1,1,1,//5
2,1,1,1,1,//6
2,2,1,1,1,//7
2,2,2,1,1,//8
2,2,2,2,1,//9
};
// LCD1602代码开始
bit lcd_bz()
{
bit result;
rs = 0;
rw = 1;
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result = (bit)(P0 & 0x80);
ep = 0;
return result;
}
void lcd_wcmd(unsigned char cmd)
{
while(lcd_bz());//判断LCD是否忙碌
rs = 0;
rw = 0;
ep = 0;
_nop_();
_nop_();
P0 = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
void lcd_pos(unsigned char pos)
{
lcd_wcmd(pos | 0x80);
}
void lcd_wdat(unsigned char dat)
{
while(lcd_bz());//判断LCD是否忙碌
rs = 1;
rw = 0;
ep = 0;
P0 = dat;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
void lcd_init()
{
lcd_wcmd(0x38);
delay(1);
lcd_wcmd(0x0c);
delay(1);
lcd_wcmd(0x06);
delay(1);
lcd_wcmd(0x01);
delay(1);
}
void xianshi()
{
int i=0,j=1,n=0;
while(dis1[i] != '\0')
{
lcd_pos(0x00);//设置显示位置
while(j!=0&&dis1[i] != '\0')
{
lcd_wdat(dis1[i]);//显示字符
i++;
j=i%16;
}
lcd_pos(0x40);// 设置显示位置
j=1;
while(j!=0&&dis1[i] != '\0')
{
lcd_wdat(dis1[i]);// 显示字符
i++;
j=i%16;
}
j=1;
if(dis1[i] != '\0')
i-=16;
}
i=0;
}
//LCD1602代码结束
void delay(unsigned char ms)
{
unsigned char i;
while(ms--)
{
for(i = 0; i< 250; i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
void delay2(int i)
{
while(i--);
}
//按下按键
void KeyDown()
{
int KeyValue=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)
{
delay(5); //消抖
if(GPIO_KEY!=0x0f)
{
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=12;break;
}
}
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+3;break;
case(0Xd0): KeyValue=KeyValue+6;break;
case(0Xe0): KeyValue=KeyValue+9;break;
}
while(GPIO_KEY!=0xf0);
if(KeyValue!=c&&dis1[w]!='\0')
{b=0;w++;}
if(KeyValue<=8&&s==0)
{
if(c==12||c==15)w--;
dis1[w]=dis2[KeyValue]+b;
d=0;delay(25);d=1;delay(25);
}
else if(KeyValue<=8&&s==1)
{
if(c==12||c==15)w--;
dis1[w]=dis3[KeyValue];
d=0;delay(25);d=1;delay(25);
}
else if(KeyValue==12)
{
//当按键为12时,删除一位(退格)
if(w>0)
{
w--;
dis1[w]=' ';
}
else
{
dis1[w]=' ';
}
d1=0;delay(25);d1=1;delay(25);
}
else if(KeyValue==15)
{
//当按下15时,添加一个空格
while(w!=0)
{
w--;
dis1[w]=' ';
}
}
else if(KeyValue==9)
{
//显示数字7
q++;
s=q%2;
if(c==12||c==15)w-=2;
}
else if(KeyValue==10)
{
//显示数字8
if(s==0)
dis1[w]=' ';
else
dis1[w]='0';
}
else if(KeyValue==11)
{
//显示数字9
dis1[w]=' ';
}
else if(KeyValue==18)
{
dis1[w]=' ';
w--;
}
else if(KeyValue==21)
{
la_ba();
}
b++;
if(b==3)b=0;
c=KeyValue;
}
}
//蜂鸣器
void la_ba()
{
int i,j,t;
for(i=0;dis1[i]!='\0';i++)
{
if(dis1[i]>=65&&dis1[i]<=90)
{
d1=0;delay(25);d1=1;delay(25);
for(j=0;laba[dis1[i]-65][j]!=3;j++)
{
if(laba[dis1[i]-65][j]==1)
{
t=100;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(laba[dis1[i]-65][j]==2)
{
t=300;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(laba[dis1[i]-65][j+1]==3)
{
delay(100);
}
}
}
if(dis1[i]>=48&&dis1[i]<=57)
{
d=0;delay(25);d=1;delay(25);
for(j=0;j<5;j++)
{
if(laba[dis1[i]-22][j]==1)
{
t=100;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(laba[dis1[i]-22][j]==2)
{
t=300;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(j==4)
{
delay(100);
}
}
}
}
}
void main()
{
lcd_init();// 初始化LCD
delay(10);
while(1)
{
KeyDown();
xianshi();
}
}