标题:
51单片机制作的多位连续四则运算的计算器 Proteus仿真程序
[打印本页]
作者:
qingrao
时间:
2019-12-23 21:23
标题:
51单片机制作的多位连续四则运算的计算器 Proteus仿真程序
基于单片机制作的多位连续四则运算的计算器
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
#include<reg52.h>//52单片机头文件
#include<math.h>//要用到数学计算公式,所以调用
#include <intrins.h>//移位
#define key P2 //定义矩阵键盘的I/O口
#define GPIO_LCD P0//定义LCD1602 数据/命令的输入端
unsigned char number[20];//用来储存我们所按键按下去的字符和数字
unsigned char add=0;//是否按过+号
unsigned char subtract=0;//是否按过-号
unsigned char ride=0;//是否按过*号
unsigned char divide=0;//是否按过/号
unsigned char eliminate=0;//是否按过清除键
unsigned char minus=0;//是否计算的数据需要添加负号
unsigned char decimals=0;//是否计算的数据需要小数点
unsigned char equal=0;//是否按下等号键
sbit LCD_RS =P3^4;//定义LCD的模式选择,1为写数据,0为写命令
sbit LCD_RW =P3^5;//定义LCD功能 1是读,0是写
sbit LCD_E =P3^6;//定义LCD使能端
unsigned long a=0,b=0;//用于储存我们所要运算的数据
unsigned char i;//定义一个全局变量
unsigned char LCD_Wait(void)//判忙函数
{
LCD_RS=0;
LCD_RW=1;
_nop_();
LCD_E=1;
_nop_();
LCD_E=0;
return GPIO_LCD;
}
void delay(void) //延时函数
{
unsigned char x,z;
for(z=19;z>0;z--)
for(x=130;x>0;x--);
}
void LCD_Write_Com(unsigned char com)//LCD1602写命令函数
{
LCD_RS =0;
LCD_RW =0;
GPIO_LCD=com;
delay() ;
LCD_E=1;
delay() ;
LCD_E=0;
delay() ;
}
void LCD_Write_Date( unsigned char input)//LCD1602写数据函数
{
LCD_RS=1;
LCD_RW=0; ;
LCD_E=0;
_nop_();
GPIO_LCD =input;
_nop_();
LCD_E=1;
_nop_();
LCD_E=0;
_nop_();
LCD_Wait();
}
void LCD_Initial()//LCD1602初始化函数
{
delay();
LCD_Write_Com (0x38);
delay() ;
LCD_Write_Com (0x38);
delay() ;
LCD_Write_Com (0x08);
delay() ;
LCD_Write_Com (0x0c);
delay() ;
LCD_Write_Com (0x06);
delay() ;
LCD_Write_Com (0x01);
delay() ;
}
以上函数是LCD1602的模块化函数库,如果看不懂,需要先学习一下LCD1602.如果懒得学的话,可以直接用这个函数库,前提是上面定义的变量要整体一一对应,各个端口的引脚也要和你的实际端口一一对应
unsigned long calculate()//计算数据模块
{
unsigned long value=0;
if(add)//如果我们按键按下了加号,那么在计算时进入这个加运算
{
value=a+b;
}
if(subtract) //如果我们按键按下了减号,那么在计算时进入这个减运算
{
if(a>=b)
value=a-b;
else
{
value=b-a;
minus=1;//说明后面的数大于前面的额数,将其标志为一,在输出结果是,可以利用它判断是否输出负号
}
}
if(ride)//乘法运算
{
value=a*b;
}
if(divide)//除法运算
{
value=(unsigned long)(((float)a/b)*1000);//因为此计算器是,保留小数点后三位,所以,两数相除,1/2=0.5,那么通过这个,可以让其先等于200,方便我们后续的结果处理
decimals=1;//标示结果已经<0,最后结果要出现小数点,
}
return value;//返回计算的结果
}
void result()
{
unsigned char f=0;//标志结果需要保留什么数
unsigned long value;
if(equal==1)
{
value=calculate();//将上面计算算出来的值赋值给这个函数中的value
LCD_Write_Com (0x40);//写LCD1602的命令,使得结果数据显示在第二排
delay();
LCD_Write_Com (0xcf); //从第二排最后一个位置依次向左写数据
delay();
LCD_Write_Com (0x04);//光标从第二排最后一个数据向左移动
delay();
do
{
LCD_Write_Date(0x30+value%10);//0x30是LCD字符库中数字0的代号,例如我们想写入 2这个结果,根据前面计算函数,计算函数已经将2变成2000,所以这里是让其变回来从后往前依次写数据到LCD1602上,
delay();
f++;//value的位数如果计算结果是0.2,则通过计算函数变成200,那么这时的f就会被加到3,
if(decimals&&f==3)//接上如果f被加到三
LCD_Write_Date(0x2e);//就在LCD1602上显示小数点
delay();
value/=10;//如果经过计算函数后是2000,则经过一次这个 value减少一位(减少的哪一位的数据已经写入LCD1602中了)
delay();
}
while(value);//当value 被用尽后跳出循环
if(decimals&&f<=3)//decimals是标志是否进行的是除法运算
{
if(f==3)
{
LCD_Write_Date(0x30);//如果是三,因为前面程序已经在对应位置加了小数点了,这时我们住需要再在前面加一个0就可以了,如果没有这条语句,0.5 的显示就是.5
}
else
{
while(3-f)//当f<3时进入这程序
{LCD_Write_Date(0x30);
f++;
}
LCD_Write_Date(0x2e);//写小数点
delay();
LCD_Write_Date(0x30);//写数据0
}
}
if(minus)//如果有负号标志
LCD_Write_Date(0x2d);//在LCD1602上显示负号
add=0;
subtract=0;
ride=0;
divide=0;
equal=0;
decimals=0;
minus=0;
eliminate=0;
}
}
void main()
{
int j,k=0,g;
i=0;
LCD_Initial();//初始化LCD1602
j=0;
while(1)
{
P2=0xfe;//扫描第一行是否有按键按下
while((P2&0xf0)!= 0xf0)
{
delay(); //延时消抖
while((P2&0xf0)!=0xf0) //确认按下
{
switch(key) //锁定按的是哪一个键
{
case 0xee: number[i]= 7; i++;k=1;break;//k=1表明按下的是数字键
case 0xde: number[i]=8;i++;k=1; break;
case 0xbe: number[i] =9; i++;k=1;break;
case 0x7e: number[i]= '/';divide++;i++;break;//计算对应的表示功能键的变量按键次数
default: number[i] = '#';
}
while((P2& 0xf0) != 0xf0) ;//扫描第二行
}
}
P2= 0xfd;
while((P2&0xf0) != 0xf0)
{
delay();
while((P2& 0xf0) != 0xf0)
{
switch(key)
{
case 0xed: number[i]= 4;i++;k=1; break;
case 0xdd: number[i] = 5; i++;k=1;break;
case 0xbd: number[i] = 6;i++;k=1; break;
case 0x7d: number[i] = '*';ride++;i++;break;
default: number[i] = '#';
}
while((P2&0xf0)!= 0xf0)
;
}
}
P2= 0xfb;//扫描第三行
while((P2& 0xf0) != 0xf0)
{
delay();
while((P2& 0xf0) != 0xf0)
{
switch(key)
{
case 0xeb: number[i] =1; i++;k=1;break;
case 0xdb: number[i]= 2; i++;k=1;break;
case 0xbb: number[i] = 3; i++;k=1;break;
case 0x7b: number[i]= '-';subtract++;i++;break;
default: number[i] = '#';
}
while((P2&0xf0)!= 0xf0);
}
}
P2= 0xf7;//扫描第四行
while((P2&0xf0)!=0xf0)
{
delay();
while((P2&0xf0)!=0xf0)
{
switch(P2)
{
case 0xe7: number[i]= 'eliminate=1;i++; break;
case 0xd7: number[i]=0;i++;k=1; break;
case 0xb7: number[i]= '=';i++;equal++;break;
case 0x77: number[i]= '+';add++;i++;break;
default: number[i] = '#';
}
while((P2&0xf0)!= 0xf0);
}
}
if(k==1)//如果有数字键按下,进入此程序
{
if(add+subtract+ride+divide==1)//如果有第一个加减乘除键被按下则进入负号符号键后面的数据存储,如1+2 这里的b存 的是2
{
b=b*10+number[i-1];
g=calculate();
}
if(add+subtract+ride+divide==2)//如果2+2+1,这里面的a=2+2, b=1,因为g村存储了前面只有一个加号时的value
{
a=g;
b=0;
b=b*10+number[i-1];
}
if(add+subtract+ride+divide==3)//如2+2+2+3,这里的a=2+2+2,b=3,同理往下
{
a=g;
b=0;
b=b*10+number[i-1];
}
if(add+subtract+ride+divide==4)
{
a=g;
b=0;
b=b*10+number[i-1];
}
if(add+subtract+ride+divide==0)
{
a=a*10+number[i-1];
}
g=calculate();
k=0;
}
LCD_Write_Com (0x80); //将要输入的数据放在首行
delay();
for(j=0;j<i;j++)
{
if(number[j]=='+'||number[j]=='||number[j]=='-'||number[j]=='*'||number[j]=='/'||number[j]=='=')
LCD_Write_Date( number[j]);//写符号位
else
LCD_Write_Date( number[j]+0x30);//写数据位
delay();
}
if(eliminate==1)//一旦按下清除键,LCD1602内数据会自动清零,可以反复输入
{
LCD_Initial();
eliminate=0;
i=0;
a=0;
b=0;
}
result(); //调用结果函数
}
}
复制代码
51hei.png
(7.29 KB, 下载次数: 73)
下载附件
2019-12-24 13:05 上传
全部资料51hei下载地址:
简易计算器.rar
(375.26 KB, 下载次数: 125)
2019-12-23 21:20 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
ykxdsy
时间:
2019-12-31 13:06
能不能实现连乘啊
作者:
2667498081
时间:
2021-6-4 08:58
里面能进行小数的运算吗
作者:
时空来客
时间:
2021-7-10 08:40
计算的都是错的,你还直接超过来了?卧槽
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1