微控制器: 簡易計算器的實現(鍵盤)
阿新 • • 發佈:2019-02-16
利用矩陣鍵盤實現一個簡易的計算器。
為了簡化問題,我們假設只支援小於100的非負整數之間的加、減、乘的運算,並且支援連續運算(結果的數值可以再進行運算)。
本程式中C為加號,D為減號,E為乘號,F為等於號。
程式碼中有詳細的註釋。
/* 注:本程式 C 為+, D 為- E為* F 為=號,支援非負整數連續運算。 輸入的數值小於100,運算結果不超過1000. by Tach ------------------------------------------------*/ #include<reg52.h> #define DataPort P0 //定義資料埠 程式中遇到DataPort 則用P0 替換 #define KeyPort P3 sbit DUAN=P2^6;//定義鎖存使能埠 段鎖存 sbit WEI=P2^7;// 位鎖存 unsigned char code dofly_DuanMa[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f, 0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};// 顯示段碼值0~F和-號 unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分別對應相應的數碼管點亮,即位碼 unsigned char TempData[8]; //儲存顯示值的全域性變數 void DelayUs2x(unsigned char t);//us級延時函式宣告 void DelayMs(unsigned char t); //ms級延時 void Display(unsigned char FirstBit,unsigned char Num);//數碼管顯示函式 unsigned char KeyScan(void);//鍵盤掃描 unsigned char KeyPro(void); void Init_Timer0(void);//定時器初始化 /*------------------------------------------------ 主函式 ------------------------------------------------*/ void main (void) { unsigned char num,tempp=0; int sym_add,sym_sub,sym_mul; int datanum[2]; int i=0,j,flag,ans,ans_clear,t; unsigned char temp[8]; Init_Timer0(); while (1) //主迴圈 { num=KeyPro(); if(num!=0xff) { if(num>=0 && num<=9) { if(ans_clear) { ans_clear=0; for(j=0;j<8;j++)//清屏 TempData[j]=0; } tempp=tempp*10+num; if(tempp/10>0) TempData[6]=dofly_DuanMa[tempp/10]; TempData[7]=dofly_DuanMa[tempp%10]; datanum[i]=tempp; } else if(num==15) { i=0; tempp=0; if(sym_add==1) { ans=datanum[0]+datanum[1]; t=ans; if(ans/100>0) { TempData[5]=dofly_DuanMa[ans/100]; ans=ans%100; } if(ans/10>0 || (TempData[5]!=0 && ans/10==0)) TempData[6]=dofly_DuanMa[ans/10]; TempData[7]=dofly_DuanMa[ans%10]; } else if(sym_sub==1) { ans=datanum[0]-datanum[1]; t=ans; if(ans<0) { flag=1; ans=-ans; } else flag=0; if(flag) TempData[4]=dofly_DuanMa[16]; //負號 if(ans/100>0) { TempData[5]=dofly_DuanMa[ans/100]; ans=ans%100; } if(ans/10>0) TempData[6]=dofly_DuanMa[ans/10]; TempData[7]=dofly_DuanMa[ans%10]; } else if(sym_mul==1) { ans=datanum[0]*datanum[1]; t=ans; if(ans/100>0) { TempData[5]=dofly_DuanMa[ans/100]; ans=ans%100; } if(ans/10>0 || (TempData[5]!=0 && ans/10==0)) TempData[6]=dofly_DuanMa[ans/10]; TempData[7]=dofly_DuanMa[ans%10]; } sym_add=0; sym_sub=0; sym_mul=0; ans_clear=1; datanum[0]=ans; } else if(num>=12 && num<=14) { i++; if(num==12) sym_add=1; else if(num==13) sym_sub=1; else if(num==14) sym_mul=1; tempp=0; for(j=0;j<8;j++)//清屏 TempData[j]=0; } } //主迴圈中新增其他需要一直工作的程式 } } /*------------------------------------------------ uS延時函式,含有輸入引數 unsigned char t,無返回值 unsigned char 是定義無符號字元變數,其值的範圍是 0~255 這裡使用晶振12M,精確延時請使用匯編,大致延時 長度如下 T=tx2+5 uS ------------------------------------------------*/ void DelayUs2x(unsigned char t) { while(--t); } /*------------------------------------------------ mS延時函式,含有輸入引數 unsigned char t,無返回值 unsigned char 是定義無符號字元變數,其值的範圍是 0~255 這裡使用晶振12M,精確延時請使用匯編 ------------------------------------------------*/ void DelayMs(unsigned char t) { while(t--) { //大致延時1mS DelayUs2x(245); DelayUs2x(245); } } /*------------------------------------------------ 顯示函式,用於動態掃描數碼管 輸入引數 FirstBit 表示需要顯示的第一位,如賦值2表示從第三個數碼管開始顯示 如輸入0表示從第一個顯示。 Num表示需要顯示的位數,如需要顯示99兩位數值則該值輸入2 ------------------------------------------------*/ void Display(unsigned char FirstBit,unsigned char Num) { static unsigned char i=0; DataPort=0; //清空資料,防止有交替重影 DUAN=1; //段鎖存 DUAN=0; DataPort=dofly_WeiMa[i+FirstBit]; //取位碼 WEI=1; //位鎖存 WEI=0; DataPort=TempData[i]; //取顯示資料,段碼 DUAN=1; //段鎖存 DUAN=0; i++; if(i==Num) i=0; } /*------------------------------------------------ 定時器初始化子程式 ------------------------------------------------*/ void Init_Timer0(void) { TMOD |= 0x01; //使用模式1,16位定時器,使用"|"符號可以在使用多個定時器時不受影響 //TH0=0x00; //給定初值 //TL0=0x00; EA=1; //總中斷開啟 ET0=1; //定時器中斷開啟 TR0=1; //定時器開關開啟 } /*------------------------------------------------ 定時器中斷子程式 ------------------------------------------------*/ void Timer0_isr(void) interrupt 1 { TH0=(65536-2000)/256; //重新賦值 2ms TL0=(65536-2000)%256; Display(0,8); // 呼叫數碼管掃描 } /*------------------------------------------------ 按鍵掃描函式,返回掃描鍵值 ------------------------------------------------*/ unsigned char KeyScan(void) //鍵盤掃描函式,使用行列逐級掃描法 { unsigned char Val; KeyPort=0xf0;//高四位置高,低四位拉低 if(KeyPort!=0xf0)//表示有按鍵按下 { DelayMs(10); //去抖 if(KeyPort!=0xf0) { //表示有按鍵按下 KeyPort=0xfe; //檢測第一行 if(KeyPort!=0xfe) { Val=KeyPort&0xf0; Val+=0x0e; while(KeyPort!=0xfe); DelayMs(10); //去抖 while(KeyPort!=0xfe); return Val; } KeyPort=0xfd; //檢測第二行 if(KeyPort!=0xfd) { Val=KeyPort&0xf0; Val+=0x0d; while(KeyPort!=0xfd); DelayMs(10); //去抖 while(KeyPort!=0xfd); return Val; } KeyPort=0xfb; //檢測第三行 if(KeyPort!=0xfb) { Val=KeyPort&0xf0; Val+=0x0b; while(KeyPort!=0xfb); DelayMs(10); //去抖 while(KeyPort!=0xfb); return Val; } KeyPort=0xf7; //檢測第四行 if(KeyPort!=0xf7) { Val=KeyPort&0xf0; Val+=0x07; while(KeyPort!=0xf7); DelayMs(10); //去抖 while(KeyPort!=0xf7); return Val; } } } return 0xff; } /*------------------------------------------------ 按鍵值處理函式,返回掃鍵值 ------------------------------------------------*/ unsigned char KeyPro(void) { switch(KeyScan()) { case 0xee:return 0;break;//0 按下相應的鍵顯示相對應的碼值 case 0xde:return 1;break;//1 case 0xbe:return 2;break;//2 case 0x7e:return 3;break;//3 case 0xed:return 4;break;//4 case 0xdd:return 5;break;//5 case 0xbd:return 6;break;//6 case 0x7d:return 7;break;//7 case 0xeb:return 8;break;//8 case 0xdb:return 9;break;//9 case 0xbb:return 10;break;//a case 0x7b:return 11;break;//b case 0xe7:return 12;break;//c case 0xd7:return 13;break;//d case 0xb7:return 14;break;//e case 0x77:return 15;break;//f default:return 0xff;break; } }