8051 单片机 LCD1602 计算器程序代码详解
这段代码是基于 8051 单片机和 LCD1602 显示屏的简易四则运算器程序。程序通过按键输入数字和运算符,进行四则运算并将结果显示在 LCD 上。
#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit lcden=P1^1; // LCD1602 使能引脚, 允许使用 E
sbit rs=P1^0;
sbit rw=P1^2;
sbit busy=P0^7;
uchar mode=0; // 记录状态按钮状态
char i,j,temp,num,num_1;
long a,b,c; // a, 第一个数 b, 第二个数 c, 输出数
float a_c,b_c;
uchar flag,fuhao; // flag 表示是否有运算符,fuhao 表示当前输入的是哪个运算符
// flag=1 表示有运算符下,flag=0 表示没有运算符下
// fuhao=1 表示加法,fuhao=2 表示减法,fuhao=3 表示乘法,fuhao=4 表示除法
uchar code table[]={// 计算数字键盘输入数组
7,8,9,0,
4,5,6,0,
1,2,3,0,
0,0,0,0
};
uchar code table1[]={ // 进行后续处理显示按钮组合的数组 lcd
7,8,9,0x2f-0x30, // 7,8,9,/
4,5,6,0x2a-0x30, // 4,5,6,*
1,2,3,0x2d-0x30, // 1,2,3,-
0x01-0x30,0,0x3d-0x30,0x2b-0x30 // C,0,=,+
};
void delay(uchar z) // 延时函数
{
uchar y;
for(z;z>0;z--)
for(y=0;y<110;y++);
}
void write_com(uchar com) // 写命令函数
{
rs=0;
P0=com; // 将 com 命令赋给 P0 端口
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_date(uchar date) // 写数据函数
{
rs=1;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void init() // 初始化
{
num=-1;
lcden=1; // 允许控制为高电平
rw=0;
write_com(0x38); // 8 位,2 行
delay(5);
write_com(0x38); // 8 位,2 行
delay(5);
write_com(0x0c); // 显示开,光标禁止,不闪烁
delay(1);
write_com(0x06); // 光标右移模式不左移
delay(1);
write_com(0x80); // 设置显示地址
delay(1);
write_com(0x01); // 清屏
num_1=0;
i=0; j=0;
a=0; // 第一个数与运算的数
b=0; // 第二个数与运算的数
c=0;
flag=0; // flag 表示是否有运算符
fuhao=0; // fuhao 表示当前输入的是哪个运算符
}
void keyscan() // 按键扫描程序
{
P2=0xfe;//1111 1110 第一行为低电平
if(P2!=0xfe)
{
delay(20);// 延时 20ms
if(P2!=0xfe)
{ // 1101 1110 & 1111 0000
temp=P2&0xf0; // 取最低位,只留高位
switch(temp)
{
// 0xe0=1110 0000,针对第 7 位按键
case 0xe0:num=0; break; // 7
case 0xd0:num=1; break; // 8
case 0xb0:num=2; break; // 9
case 0x70:num=3; break; // /
}
}
while(P2!=0xfe); // 1111 1110
if(num==0||num==1||num==2)// 如果按下的是'7','8'或'9'
{
if(j!=0){write_com(0x01); j=0; }
if(flag==0)// 没有按下运算符按钮
{ a=a*10+table[num]; } // 将下面的数字保存到 a 中
else// 如果按下了运算符按钮
{ b=b*10+table[num]; }// 将下面的数字保存到 b 中
}
else// 如果按下的是'/' 除法
{
flag=1; // 标记已经按下运算符按钮
fuhao=4;// 4 表示除号
}
i=table1[num]; // 将数据显示到上方显示区
write_date(0x30+i);// 显示数据或运算符
}
P2=0xfd; // 1111 1101
if(P2!=0xfd)
{
delay(20);
if(P2!=0xfd){ temp=P2&0xf0;
switch(temp)
{
case 0xe0:num=4; break; // 4
case 0xd0:num=5; break; // 5
case 0xb0:num=6; break; // 6
case 0x70:num=7; break; // *
}
}
while(P2!=0xfd);// 等待松开按键
if(num==4||num==5||num==6)// 如果按下的是'4','5'或'6'
{
if(j!=0){ write_com(0x01); j=0; }
if(flag==0)// 没有按下运算符按钮
{ a=a*10+table[num]; }
else// 如果按下了运算符按钮
{ b=b*10+table[num]; }
}
else// 如果按下的是'*'
{
flag=1;
fuhao=3;// 3 表示乘号
}
i=table1[num]; // 将数据显示到上方显示区
write_date(0x30+i);// 显示数据或运算符
}
P2=0xfb; // 1111 1011
if(P2!=0xfb)
{
delay(20);
if(P2!=0xfb)
{
temp=P2&0xf0;
switch(temp)
{
case 0xe0:num=8; break; // 1
case 0xd0:num=9; break; // 2
case 0xb0:num=10; break; // 3
case 0x70:num=11; break; // -
}
}
while(P2!=0xfb);
if(num==8||num==9||num==10)// 如果按下的是'1','2'或'3'
{
if(j!=0){ write_com(0x01); j=0; }
if(flag==0)// 没有按下运算符按钮
{ a=a*10+table[num]; }
else// 如果按下了运算符按钮
{ b=b*10+table[num]; }
}
else if(num==11)// 如果按下的是'-'
{
flag=1;
fuhao=2;// 2 表示减号
}
i=table1[num]; // 将数据显示到上方显示区
write_date(0x30+i);// 显示数据或运算符
}
P2=0xf7; // 1111 0111
if(P2!=0xf7){
delay(20);
if(P2!=0xf7)
{
temp=P2&0xf0;
switch(temp)
{
case 0xe0:num=12; break; // 清 0 按钮
case 0xd0:num=13; break; // 数字 0 按钮
case 0xb0:num=14; break; // 等于按钮
case 0x70:num=15; break; // +
}
}
while(P2!=0xf7);
switch(num)
{
case 12:{
if(mode==0){
write_com(0x0f);a=0;b=0;flag=0;fuhao=0;mode++;
}
if(mode!=0){
write_com(0x01);a=0;b=0;flag=0;fuhao=0;mode++;write_com(0x0f);
}
}// 如果按下的是"清屏"
break;
case 13:{
if(flag==0)// 没有按下运算符按钮
{ a=a*10; write_date(0x30); P2=0; }
else if(flag>=1)// 如果按下了运算符按钮
{ b=b*10; write_date(0x30); }
}
break;
case 14:{
j=1; // 如果按下的是等号,根据运算符不同进行不同的处理
write_com(0x0c); // 光标禁止
if(fuhao==1) // 加法运算
{
write_com(0x80+0x4f);// 如果按下的是等号,先显示下方数据
write_com(0x04); // 设置从后向前显示数据,每显示一次,光标前进一个位置
c=a+b; // 进行加法运算
while(c!=0){write_date(0x30+c%10); c=c/10; }
write_date(0x3d); // 再显示"="
a=0;b=0;flag=0;fuhao=0;
}
else if(fuhao==2) // 减法运算
{
write_com(0x80+0x4f);// 这里设置从后向前显示数据
write_com(0x04); // 设置从后向前显示数据,每显示一次,光标前进一个位置
if(a-b>0)
c=a-b;
else
c=b-a;
while(c!=0) {
write_date(0x30+c%10);
c=c/10;
}
if(a-b<0)
write_date(0x2d);
if(a==b)
write_date(0x30+0); // 当两个数相等时,输出结果 0
write_date(0x3d); // 再显示"="
a=0;b=0;flag=0;fuhao=0;
}
else if(fuhao==3) // 乘法运算
{
write_com(0x80+0x4f);
write_com(0x04);
c=a*b;
while(c!=0)
{
write_date(0x30+c%10); c=c/10;
}
write_date(0x3d);
a=0;b=0;flag=0;fuhao=0;
}
else if(fuhao==4)// 除法运算
{
write_com(0x80+0x4f);
write_com(0x04);
i=0;
if(b!=0)
{
c=(long)(((float)a/b)*1000);
while(c!=0)
{
write_date(0x30+c%10);
c=c/10;
i++;
if(i==3) write_date(0x2e);
}
if(a/b<=0)
{
if(i<=2)
{
if(i==1) write_date(0x30);
write_date(0x2e); // .
write_date(0x30);
}
write_date(0x30); //
}
write_date(0x3d);
a=0;b=0;flag=0;fuhao=0;
}
else
{
write_date('!');write_date('R');write_date('O');
write_date('R');write_date('R');write_date('E');
}
}
break;
case 15:{
write_date(0x30+table1[num]);flag=1;fuhao=1;}
break; // 加号 设置加号标志 fuhao=1;
}
}//P2!=0xf7
}
main()
{
init(); // 初始化
while(1)
{
keyscan();// 按键扫描
}
}
代码功能解析
该程序代码实现了一个简易的计算器,主要功能包括:
- 数字输入: 通过按键输入数字,程序将数字保存到对应变量中。
- 运算符输入: 通过按键输入运算符,程序记录当前运算符。
- 计算: 当用户按下“=”按键时,程序根据当前运算符进行相应的计算。
- 结果显示: 程序将计算结果显示在 LCD1602 上。
变量定义
代码中定义了以下变量:
- lcden, rs, rw, busy: 分别对应 LCD 的使能引脚、RS 引脚、RW 引脚和 BUSY 引脚,用于控制 LCD 的操作。
- mode: 记录状态按钮的状态。
- i, j, temp, num, num_1: 用于临时存储数据或进行运算。
- a, b, c: 分别用于存储第一个数、第二个数和计算结果。
- a_c, b_c: 用于存储浮点数,但程序中未实际使用。
- flag: 表示是否已有运算符输入。
- fuhao: 表示当前输入的运算符类型。
- table: 存储数字键盘输入的数组。
- table1: 存储显示按钮组合的数组,用于在 LCD 上显示相应的符号。
函数解析
代码中定义了以下函数:
- delay(uchar z): 延时函数,用于控制程序执行速度。
- write_com(uchar com): 写命令函数,用于向 LCD 发送命令。
- write_date(uchar date): 写数据函数,用于向 LCD 发送数据。
- init(): 初始化函数,用于初始化 LCD 和程序变量。
- keyscan(): 按键扫描函数,用于读取按键状态并进行相应的处理。
- main(): 主函数,程序的入口点,循环调用 keyscan 函数进行按键扫描处理。
代码分析
代码中的 keyscan 函数主要负责处理按键扫描,进行数字输入、运算符输入、计算和结果显示等操作。代码中还使用了 switch 语句和 while 循环等语句结构,实现程序的逻辑控制。
总结
该代码通过简洁的代码结构和清晰的逻辑,实现了一个功能完备的四则运算器程序。开发者可以通过分析代码,学习如何使用 8051 单片机和 LCD1602 显示屏,并掌握基本的程序设计技巧。
原文地址: https://www.cveoy.top/t/topic/bzN9 著作权归作者所有。请勿转载和采集!