main.c
/*
液晶显示计算器
对按键输入进行判断
判断是输入第几个数
输入第一个数
对第一个数进行显示(实时)
输入符号
将数字1上移,
最左侧显示符号
最右侧显示0
输入第二个数
在0处显示第二个数字
回车进行计算
回车将上一个字符整体上移
输出等于符号,输出结果
建立相应的标志位,在标志位中进行相应操作
*/
#include <reg52.h>
unsigned char step=0;
unsigned char oprt=0;
signed long num1=0;
signed long num2=0;
signed long result=0;
extern unsigned char TORH;
extern unsigned char TORL;
extern void ConfigTimer0(unsigned int ms);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);
extern unsigned char LongToString(unsigned char *str,signed long dat);
extern void KeyDriver();
extern void LcdFullClear();
extern void LcdAreaClear(unsigned char x,unsigned char y,unsigned char len);
extern void KeyScan();
void main()
{
EA=1;//开启总中断
ConfigTimer0(1);//设置1ms定时
InitLcd1602(); //初始化液晶
LcdShowStr(15,1,"0"); //初始显示0
while(1)
{
KeyDriver();
}
}
void Reset()
{
num1=0;
num2=0;
step=0;
LcdFullClear();
}
void ShowOprt(unsigned char y,unsigned char type)//对符号进行显示
{
switch(type)
{
case 0: LcdShowStr(0,y,"+"); break;
case 1: LcdShowStr(0,y,"-"); break;
case 2: LcdShowStr(0,y,"*"); break;
case 3: LcdShowStr(0,y,"/"); break;
default:break;
}
}
void NumKeyAction(unsigned char n)
{
unsigned char str[12];
unsigned char len;
if(step>1)
Reset();
else if(step==0)//输入第一个数据
{
num1=num1*10+n;
len=LongToString(str,num1);
LcdShowStr(16-len,1,str);
}
else if(step==1)//输入第二个数据
{
num2=num2*10+n;
len=LongToString(str,num2);
LcdShowStr(16-len,1,str);
}
}
void OprtKeyAction(unsigned char type)//运算符动作函数
{
unsigned char str[12];
unsigned char len;
if(step==0)
{
len=LongToString(str,num1);
LcdAreaClear(0,0,16-len);
LcdShowStr(16-len,0,str);//将数字1移到上一层
ShowOprt(1,type); //显示运算符
LcdAreaClear(1,1,14);
LcdShowStr(15,1,"0");//显示0
oprt=type;
step=1;
}
}
void GetResult()
{
unsigned char len=0;
unsigned char str[12];
if(step==1)
{
step=2;
switch(oprt)
{
case 0:result=num1+num2;break;
case 1:result=num1-num2;break;
case 2:result=num1*num2;break;
case 3:result=num1/num2;break;
default:break;
}
//显示操作
ShowOprt(0,oprt);//上移运算符
len=LongToString(str,num2);
LcdAreaClear(1,0,15-len);//清除第一行
LcdShowStr(16-len,0,str);//上移显示
len=LongToString(str,result); //结果显示
LcdAreaClear(1,1,15-len);//清除第二行
LcdShowStr(0,1,"="); //显示等号
LcdShowStr(16-len,1,str); //显示数值
}
}
void interruptimer0() interrupt 1
{
TH0=TORH;
TL0=TORL;
KeyScan();
}
lcd1602.c
/*
液晶显示相关代码
*/
#include <reg52.h>
#define LCD1602_DB P0
sbit LCD1602_RS=P1^0;
sbit LCD1602_RW=P1^1;
sbit LCD1602_E=P1^5;
void LcdWaitReady()//读状态
{
unsigned char sta;
LCD1602_DB=0XFF;//开始就进行读取
LCD1602_RS=0;
LCD1602_RW=1;
do{
LCD1602_E=1;
sta=LCD1602_DB;
LCD1602_E=0;
}while(sta&0x80);//判断高位为1,即为忙状态
}
void LcdWriteCmd(unsigned char cmd)//写入命令
{
LcdWaitReady();//写入之前需要判断状态
LCD1602_RS=0;
LCD1602_RW=0;
LCD1602_DB=cmd;
LCD1602_E=1;
LCD1602_E=0;
}
void LcdWriteDat(unsigned char dat)//写入数据
{
LcdWaitReady(); //进行状态的判断
LCD1602_RS=1;
LCD1602_RW=0;
LCD1602_DB=dat;
LCD1602_E=1;
LCD1602_E=0;
}
void LcdSetCursor(unsigned char x,unsigned char y)//进行光标位置的判断
{
unsigned char addr;
if(y)//y为1
addr=0x40+x;
else
addr=0x00+x;
LcdWriteCmd(addr|0x80);
}
void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str)//对字符进行显示
{
LcdSetCursor( x, y);
while(*str!='\0')
{
LcdWriteDat(*str++);
}
}
void InitLcd1602()//进行液晶显示的初始化
{
LcdWriteCmd(0x38);
LcdWriteCmd(0x0c);
LcdWriteCmd(0x06);//文字不动,地址加1
LcdWriteCmd(0x01);//进行清屏显示
}
void LcdAreaClear(unsigned char x,unsigned char y,unsigned char len) //清除len长度的字符
{
LcdSetCursor(x,y);
while(len--)
LcdWriteDat(' ');
}
void LcdFullClear()
{
LcdWriteCmd(0x01);
}
keyboard.c
#include <reg52.h>
sbit KEY_IN_1 = P2^4;
sbit KEY_IN_2 = P2^5;
sbit KEY_IN_3 = P2^6;
sbit KEY_IN_4 = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;
unsigned char code KeyCodeMap[4][4] = { //矩阵按键编号到标准键盘键码的映射表
{ '1', '2', '3', 0x26 }, //数字键1、数字键2、数字键3、向上键
{ '4', '5', '6', 0x25 }, //数字键4、数字键5、数字键6、向左键
{ '7', '8', '9', 0x28 }, //数字键7、数字键8、数字键9、向下键
{ '0', 0x1B, 0x0D, 0x27 } //数字键0、ESC键、 回车键、 向右键
};
unsigned char pdata KeySta[4][4] = { //全部矩阵按键的当前状态
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};
extern void Reset();
extern void GetResult();
extern void NumKeyAction(unsigned char n);
extern void OprtKeyAction(unsigned char type);
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
void KeyAction(unsigned char keycode)
{
if((keycode >= '0') && (keycode <= '9'))
{
NumKeyAction(keycode - '0');
}
else if(keycode == 0x26)//上
{
OprtKeyAction(0);
}
else if(keycode == 0x28) //下
{
OprtKeyAction(1);
}
else if(keycode == 0x25) //左
{
OprtKeyAction(2);
}
else if(keycode == 0x27) //右
{
OprtKeyAction(3);
}
else if(keycode == 0x0D) //回车
{
GetResult();
}
else if(keycode == 0x1B) //esc键
{
Reset();
LcdShowStr(15, 1, "0");
}
}
/* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */
void KeyDriver()
{
unsigned char i, j;
static unsigned char pdata backup[4][4] = { //按键值备份,保存前一次的值
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};
for (i=0; i<4; i++) //循环检测4*4的矩阵按键
{
for (j=0; j<4; j++)
{
if (backup[i][j] != KeySta[i][j]) //检测按键动作
{
if (backup[i][j] != 0) //按键按下时执行动作
{
KeyAction(KeyCodeMap[i][j]); //调用按键动作函数
}
backup[i][j] = KeySta[i][j]; //刷新前一次的备份值
}
}
}
}
/* 按键扫描函数,需在定时中断中调用,推荐调用间隔1ms */
void KeyScan()
{
unsigned char i;
static unsigned char keyout = 0; //矩阵按键扫描输出索引
static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
};
//将一行的4个按键值移入缓冲区
keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
//消抖后更新按键状态
for (i=0; i<4; i++) //每行4个按键,所以循环4次
{
if ((keybuf[keyout][i] & 0x0F) == 0x00)
{ //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
KeySta[keyout][i] = 0;
}
else if ((keybuf[keyout][i] & 0x0F) == 0x0F)
{ //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
KeySta[keyout][i] = 1;
}
}
//执行下一次的扫描输出
keyout++; //输出索引递增
keyout &= 0x03; //索引值加到4即归零
switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
{
case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
default: break;
}
}
configtimer0.c
#include <reg52.h>
unsigned char TORH=0;
unsigned char TORL=0;
void ConfigTimer0(unsigned int ms)
{
unsigned long tmp;
tmp=11059200/12*ms/1000;
tmp=65536-tmp;
TORH=(unsigned char)(tmp>>8);
TORL=(unsigned char)(tmp);
TMOD&=0XF0;
TMOD|=0X01;
TH0=TORH;
TL0=TORL;
ET0=1;
TR0=1;
}
longyostring.c
#include <reg52.h>
//主要是将数字转化为字符串
unsigned char LongToString(unsigned char *str,signed long dat)
{
unsigned char len=0;
unsigned char buf[12];
signed char i=0;
if(dat<0)
{
dat=-dat;
*str++='-';
len++;
}
while(dat)
{
buf[i++]=dat%10;
dat/=10;
}
len+=i;
while(i-->0)
{
*str++=buf[i]+'0';
}
*str='\0';
return len;
}