基于单片机的简易计算器编程

基于单片机的简易计算器编程
单片机STC80c51写的计算器,键盘输入,单片机处理,液晶1602显示;能实现加减乘除,除法能保留小数点后两位,加减乘除最大数不能超过4个字节,也就是不能超过4294967296,还可以做范围更大,但要用到浮点数处理,浮点数显示没搞懂,所以范围就限制在四个字节了,读者可以尝试浮点数运算、显示

程序:
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
#define PinData P0
#define ClearScreen() WriteInstruc(0x01)
#define DispControl(temp) WriteInstruc(temp)
#define FunctionSet(temp) WriteInstruc(temp)
#define SetDDRAM_Add(Address) WriteInstruc(0x80 | Address)
#define CursorReturn() WriteInstruc(0x02)
sbit PinRS=P2^0;
sbit PinRW=P2^1;
sbit PinE=P2^2;
int r=0;
int a;
int f3=0; // 除法运算标志位
int f2=0; //一次运算只输入一次运算符标志位,输入则为1
int reset=0; //结束一次运算后复位标志位
int f1=0; //结果是负数标志位
int yun; //yun==1+ 2- 3* 4/----- 符号标志位
int o[16];
char idata e[16]="system error";
char t[16] ;
char m[16] ;
unsigned long int u=0;
unsigned long int v=0;
unsigned long int w=0;
double wd=0.0;
void delay(int i) //误差 0us 延时
{
unsigned char j;
for(;i>0;i--)
for(j=0;j<100;j++);
}
void ShortDelay(int i)
{
for(;i>0;i--) ;
}
void InitP0(bit i)
{
if(i==1) P0 = 0xff;
else P0 = 0x00;
}
char Read_BF_AC()
{
uchar temp;
InitP0(1);
PinRS=0;
PinRW=1;
PinE=0;
PinE=1;
ShortDelay(1);
temp = PinData;
ShortDelay(10);
PinE=0;
PinRW=0;
PinRS=1;
return(temp);
}
bit StatusCheck()
{
return((bit)(Read_BF_AC() & 0x80));
}
void WriteData(char data1)
{
InitP0(0);
PinRS=1;
PinRW=0;
PinE=0;
PinData = data1;
PinE=1;
ShortDelay(10);
PinE=0;
PinRW=1;
PinRS=0;
}
void WriteInstruc(char Instruc)
{
while(StatusCheck());
InitP0(0);
PinRS=0;
PinRW=0;
PinE=0;
PinData =Instruc;
PinE=1;
ShortDelay(10);
PinE=0;
PinRW=1;
PinRS=1;
}

void DispCharacter(int x, int y, char data1)
{
int temp;
while(StatusCheck()); //若LCD控制器忙,则等待
temp = y & 0x0f;
x &= 0x01;
if(x) temp |= 0x40;
SetDDRAM_Add(temp); //设置显示位置
WriteData(data1);
}
void soft_reset(void) //复位
{
((void (code *) (void)) 0x0000) ();
}
char xunzuo(char c) //0xfe左移
{

if(c&0x80)
{
c=c<<1;
c=c|0x01;
}
else
{ c<<=1;}
return(c);
}
unsigned long int pow(int y) //平方
{
int i;
unsigned long int x=1;
for(i=0;i<y;i++)
{
x=x*10;
}
return x;
}
void systemerror() //错误提醒,输入溢出或结果溢出!
{
int y0,q

0=3;
ClearScreen();
for(y0=0;y0<12;y0++)
{
DispCharacter(0,q0++,e[y0]);
}
delay(2000);
ClearScreen();
soft_reset();
}
void qian() //计算符号前面的数值
{
int i;
unsigned long tx=0;
u=0;
if(r-1>10) { systemerror();}
if(r-1==10) //判断输入数据是否溢出(四个字节!!)
{
if((t[0]-48)>4&&(t[1]-48)>2&&(t[2]-48)>9&&(t[3]-48)>4&&(t[4]-48)>9&&(t[5]-48)>6&&(t[6]-48)>7&&(t[7]-48)>2&&(t[8]-48)>9&&(t[9]-48)>5) { systemerror();}
}
for(i=r-2;i>=0;i--)
{
tx=u;
u=u+(( unsigned long )(t[i]-48)*(pow(r-i-2)));
if(u<tx) { systemerror();}
}
}
void hou( ) //计算符号后面的数值
{
int i;
unsigned long ty=0;
v=0;
if(r-1-a>10) { systemerror();} //判断输入数据是否溢出(四个字节!!)
if(r-1-a==10)
{
if((t[a]-48)>4&&(t[a-1]-48)>2&&(t[a-2]-48)>9&&(t[a-3]-48)>4&&(t[a-4]-48)>9&&(t[a-5]-48)>6&&(t[a-6]-48)>7&&(t[a-7]-48)>2&&(t[a-8]-48)>9&&(t[a-9]-48)>5) { systemerror();}
}
for(i=a;i<=r-2;i++)
{ ty=v;
v=v+(( unsigned long )(t[i]-48)*(pow(r-2-i)));
}
}
void xianshi0(char t[16]) //显示上行的算式,下行的结果
{
int j;
int k=15;
for(j=r-1;j>=0;j--)
{
if(t[j]==0x30) { DispCharacter(0,k--,'0');}
if(t[j]==0x31) { DispCharacter(0,k--,'1');}
if(t[j]==0x32) { DispCharacter(0,k--,'2');}
if(t[j]==0x33) { DispCharacter(0,k--,'3');}
if(t[j]==0x34) { DispCharacter(0,k--,'4');}
if(t[j]==0x35) { DispCharacter(0,k--,'5');}
if(t[j]==0x36) { DispCharacter(0,k--,'6');}
if(t[j]==0x37) { DispCharacter(0,k--,'7');}
if(t[j]==0x38) { DispCharacter(0,k--,'8');}
if(t[j]==0x39) { DispCharacter(0,k--,'9');}
if(t[j]==0x3a) { ClearScreen();soft_reset();}
if(t[j]==0x3b) { DispCharacter(0,k--,'=');}
if(t[j]==0x3c) { DispCharacter(0,k--,'+');}
if(t[j]==0x3d) { DispCharacter(0,k--,'-');}
if(t[j]==0x3e) { DispCharacter(0,k--,'*');}
if(t[j]==0x3f) { DispCharacter(0,k--,'/');}
if(k<-1)
{
systemerror();
}
}
}
void xianshi1(char m[16],int z) //显示上行的算式,下行的结果
{
int j,flash=0; //标志位:从不是零的高位开始显示!
int k=12;
for(j=3;j>=0;j--)
{
if(f3==0) { break; }
if(m[0]==0x30&&m[1]==0x30&&m[2]==0x30) { f3=0; break; }
if(m[j]==0x30) { DispCharacter(1,k++,'0'); flash++;}
if(m[j]=='.') { DispCharacter(1,k++,'.'); flash++;}
if(m[j]==0x31) { DispCharacter(1,k++,'1'); flash++;}
if(m[j]==0x32) { DispCharacter(1,k++,'2'); flash++;}
if(m[j]==0x33) { DispCharacter(1,k++,'3'); flash++;}

if(m[j]==0x34) { DispCharacter(1,k++,'4'); flash++;}
if(m[j]==0x35) { DispCharacter(1,k++,'5'); flash++;}
if(m[j]==0x36) { DispCharacter(1,k++,'6'); flash++;}
if(m[j]==0x37) { DispCharacter(1,k++,'7'); flash++;}
if(m[j]==0x38) { DispCharacter(1,k++,'8'); flash++;}
if(m[j]==0x39) { DispCharacter
(1,k++,'9'); flash++;}
}
flash=0;
if(f3==0) { k=6; } //确定显示方式:+-*则整数显示;/则小数显示!
else k=2;
for(j=z;j>=4;j--)
{
if(m[j]==0x30)
{
if(flash)
{
DispCharacter(1,k++,'0');
flash++;
}
else
k++;
}
if(m[j]==0x31) { DispCharacter(1,k++,'1'); flash++;}
if(m[j]==0x32) { DispCharacter(1,k++,'2'); flash++;}
if(m[j]==0x33) { DispCharacter(1,k++,'3'); flash++;}
if(m[j]==0x34) { DispCharacter(1,k++,'4'); flash++;}
if(m[j]==0x35) { DispCharacter(1,k++,'5'); flash++;}
if(m[j]==0x36) { DispCharacter(1,k++,'6'); flash++;}
if(m[j]==0x37) { DispCharacter(1,k++,'7'); flash++;}
if(m[j]==0x38) { DispCharacter(1,k++,'8'); flash++;}
if(m[j]==0x39) { DispCharacter(1,k++,'9'); flash++;}
if(flash==1&&f1==1) //当负数标志位为1时,在结果前输出“-”号!
{
f1=0;
k=k-2;
DispCharacter(1,k,'-');
k=k+2;
}
}
if(flash==6&&f3==1)
{
k=12;
DispCharacter(1,12,'.');
if(m[13]==0x31) { DispCharacter(1,k++,'1'); }
if(m[13]==0x32) { DispCharacter(1,k++,'2'); }
if(m[13]==0x33) { DispCharacter(1,k++,'3'); }
if(m[13]==0x34) { DispCharacter(1,k++,'4'); }
if(m[13]==0x35) { DispCharacter(1,k++,'5'); }
if(m[13]==0x36) { DispCharacter(1,k++,'6'); }
if(m[13]==0x37) { DispCharacter(1,k++,'7'); }
if(m[13]==0x38) { DispCharacter(1,k++,'8'); }
if(m[13]==0x39) { DispCharacter(1,k++,'9'); }
DispCharacter(1,14,'_');
DispCharacter(1,15,'_');
}

if(flash>6&&f3==1)
{
DispCharacter(1,12,'.');
DispCharacter(1,13,'_');
DispCharacter(1,14,'_');
DispCharacter(1,15,'_');
}
if(k>16) //理论上K没可能大于16!防止跑飞!
{
systemerror();
}
if(flash==0) { DispCharacter(1,11,'0');} //小数点前全为0的情况处理
reset=1; //标志位在一轮运算后初始化!(暂没让结果做第二轮运算功能...)
flash=0;
f1=0;
f2=0;
f3=0;
}

void fenshu() //将要显示的数分开成 个 十 百 千 万 最大值为4个字节
{
unsigned long int b,p;
if(f3==1)
{
b = w; // ******除法时********
p = ( unsigned long ) (wd*1000)-(w *1000.0);//(wd*1000)溢出时结果则错误 当w6位:不溢出,显示点后一位!
} //当w7位,可能不溢出,不显示点后数据(缺陷1:)但结果恰好位整数时看

不出来!)
else // 可能溢出,同样不显示点后数据
{ //当w>7位,一定溢出,不显示点后数据
b = w;
p = 0;
}
o[0]=p %10; //**************************************************************//
o[1]=p %100/10; //小数点后个十百的分离
o[2]=p /100;
//**************************************************************//
o[4]=b %10; //**************************************************************//
o[5]=b %100/10; //
o[6]=b %1000/100; //小数点前个十百千的分离,为四个字节
o[7]=b %10000/1000;
o[8]=b %100000/10000; //加减乘中结果存储在w中:w<4294967296
o[9]=b %1000000/100000; //除法 结果存储在wd中:wd<4294967296.0(只有前7位有效!)
o[10]=b %10000000/1000000; //加减法:输入溢出和结果大于四个字节输出溢出时能判断出来!
o[11]=b %100000000/10000000; //乘法: 溢出时由结果判断不出,只能判断出输入溢出的情况!
o[12]=b %1000000000/100000000; //(缺陷2:)输入不溢出而结果溢出的情况同样判断不出!(暂没办法)
o[13]=b /1000000000; // 除法:没有溢出的情况,在有效数字范围内能精确到小数点后三位!
//如果小数点前面就有5位数字,那小数点后就只能精确到两位了!
m[13]=o[13]+48; //***************************************************************//
m[12]=o[12]+48;
m[11]=o[11]+48;
m[10]=o[10]+48;
m[9]=o[9]+48;
m[8]=o[8]+48;
m[7]=o[7]+48;
m[6]=o[6]+48;
m[5]=o[5]+48;
m[4]=o[4]+48;
m[3]='.';
m[2]=o[2]+48;
m[1]=o[1]+48;
m[0]=o[0]+48;
}
void main() //主函数:键盘扫描
{
int i,j;
char temp0=0;
char temp1;
char temp2;
char run=0xfe;
char code tablepan[16]={0x7d,0xbe,0xbd,0xbb,0xde,0xdd,0xdb,0xee,0xed,0xeb,0x7e,0x7b,0x77,0xb7,0xd7,0xe7};
P1=0xf0;
t[0]=0x30;
DispControl(0x0c);
FunctionSet(0x3c);
SetDDRAM_Add(0x8f);
WriteData(t[0]);
while(1)
{
run=0xfe;
if(P1!=0xf0)
{
if(reset)
{
ClearScreen();soft_reset();
}
temp1=P1;
while(temp0==0)
{
P1=run;
delay(2);
run=xunzuo(run);
if((P1&0xf0)==temp1)
{
temp2=P1&0x0f;
temp0=(temp1)|(temp2);
for(i=0;i<16;i++)
{
if(temp0==tablepan[i])
{ P1=0xf0;
j=r;
if(f2==1&&temp0==tablepan[12]) {temp0=0; break;} //判断不重复输入运算符
if(f2==1&&temp0==tablepan[13]) {temp0=0; break;}
if(f2==1&&temp0==tablepan[14]) {temp0=0; break;}
if(f2==1&&temp0==tablepan[15]) {temp0=0; break;}
if((f2==0&&temp0==tablepan[11])) {temp0=0; break;} //判断输入‘=’前有运算符输入
if(j==0&&temp0==tablepan[12]) { temp0=0; break;} //判断第一个输入不是运算符
if(j==0&&temp0==tablepan[13]) { temp0=0; break;}
if(j==0&&temp0==tablepan[14]) { temp0=0; break;}
if(j==0&&temp0=

=tablepan[15]) { temp0=0; break;}
if(j==0&&temp0==tablepan[11]) { temp0=0; break;}
t[j]=(i+48)&0xff;
if((f2==1&&temp0==tablepan[11]&&t[j-1]==0x3c)) {temp0=0; break;} // 判断'='前
不是运算符
if((f2==1&&temp0==tablepan[11]&&t[j-1]==0x3d)) {temp0=0; break;}
if((f2==1&&temp0==tablepan[11]&&t[j-1]==0x3e)) {temp0=0; break;}
if((f2==1&&temp0==tablepan[11]&&t[j-1]==0x3f)) {temp0=0; break;}
r++;
xianshi0(t);
reset=0;
break;
}
}
}
}
if(temp0==tablepan[12]) // + yun为符号标志位
{qian();a=r;yun=1;f2=1;}
if(temp0==tablepan[13]) // - f2为已经输入运算符标志位
{qian();a=r;yun=2;f2=1;}
if(temp0==tablepan[14])
{qian();a=r;yun=3;f2=1;} // *
if(temp0==tablepan[15])
{qian();a=r;yun=4;f2=1;} // /
if(temp0==0x7b) // 当输入运算符后(f2==1时)才能进行运算!
{
hou();
if(yun==1)
{
w=u+v;
if(w<u) { systemerror();} //加法结果溢出
}
if(yun==2)
{
CY=0;
w=u-v;
while(CY==1) //减法出现借位处理:整形处理时
{
w=4294967296-w;
f1=1;
break;
CY=0;
}
// if(w<0) //减法出现负号--标志位处理为1 double型处理时
// {
// w=w*(-1);
// f1=1;
// }
}
if(yun==3)
{
w=u*v;
if(j>12)
{ systemerror();} //u 和 v总的数位不能超过11位,否则溢出
}
if(yun==4) // (缺陷2):为11位时也有溢出的可能,这种情况计算器判断不出了!
{
if(v==0) {systemerror();}
w=u/v;
wd=( double )(( double )u/( double )v);
f3=1;
}
fenshu();
xianshi1(m,13);
}
}
temp0=0;
P1=0xf0;
while(P1!=0xf0)
{ }
delay(5);
}
}

相关文档
最新文档