基于單片機的簡易計算器設計
一、設計任務和性能指標
1.1設計任務
利用單片機及外圍接口電路(鍵盤接口和顯示接口電路)設計制作一個計算器,用四位一體數碼管顯示計算數值及結果。要求用Protel 畫出系統的電路原理圖(要求以最少組件,實現系統設計所要求的功能),繪出程序流程圖,并給出程序清單(要 求思路清晰,盡量簡潔,主程序和子程序分開,使程序有較強的可讀性)。
1.2性能指標
1加法:能夠計算四位以內的數的加法。
2減法:能計算四位數以內的減法。
3乘法:能夠計算兩位數以內的乘法。
4除法:能夠計算四位數的乘法
5有清零功能,能隨時對運算結果和數字輸入進行清零。
二、系統設計方案
按照系統設計的功能的要求,初步確定設計系統由單片機主控模塊、四位一體數碼管顯示模塊、鍵掃描接口電路共三個主要模塊組成。主控芯片使用51系列AT89C51單片機,采用高性能的靜態80C51設計,它由先進工藝制造,并帶有非易失性Flash程序存儲器。它是一種高性能、低功耗的8位COMS微處理芯片,市場應用最多。
鍵盤電路采用4*4矩陣鍵盤電路。
顯示模塊采用四位一體共陽極數碼管和SN74LS244鎖存芯片構成等器件構成。
三、硬件系統設計
1.單片機最小系統
單片機最小系統就是支持主芯片正常工作的最小電路部分,包括主控芯片、復位電路和晶振電路。
主控芯片選取STC89C51RC芯片,因其具有良好的性能及穩定性,價格便宜應用方便。
晶振選取11.0592MHz,晶振旁電容選取30pF。
采用按鍵復位電路,電阻分別選取100Ω和10K,電容選取10μF。
單片機最小系統硬件電路圖如圖(1)所示。
0.png (48.81 KB, 下載次數: 108)
下載附件
2017-5-25 15:47 上傳
圖(1) 單片機最小系統 2.鍵盤接口電路 計算器所需按鍵有: 數字鍵:’1’,’2’,’3’,’4’,’5’,’6’,’7’,’8’,’9’,’0’ 功能鍵:’+’, ’-‘, ’*’, ’/ ’ , ’ = ’, ’ C( 清零)’ 共計16個按鍵,采用4*4矩陣鍵盤,鍵盤的行和列之間都有公共端相連,四行采用端口P0.0~P0.3,四列采用端口P3.0~P3.3,通過8個端口的的高低電平完成對矩陣鍵盤的控制。通過對16個按鍵進行編碼,從而得到鍵盤的口地址,對比P1口德掃描結果和各按鍵的地址,我們就可以得到是哪個鍵按下,從而完成鍵盤的功能。 3.數碼管顯示電路 采用4位一體的數碼管對計算數據和結果進行顯示,這里選取共陽數碼管,利用NPN三極管對數碼管進行驅動,為了節省I/O資源,采取動態顯示的方法來顯示計算數據及結果。 利用SN74LS244N鎖存器來實現數碼管的動態顯示,P1口輸出顯示值,P2.0~P2.3為位選端口。通過鎖存器對段選信號的鎖存,最終得到對數碼管輸入數據的控制。 以下為數碼顯示電路的硬件電路圖,左圖為數碼管驅動電路,右圖為段選信號鎖存電路。
0.png (33.6 KB, 下載次數: 87)
下載附件
2017-5-25 15:48 上傳
四.軟件設計部分 根據選題要求,系統編程如下所示: - #include "reg51.h"
- sbit P3_0=P3^0;
- sbit P3_1=P3^1;
- sbit P3_2=P3^2;
- sbit P3_3=P3^3;
- sbit P3_4=P3^4;
- sbit P3_5=P3^5;
- sbit P3_6=P3^6;
- sbit P3_7=P3^7;
- unsigned char sz[11],xs1[4],xs2[4],sj;
- int i,cs,bb,t1,t2,fh,s1,s2;
- void chushihua()
- {
- bb=1;
- xs1[0]=10;xs1[1]=10;xs1[2]=10;xs1[3]=10;
- xs2[0]=10;xs2[1]=10;xs2[2]=10;xs2[3]=10;
- t1=0;t2=0;s1=s2=0;
- fh=0;
- cs=1;
-
- }
- void xianshi(unsigned char xs[4])
- {
- int i,j;
- unsigned char zy;
- zy=0x08;
- for (i=0;i<4;i++)
- {
- P2=(0xff-zy);
- P1=sz[xs[i]];
- zy=(zy>>1);
- for (j=0;j<100;j++) ;
-
- }
- // for (i=0;i<100;i++);
- return;
- }
- unsigned char saomiao()
- {
- int i,j;
- unsigned char pp;
- for (i=0;i<1000;i++);
- P0=0xfe;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 7;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 8;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 9;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 11;}
- //==========1
- P0=0xfd;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 4;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 5;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 6;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 12;}
- //==========2
- P0=0xfb;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 1;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 2;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 3;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 13;}
- //==========3
- P0=0xf7;
- P3=0x0f;
- pp=P3;
- if (P3_0==0) {P3=0x0f;pp=P3;while (P3_0==0);for (i=0;i<1000;i++);return 16;}
- if (P3_1==0) {P3=0x0f;pp=P3;while (P3_1==0);for (i=0;i<1000;i++);return 0;}
- if (P3_2==0) {P3=0x0f;pp=P3;while (P3_2==0);for (i=0;i<1000;i++);return 15;}
- if (P3_3==0) {P3=0x0f;pp=P3;while (P3_3==0);for (i=0;i<1000;i++);return 14;}
- //===========4
- return 10;
- }
- void chuli(unsigned char x)
- {
- int i;
- if (x==16)
- {
- cs=0;
- return ;
- }
- if (x>=0 && x<10)
- {
- if (bb==1)
- {
- if (s1= =4) {cs=0;return ;}
- else
- {
- for (i=3;i>0;i--)
- xs1[i]=xs1[i-1];
- xs1[0]=x;
- s1++;
- t1=t1*10+x;
- }
- }
- if (bb==2)
- {
- if (s2==4) {cs=0;return ;}
- else
- {
- for (i=3;i>0;i--)
- xs2[i]=xs2[i-1];
- xs2[0]=x;
- s2++;
- t2=t2*10+x;
- }
- }
- }
- if (x>10)
- {
- if (bb==1) {fh=x;bb=2;return;}
- if (bb==2)
- {
- if (fh==11) t1=t1/t2;
- if (fh==12) t1=t1*t2;
- if (fh==13) t1=t1-t2;
- if (fh==14) t1=t1+t2;
- if (t1>=10000) {cs=0;return;}
- else
- {
- if (t1>=0 && t1<10) {xs1[0]=t1;xs1[1]=10;xs1[2]=10;xs1[3]=10;}
- if (t1>=10 && t1<100) {xs1[0]=t1%10;xs1[1]=t1/10;xs1[2]=10;xs1[3]=10;}
- if (t1>=100 && t1<1000) {xs1[0]=t1%10;xs1[1]=(t1-(t1/100)*100)/10;xs1[2]=t1/100;xs1[3]=10;}
- if (t1>=1000 && t1<10000) {xs1[0]=t1%10;xs1[1]=t1%100/10;xs1[2]=(t1-(t1/1000)*1000)/100;xs1[3]=t1/1000;}
- bb=2;
- s2=0;
- t2=0;
- xs2[0]=10;xs2[1]=10;xs2[2]=10;xs2[3]=10;
- fh=x;
- }
- }
- }
- }
- void main()
- {
- sz[0]=0xfc;
- sz[1]=0x60;
- sz[2]=0xda;
- sz[3]=0xf2;
- sz[4]=0x66;
- sz[5]=0xb6;
- sz[6]=0xbe;
- sz[7]=0xe0;
- sz[8]=0xfe;
- sz[9]=0xf6;
- sz[10]=0x00;
- cs=0;
-
- for (;;)
- {
- if (cs==0) chushihua();
- if (cs==1) sj=saomiao();
- if (cs==1 && sj!=10) chuli(sj);
- if (cs==1 &&(bb==1 || bb==2 && s2==0)) xianshi(xs1);
- if (cs==1 &&(bb==2 && s2!=0)) xianshi(xs2);
-
- }
- }
- 軟件設計好后,在KEIL上面進行仿真,把仿真得到的文件下載到Proteus里面進行仿真,得到Proteus仿真電路圖如下所示:
-
- 圖(2) 計算器Proteus仿真電路圖
- 五.硬件電路焊接及調試
- 根據電路圖紙,焊接好硬件電路,把程序下載到單片機芯片,接通好電源,進行調試。在焊接好器件后,先不要將芯片插在芯片座上,要先驗證先板上電源是否好用,有無短路等。接上USB電源,用萬用表測量個芯片座對應電源和地之間的電壓值,觀察電壓值是否正常。一切正常后方可將芯片插入芯片座,以繼續測試其他功能。
- 將芯片插上后,對各個模塊進行調試,按鍵是否工作正常,數碼管是否顯示正常等。編寫相關部分的測試程序對其進行測試。
- 各部分硬件檢測無誤后,下載程序進行整體調試,一切正常后,結束調試過程。
- 用所設計的單片機進行數字計算,顯示結果與任務要求一致,焊接電路符合要求。
- 六.課程設計心得
- 兩周的時間,終于把單片機課程設計搞完了。整個體會還是比較多的。首先是題目的選擇,各方面的原因,自己還是想選個簡單點的題目,不過最后選來選去,還是選擇了計算器。由于自己對單片機編程還不是很熟悉,結果在設計的時候遇到了一系列問題,程序總是調試部處理,不過還好,最后在同學的幫助下終于把程序調試出來了,雖然程序設計實現的功能與老師要求的不盡相同,不過勉強還算可以。從這里我知道了基本知識的重要性。其實進行程序設計的時候主要是對各功能模塊的把握。計算器里面最難的一部分是矩陣鍵盤的掃描和編碼,那個費了很大力氣。
- 另外一點就是硬件焊接調試部分。焊接的時候到時輕松,一個下午就焊接好了,然后是調試部分。調試花費的時間還是比較長的。不過有了上個學期數字電路焊接調試的經驗,這次單片機調試還算是比較順利。我也是從電路板的正負電源檢測起,一步一步來,最終得到了想要的結果。調試的時候主要遇到了兩個問題。一個是鍵盤總是沒有反應,為了這個自己調試了很久,前前后后把電路板檢查了幾次,最后才發現是鍵盤本身的問題,和同學們換了個好鍵盤才行。另一個問題是總是顯示不出來1、4、7這三個數字。檢測來檢測去,發現來是在測試最小系統時在一個位選端接了高電平,對位選信號產生了影響。當把那個高電平去掉后,終于得到了正確的結果。
- 總的來說這次課程設計達到了完成了基本任務,達到了基本要求。通過親身對程序設計和電路焊接調試的體會,自己對單片機有了進一步的了解,單片機編程能力也得到了提高。電路板的焊接與調試,使自己電路調試的方法和思想進一步加強了。這次單片機課程設計應該說是比較成功的。
- 參考文獻:
- 【1】徐維祥、劉旭敏:,《單片微型機原理及應用》,大連理工大學出版社,1996年。
- 【2】李光飛、樓然苗、胡佳文、謝象佐.,《單片機課程設計與實例指導.》, 北京航空航天大學出版社,2004年。
- 【3】余永權,《89系列FLASH單片機原理及應用.》,電子工業出版社,2002。
- 【4】楊恢先、黃輝先,《單片機原理及應用》,人民郵電出版社,2006年。
- 【5】常敏、王涵、范江波,《單片機應用程序開發與實踐》,電子工業出版社,2009年。
- #include //頭文件
- #define uint unsigned int //
- #define uchar unsigned char
-
- sbit lcden=P2^3; //定義引腳
- sbit rs=P2^4;
- sbit rw=P2^0;
- sbit busy=P0^7;
-
- char i,j,temp,num,num_1;
- long a,b,c; //a,第一個數 b,第二個數 c,得數
- float a_c,b_c;
- uchar flag,fuhao;//flag表示是否有符號鍵按下,fuhao表征按下的是哪個符號
-
- uchar code table[]={
- 7,8,9,0,
- 4,5,6,0,
- 1,2,3,0,
- 0,0,0,0};
- uchar code table1[]={
- 7,8,9,0x2f-0x30,
- 4,5,6,0x2a-0x30,
- 1,2,3,0x2d-0x30,
- 0x01-0x30,0,0x3d-0x30,0x2b-0x30};
-
- void delay(uchar z) // 延遲函數
- {
- uchar y;
- for(z;z>0;z--)
- for(y=0;y<110;y++);
- }
-
- void check() // 判斷忙或空閑
- {
- do{
- P0=0xFF;
- rs=0; //指令
- rw=1; //讀
- lcden=0; //禁止讀寫
- delay(1); //等待,液晶顯示器處理數據
- lcden=1; //允許讀寫
- }while(busy==1); //判斷是否為空閑,1為忙,0為空閑
- }
- void write_com(uchar com) // 寫指令函數
- {
- P0=com; //com指令付給P0口
- rs=0;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void write_date(uchar date) // 寫數據函數
- {
- P0=date;
- rs=1;
- rw=0;
- lcden=0;
- check();
- lcden=1;
- }
-
- void init() //初始化
- {
- num=-1;
- lcden=1; //使能信號為高電平
- write_com(0x38); //8位,2行
- write_com(0x0c); //顯示開,光標關,不閃爍*/
- write_com(0x06); //增量方式不移位 顯竟獗暌貧 柚?
- write_com(0x80); //檢測忙信號
- write_com(0x01); //顯示開,光標關,不閃爍
- num_1=0;
- i=0;
- j=0;
- a=0; //第一個參與運算的數
- b=0; //第二個參與運算的數
- c=0;
- flag=0; //flag表示是否有符號鍵按下,
- fuhao=0; // fuhao表征按下的是哪個符號
- }
- void keyscan() // 鍵盤掃描程序
- {
-
- P3=0xfe;
- if(P3!=0xfe)
- {
- delay(20); 延遲20ms
- if(P3!=0xfe)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=0;
- break;
- case 0xd0:num=1;
- break;
- case 0xb0:num=2;
- break;
- case 0x70:num=3;
- break;
- }
- }
- while(P3!=0xfe);
- if(num==0||num==1||num==2)//如果按下的是'7','8'或'9
- {
- if(j!=0)
- {
- write_com(0x01);
- j=0;
- }
- if(flag==0)//沒有按過符號鍵
- {
- a=a*10+table[num];
- }
- else//如果按過符號鍵
- {
- b=b*10+table[num];
- }
- }
- else//如果按下的是'/'
- {
- flag=1;
- fuhao=4;//4表示除號已按
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xfd;
- if(P3!=0xfd)
- {
- delay(5);
- if(P3!=0xfd)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=4;
- break;
-
- case 0xd0:num=5;
- break;
-
- case 0xb0:num=6;
- break;
-
- case 0x70:num=7;
- break;
- }
- }
- while(P3!=0xfd);
- if(num==4||num==5||num==6&&num!=7)//如果按下的是'4','5'或'6'
- {
- if(j!=0)
- {
- write_com(0x01);
- j=0;
- }
- if(flag==0)//沒有按過符號鍵
- {
- a=a*10+table[num];
- }
- else//如果按過符號鍵
- {
- b=b*10+table[num];
- }
- }
- else//如果按下的是'/'
- {
- flag=1;
- fuhao=3;//3表示乘號已按
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xfb;
- if(P3!=0xfb)
- {
- delay(5);
- if(P3!=0xfb)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=8;
- break;
-
- case 0xd0:num=9;
- break;
-
- case 0xb0:num=10;
- break;
-
- case 0x70:num=11;
- break;
- }
- }
- while(P3!=0xfb);
- if(num==8||num==9||num==10)//如果按下的是'1','2'或'3'
- {
- if(j!=0)
- {
- write_com(0x01);
- j=0;
- }
- if(flag==0)//沒有按過符號鍵
- {
- a=a*10+table[num];
- }
- else//如果按過符號鍵
- {
- b=b*10+table[num];
- }
- }
- else if(num==11)//如果按下的是'-'
- {
- flag=1;
- fuhao=2;//2表示減號已按
- }
- i=table1[num];
- write_date(0x30+i);
- }
-
- P3=0xf7;
- if(P3!=0xf7)
- {
- delay(5);
- if(P3!=0xf7)
- {
- temp=P3&0xf0;
- switch(temp)
- {
- case 0xe0:num=12;
- break;
-
- case 0xd0:num=13;
- break;
-
- case 0xb0:num=14;
- break;
-
- case 0x70:num=15;
- break;
- }
- }
- while(P3!=0xf7);
- switch(num)
- {
- case 12:{write_com(0x01);a=0;b=0;flag=0;fuhao=0;}//按下的是"清零"
- break;
- case 13:{ //按下的是"0"
- if(flag==0)//沒有按過符號鍵
- {
- a=a*10;
- write_date(0x30);
- P1=0;
- }
- else if(flag==1)//如果按過符號鍵
- {
- b=b*10;
- write_date(0x30);
- }
- }
- break;
- case 14:{j=1;
- if(fuhao==1){write_com(0x80+0x4f);//按下等于鍵,光標前進至第二行最后一個顯示處
- write_com(0x04); //設置從后住前寫數據,每寫完一個數據,光標后退一格
- c=a+b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d); //再寫"="
- a=0;b=0;flag=0;fuhao=0;
- }
- else if(fuhao==2){write_com(0x80+0x4f);//光標前進至第二行最后一個顯示處
- write_com(0x04); //設置從后住前寫數據,每寫完一個數據,光標后退一格(這個照理說順序不對,可顯示和上段一樣)
- if(a-b>0)
- c=a-b;
- else
- c=b-a;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- if(a-b<0)
- write_date(0x2d);
- write_date(0x3d); //再寫"="
- a=0;b=0;flag=0;fuhao=0;
- }
- else if(fuhao==3){write_com(0x80+0x4f);
- write_com(0x04);
- c=a*b;
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- }
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- else if(fuhao==4){write_com(0x80+0x4f);
- write_com(0x04);
- i=0;
- c=(long)(((float)a/b)*1000);
- while(c!=0)
- {
- write_date(0x30+c%10);
- c=c/10;
- i++;
- if(i==3)
- write_date(0x2e);
- }
- if(a/b<=0)
- write_date(0x30);
- write_date(0x3d);
- a=0;b=0;flag=0;fuhao=0;
- }
- }
- break;
- case 15:{write_date(0x30+table1[num]);flag=1;fuhao=1;}
- break;
- }
- }
- }
-
- main()
- {
- init();
- ………余下代碼請下載附件………
-
復制代碼
完整的課程設計報告(論文)下載:
單片機計算器課程設計報告.doc
(154 KB, 下載次數: 82)
2017-5-25 13:13 上傳
點擊文件名下載附件
課設報告 下載積分: 黑幣 -5
|