AT89S52单片机实现简易计算器(C语言程序)

发布时间:2023-06-26  

本文设计基于AT89S52单片机的简易计算器。它的功能是:

(1)计算器至少能正常显示8位数。

(2)卡机时,显示0。第一次按下时,显示D1;第二次按下时,显示D1D2。

(3)计算器能对整数进行简单的加、减、乘、除四则运算,在做除法时能自动舍去小数部分。

(4)运算结果超过可显示的位数时能进行出错提示。


总体设计

计算器以AT89S52单片机为核心芯片,通过扫描键盘来得到数据,另外通过CPU将得到的数据按要求进行运算并将结果送到显示电路进行显示。


框图设计

基于AT89S52单片机的简易计算器由电源电路、单片机主控电路、按键电路、显示电路和复位电路几部分组成,框图组成如下图所示。

AT89S52单片机实现简易计算器(C语言程序)

基于AT89S52单片机的简易计算器系统框图


系统设计

电路原理图

AT89S52单片机实现简易计算器(C语言程序)

基于AT89S52单片机简易计算器电路原理图

程序流程图

由于本设计主要是算法问题,所以程序采用C语言编写。主函数对单片机进行初始化,并不断调用扫描函数和运算函数。显示函数采用1ms定时中断来对显示数据进行实时跟新。基于AT89S52单片机简易计算器程序流程图如下图所示。

AT89S52单片机实现简易计算器(C语言程序)

简易计算器程序流程图

代码编写

#include P #include《》

#define LEDS 8

/***按键程序***/ char keyscan();

/***显示程序***/ void display();

char dsp[9]={0,0,12,12,12,12,12,12,12}; //初始化显示数组

/***计算程序***/

void calculate(char k,char c1[8],char c2[8]);


/***片选***/

unsigned char code Select[]=

{0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

/***码选***/

unsigned char code LED_CODES[]=

{0xC0,0xF9,0xA4,0xB0,0x99,

//0-4

0x92,0x82,0xF8,0x80,0x90, //5-9

0x86,0xAF,0xFF,0x7F,0xBF,}; //E,r,空格,。,-

/***main函数***/

void main(void) {

char i,j,k,c;

char a[8],b[8];

/***定时1ms***/

TMOD=0;

TL0=-(1000/256);

TH0=-(1000%256);

EA = 1; //总中断开关

ET0 = 1; //开中断

TR0 = 1; //启用计数器0

KSC:do {

for(i=1;i《9;i++) //数字录入循环 {

dsp[0]=keyscan();

if(c==2&&dsp[0]《10)

//此段代码验证是否有旧的计算结果在显示,且不

再参与新计算

{

dsp[1]=dsp[0];

for(j=2;j《9;j++)

dsp[j]=12;

c=0;

}

else if(c==2&&dsp[0]》9) //旧的计算结果将参与新的计算,作为第一个数

{ c=0; }

if(dsp[0]==0&&dsp[1]==0&&dsp[2]==12) //个位为0且十位为空时按下0,按键无

效,跳回KSC等待正确输入 {

/***goto跳转标志***/ goto KSC;

}

else if(dsp[0]》9) break; //有操作符按下,跳出数字录入循环

else

{

for(j=i;j》0;j--)

dsp[j]=dsp[j-1]; //移位,以正确显示数字 }

}

if(i==9) //判断是否输入8个有效数字,是则等待操作符,否则直接判断操作符 {

do //使用do while无论是否第一个数都取一次操作符 {

dsp[0]=keyscan();

//获取操作符号

if(dsp[0]==14||dsp[0]《10) //按下C或者第9位数字清零

{

单片机系统开发与应用工程实习计报告

7

dsp[1]=0;

for(i=2;i《9;i++)

dsp[i]=12; c=0;

}

}

while((dsp[0]==15)&&(c==0));

//等号被按下,等待新的操作符(仅对

第一个数字有效)

}

else if(dsp[0]==14) //按下C清零

{

dsp[1]=0;

for(i=2;i《9;i++)

dsp[i]=12;

c=0;

}

while(dsp[0]==15&&c==0)

//未输满8位且是第一个数字即按下等号,等

待非等号操作符 {

dsp[0]=keyscan();

//获取操作符号

if(dsp[0]==14||dsp[0]《10) //按下C或者数字都进行清零,重新输入a

{

dsp[0]=14; //将dsp[0]置为14,防止因数字清零未能拦截

dsp[1]=0;

for(i=2;i《9;i++)

dsp[i]=12;

c=0;

}

}

}while(dsp[0]==14); //数字输入未完成即按下C,重新等待输入

do

{

if(c==0) //没有数字输入 { k=dsp[0];

//存计算符(循环内已排除C、=、数字)

for(i=0;i《8;i++) //将第一个数存入a[8] {

a[i]=dsp[i+1];

}


dsp[1]=0;

//清零

for(i=2;i《9;i++) dsp[i]=12; c=1;

//已输入a

/***goto跳转标志***/ goto KSC;

}

else if(c==1) {

for(i=0;i《8;i++) //将第二个数存入b[8] {

b[i]=dsp[i+1]; }

c=2;

//已输入b

if(dsp[0]!=15) //b输完后操作符不是等号

{

calculate(k,a,b);

for(i=0;i《8;i++) //将计算结果存入a[8],a值更新 {

a[i]=dsp[i+1];

}

k=dsp[0]; //更新计算符

c=1;

/***goto跳转标志***/ goto KSC; }

}

}while((dsp[0]==15)&&(c《2)); //直到ab输入完成且按下等号

calculate(k,a,b); //进行最后计算

/***goto跳转标志***/

goto KSC; //跳回KSC,等待新一轮计算 while(1); //防止程序跑飞

}

char keyscan() {

char KeyL;

char KeyR;

char j;

do

{

do

{

P3=0xF0;

P3=P3|0xF0;//行扫描11110000

if(P3!=0xF0)

{

KeyL=P3;

P3=0x0F;

P3=P3|0x0F;//列扫描00001111

KeyR=P3;

}

}

while(KeyL==0xF0||KeyR==0x0F);

for(j=0;j《12;j++) //延时0.001s=1ms

{;}

}while(P3!=0x0F);

switch(KeyL&KeyR) {

case 0x28:{return 0;break;}

case 0x11:{return 1;break;}

case 0x21:{return 2;break;}

case 0x41:{return 3;break;}

case 0x12:{return 4;break;}

case 0x22:{return 5;break;} case 0x42:{return 6;break;} case 0x14:{return 7;break;} case 0x24:{return 8;break;}

case 0x44:{return 9;break;}

case 0x81:{return 10;break;}//加法(第一行,第四列)

case 0x82:{return 11;break;}//减法(第二行,第四列)

case 0x84:{return 12;break;}//乘法(第三行,第四列)

case 0x88:{return 13;break;}//除法(第四行,第四列)

case 0x18:{return 14;break;}//清零(第四行,第一列)

case 0x48:{return 15;break;}//计算结果(第四行,第三列) }

}


void display() interrupt 1 using 1 //利用定时器中断实现间时显示

{

char i,j,h;

ET0=0;

for(j=8;j》0;j--) //扫描8次 {

for(i=7;i》=0;i--) //从高位到低位扫描显示 { P2=1;

P1=LED_CODES[dsp[8-i]];

P2=Select[i];

for(h=0;h《8;h++)

{

;} }

}

TL0=-(1000/256);

TH0=-(1000%256);

ET0=1;

}

void calculate(char k,char a[8],char b[8]) {

char r[8];

long i,x,y;

i=0;

x=0;

y=0;

for(i=7;i》0;i--) //数值转化,将代表空格的12转化为数字0,因为个位不显示空格,默认为0,所以不转化 {

while(a[i]==12)a[i]=0;

while(b[i]==12)b[i]=0;

}

x=a[4];

x=10000*x;

x=x+a[0]+a[1]*10+a[2]*100+a[3]*1000+a[5]*100000+a[6]*1000000+a[7]*10000000;

y=b[4];

y=10000*y;

y=y+b[0]+b[1]*10+b[2]*100+b[3]*1000+b[5]*100000+b[6]*1000000+b[7]*10000000;

if(k==10)//加法运算 {

x=x+y;

if(x》99999999) //大于8位,显示“Err”

{

r[0]=11; //r

r[1]=11; //r

r[2]=10; //E

r[3]=12; //空格

r[4]=12;

r[5]=12;

r[6]=12

; r[7]=12;

}

else {

r[0]=x%10;

r[1]=(x%100)/10;

r[2]=(x%1000)/100;

r[3]=(x%10000)/1000;

r[4]=(x%100000)/10000;

r[5]=(x%1000000)/100000;

r[6]=(x%10000000)/1000000;

r[7]=x/10000000;

}

}


if(k==11)//减法运算 {

if(x

x=y-x;

if(x》9999999)

{

r[0]=11; //r

r[1]=11; //r

r[2]=10; //E

r[3]=12; //空格

r[4]=12;

r[5]=12;

r[6]=12;

r[7]=12;

}

else {

r[0]=x%10;

r[1]=(x%100)/10;

r[2]=(x%1000)/100;

r[3]=(x%10000)/1000;

r[4]=(x%100000)/10000;

r[5]=(x%1000000)/100000;

r[6]=(x%10000000)/1000000;

r[7]=x/10000000;

for(i=7;i》0;i--) //将有效数字的高一位转化为-号

{

if(r[i]==0&&r[i-1]!=0) { r[i]=14; break; }

}

}

}

else { x=x-y; r[0]=x%10; r[1]=(x%100)/10; r[2]=(x%1000)/100; r[3]=(x%10000)/1000; r[4]=(x%100000)/10000; r[5]=(x%1000000)/100000; r[6]=(x%10000000)/1000000; r[7]=x/10000000; }

}

if(k==12)//乘法运算

{

i=x; x=x*y;

if(y==0)

{

x=0;

}

else if(x》99999999||x

{

r[0]=11; //r

r[1]=11; //r

r[2]=10; //E

r[3]=12; //空格

r[4]=12;

r[5]=12;

r[6]=12;

r[7]=12;

}

else {

r[0]=x%10;

r[1]=(x%100)/10;

r[2]=(x%1000)/100;

r[3]=(x%10000)/1000;

r[4]=(x%100000)/10000;

r[5]=(x%1000000)/100000

; r[6]=(x%10000000)/1000000;

r[7]=x/10000000;

}

}

if(k==13)//除法运算

{

if(y==0) //被除数不能为0

{ r[0]=11; //r

r[1]=11; //r

r[2]=10; //E

r[3]=12; //空格

r[4]=12;

r[5]=12;

r[6]=12;

r[7]=12;

}


else {

x=x/y;

r[0]=x%10;

r[1]=(x%100)/10;

r[2]=(x%1000)/100;

r[3]=(x%10000)/1000;

r[4]=(x%100000)/10000;

r[5]=(x%1000000)/100000;

r[6]=(x%10000000)/1000000;

r[7]=x/10000000;

}

}

for(i=7;i》0;i--) //数值转化,将高位的无效数字0转化为空格符12 { if(r[i]==0) r[i]=12; else

break;

}

for(i=0;i《8;i++) //将计算结果存入dsp[9],显示数更新

{

dsp[i+1]=r[i];

}

}


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>