1602液晶显示简易计算器

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;	
}
  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值