单片机计算器资料.docx
《单片机计算器资料.docx》由会员分享,可在线阅读,更多相关《单片机计算器资料.docx(22页珍藏版)》请在冰豆网上搜索。
单片机计算器资料
#include"reg52.h"
#include"math.h"
//#include"lcd1602_8.h"
#defineuintunsignedint
#defineucharunsignedchar
uinttemp,num;//键盘扫描数值
ucharkeynum1=0,keynum2=0,sign=0,i=0,j=0;//按键计数,符号标示
ucharnum1[8]={0},num2[8]={0};//按键存储数组
floatans1=0,ans2=0,ans=0,point=0;//运算数据
bitconflag=0;//继续运算标志位
bitnewcalc=0;//新运算标志位
bitac=0;//清零标志,1为清零
bitbeepflag=0;//蜂鸣器标志位
bitsqrtflag1=0;//开方1标志位
bitsqrtflag2=0;//开方2标志位
sbitkeybeep=P3^3;//蜂鸣器开关按键
sbitbeep=P2^7;//蜂鸣器控制口
sbitkeysqrt=P3^4;//开方按键
sbitkeypow=P3^5;//任意次方按键
sbitLCDRS=P2^0;
sbitLCDRW=P2^1;
sbitLCDEN=P2^2;
ucharkeyscan();
voidmaininit(void);
//附4:
LCD1602显示程序
//#include
//#include"lcd1602_8.h"
//#include
//延时1ms程序
voiddelayms(uintx)//12M延时1ms
{
unsignedintTempMS=x*110;
while(TempMS--);
}
//写命令
voidlcdwrite_com(uchari)
{
P0=i;
LCDRS=0;
LCDRW=0;
LCDEN=0;
delayms
(1);
LCDEN=1;
}
//写数据
voidlcdwrite_data(uchari)
{
P0=i;
LCDRS=1;
LCDRW=0;
LCDEN=0;
delayms
(1);
LCDEN=1;
}
//写字符串
voidlcdwrite_string(uchar*s)
{
while(*s)
{
lcdwrite_data(*s);
s++;
}
}
//设置lcd光标值
voidlcd_setxy(ucharx,uchary)
{
ucharaddress;
y&=0x0f;
if(!
x)
address=0x80+y;//0在第一行
else
address=0xc0+y;//1在第二行
lcdwrite_com(address);
}
//显示1位数字
voidlcdwrite_num1(uintn)
{
lcdwrite_data(n+48);
}
//显示任意位数字
voidlcdwrite_num(longn)
{
ucharlength=0,j,a[8]={0,0,0,0,0,0,0,0};
longnx;
if(n==0)
{
lcdwrite_data('0');
return;
}
if(n<0)
{
lcdwrite_data('-');
n=0-n;
}
nx=n;
for(j=0;j<8;j++)
{
if(nx>=1)
length++;
nx/=10;
}
nx=n;
for(;length>0;length--)
{
a[length-1]=nx%10+0x30;
nx/=10;
}
lcdwrite_string(a);
}
//显示7位小数
voidlcdwrite_float(floatn)
{
uchari=0;
uintj=0;
longnxtemp;
if(n==0)
{
lcdwrite_data('0');
return;
}
if(n<0)
{
lcdwrite_data('-');
n=0-n;
}
nxtemp=n;
n=n;//+0.000002;
lcdwrite_num(nxtemp);
if((n-nxtemp)>0.000009)
{
lcdwrite_data('.');
n=(n-nxtemp)*10000000;
//n=n-1;
nxtemp=n;
//if(nxtemp%10!
=0)
lcdwrite_data(nxtemp/10000000+0x30);//显示第7位小数
if((nxtemp%1000000%100000%10000%1000%100/10!
=0)||(nxtemp%1000000%100000%10000%1000/100!
=0)||(nxtemp%1000000%100000%10000/1000!
=0)||(nxtemp%1000000%100000/10000!
=0)||(nxtemp%1000000/100000!
=0))
lcdwrite_data(nxtemp%1000000/100000+0x30);//显示第6位小数
if((nxtemp%1000000%100000%10000%1000%100/10!
=0)||(nxtemp%1000000%100000%10000%1000/100!
=0)||(nxtemp%1000000%100000%10000/1000!
=0)||(nxtemp%1000000%100000/10000!
=0))
lcdwrite_data(nxtemp%1000000%100000/10000+0x30);//显示第5位小数
if((nxtemp%1000000%100000%10000%1000%100/10!
=0)||(nxtemp%1000000%100000%10000%1000/100!
=0)||(nxtemp%1000000%100000%10000/1000!
=0))
lcdwrite_data(nxtemp%1000000%100000%10000/1000+0x30);//显示第4位小数
if((nxtemp%1000000%100000%10000%1000%100/10!
=0)||(nxtemp%1000000%100000%10000%1000/100!
=0))
lcdwrite_data(nxtemp%1000000%100000%10000%1000/100+0x30);//显示第3位小数
if(nxtemp%1000000%100000%10000%1000%100/10!
=0)
lcdwrite_data(nxtemp%1000000%100000%10000%1000%100/10+0x30);//显示第2位小数
//lcdwrite_data(nxtemp%10+0x30);//显示第1位小数
}
elsereturn;
}
//初始化液晶
voidlcd_init(void)
{
lcdwrite_com(0x01);//显示清屏
lcdwrite_com(0x01);//显示清屏
lcdwrite_com(0x38);//设置成1602显示
delayms(5);
lcdwrite_com(0x38);//设置成1602显示
delayms(5);
lcdwrite_com(0x38);//设置成1602显示
delayms(5);
//lcdwrite_com(0x0f);//开显示0x0e显示开,光标开
lcdwrite_com(0x0c);//显示开
lcdwrite_com(0x06);//设置光标移动方向增量方式,并指定显示不移动。
//lcdwrite_com(0x05);//设置光标移动方向减量方式,并指定显示移动。
(光标不移动而整个屏幕移动)
//lcdwrite_com(0x07);//(当写一个字符,整屏显示左移)
}
//初始化程序
voidmaininit(void)
{
delayms(100);//等待液晶初始化
lcd_init();
lcd_setxy(0,0);
lcdwrite_data('0');
lcd_setxy(0,0);
IT0=1;//下降沿触发
EX0=1;//开外部中断0
IT1=1;//下降沿触发
EX1=1;//开外部中断1
EA=1;//开全局中断
}
//清零中断程序
voidEX0_int()interrupt0
{
if(beepflag==1)//若开声音则每一次按键均鸣叫
{
beep=0;
delayms(100);
beep=1;
}
lcdwrite_com(0x01);//显示清屏
lcd_setxy(0,0);
lcdwrite_data('0');
lcd_setxy(0,0);
num='N';//数字初始化
keynum1=0,keynum2=0,sign=0;
ans1=0,ans2=0,ans=0,point=0;
conflag=0,newcalc=0;
ac=1;
}
//声音中断程序
voidEX1_int()interrupt2
{
beepflag=~beepflag;
if(beepflag==1)//若开声音则每一次按键均鸣叫
{
beep=0;
delayms(100);
beep=1;
}
}
//按键扫描程序
ucharkeyscan()
{
num='N';//若没有按下任何按键,则返回‘N’
P1=0xfe;//扫描第一行
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)//扫描列
{
delayms(10);
temp=P1;
switch(temp)
{
case0xee:
num='+';
break;
case0xde:
num='=';
break;
case0xbe:
num='.';
break;
case0x7e:
num=0;
break;
}
while(temp!
=0xf0)//等待松手
{
temp=P1;
temp=temp&0xf0;
}
}
P1=0xfd;//扫描第二行
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)//扫描列
{
delayms(10);
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xed:
num='-';
break;
case0xdd:
num=3;
break;
case0xbd:
num=2;
break;
case0x7d:
num=1;
break;
}
while(temp!
=0xf0)
{
temp=P1;
temp=temp&0xf0;//等待松手
}
}
}
P1=0xfb;//扫描第三行
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)//扫描列
{
delayms(10);
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xeb:
num='*';
break;
case0xdb:
num=6;
break;
case0xbb:
num=5;
break;
case0x7b:
num=4;
break;
}
while(temp!
=0xf0)//等待松手
{
temp=P1;
temp=temp&0xf0;
}
}
}
P1=0xf7;//扫描第四行
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)//扫描列
{
delayms(10);
temp=P1;
temp=temp&0xf0;
while(temp!
=0xf0)
{
temp=P1;
switch(temp)
{
case0xe7:
num='/';
break;
case0xd7:
num=9;
break;
case0xb7:
num=8;
break;
case0x77:
num=7;
break;
}
while(temp!
=0xf0)
{
temp=P1;
temp=temp&0xf0;//等待松手
}
}
}
if(keypow==0)
{
delayms(5);
if(keypow==0)
{
//powflag=1;
num='^';
}
while(keypow==0);//扫描多次方按键
delayms(5);
while(keypow==0);
}
if(beepflag==1&&num!
='N')//若开声音则每一次按键均鸣叫
{
beep=0;
delayms(100);
beep=1;
}
returnnum;
}
//主程序
voidmain(void)
{
maininit();//初始化
while
(1)//整个系统大循环,让计数器一直处于工作状态
{
while
(1)//第一运算数扫描
{
if(ac==1)break;//若清零则退出输入
if((keyscan()!
='N')&&((num>=0&&num<=9)||num=='.'))//记录按下的数字
{
if(newcalc==1)//新一次运算开始
{
lcdwrite_com(0x01);//清屏
newcalc=0;
lcd_setxy(0,0);
}
if(keynum1<=7)//限制输入位数
{
if(num=='.')
{
lcdwrite_data('.');//显示小数点
}
else
lcdwrite_num1(num);
num1[keynum1]=num;
keynum1++;
}
}
elseif(num=='+'||num=='-'||num=='*'||num=='/'||num=='='||num=='^'||keysqrt==0)
{
if(keynum1==0&&num1[0]==0)//若直接输入运算符而没有输入数字则执行连续运算
{
here:
ans1=ans;
sign=num;
lcdwrite_com(0x01);
delayms(5);
lcd_setxy(0,0);
lcdwrite_float(ans1);
if(sqrtflag2!
=1&&num!
='N')lcdwrite_data(num);
break;
}
for(i=0;keynum1>0;i++)//计算按下的数字的大小
{
if(num1[i]!
='.')ans1=ans1*10+num1[i];
elseif(num1[i]=='.')
break;
keynum1--;
}
for(keynum1--,i++,j=0;keynum1>0;j++,i++,keynum1--)point=point*10+num1[i];
for(;j>0;j--)point*=0.1;
ans1=ans1+point;
sqrtflag1=0;//清除开方标志
sqrtflag2=0;//清除开方标志
if(keysqrt==0)//计算开方
{
delayms(5);
if(keysqrt==0)
{
if(beepflag==1)//若开声音则每一次按键均鸣叫
{
beep=0;
delayms(100);
beep=1;
}
ans=sqrt(ans1);
sqrtflag1=1;
lcdwrite_data(0xe8);
while(keysqrt==0);
delayms(10);
while(keysqrt==0);
break;
}
}
sign=num;//记住运算符号
lcdwrite_data(num);
break;//输入运算符号则退出第一运算数的输入
}
}
while
(1)
{
if(ac==1)break;//若清零,则退出输入
if(sqrtflag1==1)//若第一次按键为开方,则直接显示结果
{
break;
}
if((keyscan()!
='N')&&((num>=0&&num<=9)||num=='.'))//记录按键下的数字
{
if(keynum2<=7)
{
if(num=='.')
{
lcdwrite_data('.');//显示小数点
}
else
lcdwrite_num1(num);
num2[keynum2]=num;
keynum2++;
}
}
elseif(num=='='||keysqrt==0)
{
sqrtflag2=0;//清除开方标志
if(keysqrt==0)//进入开方
{
delayms(5);
if(keysqrt==0)
{
sqrtflag2=1;//开方标志
lcdwrite_data(0xe8);//写开方符号
if(beepflag==1)//若开声音则每一次按键均鸣叫
{
beep=0;
delayms(100);
beep=1;
}
while(keysqrt==0);
delayms(10);
while(keysqrt==0);
}
}
point=0;
for(i=0;keynum2>0;i++)//计算按下是数字的大小
{
if(num2[i]!
='.')ans2=ans2*10+num2[i];
elseif(num2[i]=='.')break;
keynum2--;
}
for(keynum2--,i++,j=0;keynum2>0;j++,i++,keynum2--)
point=point*10+num2[i];
for(;j>0;j--)
point*=0.1;
if(sqrtflag2!
=1)
lcdwrite_data(num);
ans2=ans2+point;
break;//输入等于号则退出第二运算数的输入
}
elseif(num=='+'||num=='-'||num=='*'||num=='/'||num=='^')
{
point=0;
for(i=0;keynum2>0;i++)//计算按下数字的大小
{
if(num2[i]!
='.')ans2=ans2*10+num2[i];
elseif(num2[i]=='.')break;
keynum2--;
}
for(keynum2--,i++,j=0;keynum2>0;j++,i++,keynum2--)
point=point*10+num2[i];
for(;j>0;j--)
point*=0.1;
lcdwrite_data(num);
ans2=ans2+point;
conflag=1;
break;//进行连续计算
}
}
if(ac==1)
{
ac=0;
continue;//清零后进行下一次运算
}
if(sign=='+')//计算结果
ans=ans1+ans2;
if(sign=='-')
ans=ans1-ans2;
if(sign=='*')
ans=ans1*ans2;
if(sign=='/')
ans=ans1/ans2;
if(sign=='^')//计算多次方
ans=pow(ans1,ans2);
if(sqrtflag2==1)//计算开方
ans=sqrt(ans);
lcd_setxy(1,0);
if((ans2==0&&sign=='/')||(ans<0&&(sqrtflag1==1||sqrtflag2==1)))
lcdwrite_string("matherror");//ans2=0或被开方数小于0时提示错误
elselcdwrite_float(ans);//显示结果
sqrtflag1=0,newcalc=1;//为新的一次运算准备
ans1=0;
ans2=0;
for(i=0;i<8;i++)
num1[i]=0;
for(i=0;i<8;i++)
num2[i]=0;
if(conflag==1)
{
conflag=0;
gotohere;//跳转到连续运算
}
}
}