本文設計基于AT89S52單片機的簡易計算器。它的功能是:
(1)計算器至少能正常顯示8位數。
(2)卡機時,顯示0。第一次按下時,顯示D1;第二次按下時,顯示D1D2。
(3)計算器能對整數進行簡單的加、減、乘、除四則運算,在做除法時能自動舍去小數部分。
(4)運算結果超過可顯示的位數時能進行出錯提示。
總體設計
計算器以AT89S52單片機為核心芯片,通過掃描鍵盤來得到數據,另外通過CPU將得到的數據按要求進行運算并將結果送到顯示電路進行顯示。
框圖設計
基于AT89S52單片機的簡易計算器由電源電路、單片機主控電路、按鍵電路、顯示電路和復位電路幾部分組成,框圖組成如下圖所示。
基于AT89S52單片機的簡易計算器系統框圖
系統設計
電路原理圖
基于AT89S52單片機簡易計算器電路原理圖
程序流程圖
由于本設計主要是算法問題,所以程序采用C語言編寫。主函數對單片機進行初始化,并不斷調用掃描函數和運算函數。顯示函數采用1ms定時中斷來對顯示數據進行實時跟新。基于AT89S52單片機簡易計算器程序流程圖如下圖所示。
簡易計算器程序流程圖
代碼編寫
#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];
}
}
評論