protues中有KEYPAD-SMALLCALC直接就是4*4的矩阵:
做完之后才发现了,当时不知道,自己画了一个4*4的矩阵键盘
1.protues仿真图
2.源程序
注释我写的很详细
#include "reg52.h"
typedef unsigned int uint; //定于无符号int
typedef unsigned char uchar; //定义无符号char
sbit rw=P2^5;
sbit rs=P2^6;
sbit e=P2^7;
uint fuhao,flag,k,i,j,num;
uchar disp[]=" ERROR!";//除数为0时,显示
uchar wel[]=" Welcome!";//初始化时显示
long a,b,c,x;
void delay(long i) //延时
{
while(i--);
}
void Delay1000ms() //@11.0592MHz STC-ISP软件延时计算器生成延时一秒函数
{
unsigned char i, j, k;
i = 43;
j = 6;
k = 203;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void lcdwrc(uint c) //设置LCD写命令
{
delay(1000);
rs=0;
rw=0;
e=0;
P0=c;
e=1;
delay(1000);
e=0;
}
void lcdwrd(uint dat) //设置LCD写数据
{
delay(1000);
rs=1;
rw=0;
e=0;
P0=dat;
e=1;
delay(1000);
e=0;
rs=0;
}
void lcdinit() //初始化LCD
{
delay(1500);
lcdwrc(0x38);
delay(500);
lcdwrc(0x38);
delay(500);
lcdwrc(0x38);
delay(500);
lcdwrc(0x38); //功能设定指令
lcdwrc(0x08); //
lcdwrc(0x01); //清屏
lcdwrc(0x06); //设置LCD显示
lcdwrc(0x0c); //显示开关控制指令
num=0;
fuhao=0;
flag=0;
a=0;
b=0;
c=0;
x=0;
k=0;
j=0;
}
void KeyDown() //按键函数
{
k=0;
P1=0x0f; //后列前行 列都为高电平1,行都为低电平0
if(P1!=0x0f)//有按键被按下
{
delay(1000);
if(P1!=0x0f)//延时再次判断,软件消抖
{
P1=0x0f;//列都为高电平1,行都为低电平0
switch(P1)
{
case 0x07: //0000 0111 第一列有按键被按下
{
P1=0xf0;//列都为低电平0,行都为高电平1
switch(P1)//判断哪一行的按键被按下
{
case 0x70: num = 1;k=7;break; //0111 0000第一列第一行
case 0xb0: num = 5;k=4;break; //1011 0000第一列第二行
case 0xd0: num = 9;k=1;break; //1101 0000第一列第三行
case 0xe0: num = 13;break; //1110 0000第一列第四行
}
if(num!=13)//被按下的按键不是清零键
{
if(fuhao==0)//fuhao==0,表示第一个数a,fuhao==1,表示第二个数b
a=a*10+k;
else
b=b*10+k;
}
lcdwrd(0x30+k);//显示按下的数,0x3y:显示y
if(num==13)//按下的按键是清零键
{
lcdwrc(0x01); //清屏指令
lcdinit();//重新初始化LCD1602
}
}
while(P1!=0xf0);break;//当有按键被按下时,结束此次判断,进行下一次判断
case 0x0b: //0000 1011 第二列有按键被按下
{
P1=0xf0;//列都为低电平0,行都为高电平1
switch(P1)//判断哪一行有按键被按下
{
case 0x70: k=8;break;//第二列第一行
case 0xb0: k=5;break;//第二列第二行
case 0xd0: k=2;break;//第二列第三行
case 0xe0: k=0;break;//第二列第四行
}
if(fuhao==0)
a=a*10+k;
else
b=b*10+k;
lcdwrd(0x30+k);
}
while(P1!=0xf0);break;
case 0x0d: //0000 1101 第三列有按键被按下
{
P1=0xf0;
switch(P1)
{
case 0x70: num=3;k=9;break;//第三列第一行
case 0xb0: num=7;k=6;break;//第三列第二行
case 0xd0: num=11;k=3;break;//第三列第三行
case 0xe0: num=15;break;//第三列第四行
}
if(num!=15)
{
if(fuhao==0)
a=a*10+k;
else
b=b*10+k;
lcdwrd(0x30+k);
}
if(num==15)//按下的键为=键
{
switch(flag)//判断进行哪种运算
{
case 1://+
{
c=a+b;//计算结果
lcdwrc(0x4f+0x80);//光标置于第二行末尾
lcdwrc(0x04);//设置显示方式:显示后指针减一
if(c==0)//若结果为0
lcdwrd(0x30);//显示0
while(c!=0)
{
lcdwrd(0x30+c%10);//从最后一位开始显示
c=c/10;
}
lcdwrd(0x3d);//显示=
}
break;
case 2://-
{
if(a>b)
c=a-b;
else
c=b-a;//计算两数相减的绝对值
lcdwrc(0x4f+0x80);//将光标置于第二行末尾
lcdwrc(0x04);//设置显示方式:显示后指针减一
if(c==0)//若结果为零
lcdwrd(0x30);//显示0
while(c!=0)
{
lcdwrd(0x30+c%10);//从最后一位开始显示
c=c/10;
}
if(a<b)//若结果为负数
lcdwrd(0x2d);//ROM字符库-
lcdwrd(0x3d);//显示=
}
break;
case 3://*
{
c=a*b; //计算结果
lcdwrc(0x4f+0x80);//光标置于第二行末尾
lcdwrc(0x04);//显示设置:显示后指针减一
if(c==0)//若结果为0
lcdwrd(0x30);//显示0
while(c!=0)
{
lcdwrd(0x30+c%10); //从最后一位开始显示
c=c/10;
}
lcdwrd(0x3d); //显示=
}
break;
case 4: //÷
{
if(b==0)//若除数为0
{
lcdwrc(0x01);//清屏
for(j=0;j<11;j++)
{
lcdwrd(disp[j]);//显示语句:ERROR!
}
delay(5000);//延时
lcdwrc(0x01);//初始化LCD1602
delay(5000);
}
else
{ //将结果放大10000倍
c=(long)(((float)a/b)*10000);//例36/6=6.0000 60000
x=c;
lcdwrc(0x4f+0x80);//光标第二行最后
lcdwrc(0x04);//I/D==0
while(c!=0) //一位一位显示
{
k++;
lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置 //0 00 000 0000
c=c/10;//取前面的结果数据
if(x>0&&x<=9)
{
if(k==1)//只有小数点后最后一位
{
lcdwrd(0x30);//0
lcdwrd(0x30);//0
lcdwrd(0x30);//0
lcdwrd(0x2e);//.
k=0;
}
}
if(x>9&&x<=99)
{
if(k==2)//只有小数点后最后两位
{
lcdwrd(0x30);//0
lcdwrd(0x30);//0
lcdwrd(0x2e);//.
k=0;
}
}
if(x>99&&x<=999)
{
if(k==3)//只有小数点后最后三位
{
lcdwrd(0x30);//0
lcdwrd(0x2e);//.
k=0;
}
}
else if(k==4)//小数点后四位都有
{
lcdwrd(0x2e);//.
k=0;
}
}
if(x<10000)
lcdwrd(0x30);//若结果小于1,在各位补充0
lcdwrd(0x3d);//显示=
}
}
break;
}
}
}
while(P1!=0xf0);
break;
case 0x0e: //0000 1110
{
fuhao=1; //有符号键被按下
P1=0xf0; //1111 0000
switch(P1)
{
case 0x70:/*0111 0000*/flag=4;lcdwrd(0xfd);break;//除号第四列第一行
case 0xb0:/*1011 0000*/flag=3;lcdwrd(0x2a);break;//* 第四列第二行
case 0xd0:/*1101 0000*/flag=2;lcdwrd(0x2d);break;//- 第四列第三行
case 0xe0:/*1110 0000*/flag=1;lcdwrd(0x2b);break;//+ 第四列第四行
}
}
while(P1!=0xf0);break;
}
}
}
}
void main()
{
uint x;
lcdinit();//LCD1602初始化
for(x=0;x<12;x++)
lcdwrd(wel[x]);//显示欢迎语句:Welcome
Delay1000ms();//STC-ISP软件延时计算器1s延时函数
lcdwrc(0x01);//LCd1602清屏
while(1)
KeyDown();//按键判断函数
}