摘要:計算器是我們生活中常用的工具,在我們生活中不可或缺。本次設計是設計一個算術型計算器,該計算器能夠完成簡單的四則運算,還可以實現連續運算。本次是以51單片機為運算核心,以LCD1602為顯示的進行硬件上的設計,在軟件上以Keil4進行軟件編程,以Proteus進行仿真調試,設計出一個能夠完成簡單的四則運算,實現連續運算的小型算術型計算器。
正文:
一、設計概述
1. 課題意義
計算器有鍵盤部分、單片機、顯示部分三部分組成,鍵盤部分主要完成輸入功能;單片機主要完成數據處理功能,包括確定按鍵,完成運算,以及輸出數據;顯示器部分主要完成單片機輸出的顯示。基本掌握計算器的設計原理和LCD1602的顯示原理,進而熟悉C51的編程和調試方法。
2. 系統功能
能夠完成簡單的四則運算,還可以實現連續運算的小型算術型計算器。
硬件設計上通過Proteus進行電路原理圖和仿真運行圖的設計,軟件設計上以Keil4為基礎進行軟件編程,將編程生成的.hex文件放入在Proteus已畫好的原理圖中調試,觀察設計結果,并對代碼進行修改。
二、硬件設計
[size=9.0000pt] 圖1 [size=9.0000pt]總原理圖
1.按鍵設計
矩陣鍵盤的原理是見I/O口分為行線和列線,按鍵設置在跨接行線和列線的交點上,列線通過上拉電阻接正電源,進而形成基本的4x4行列式鍵盤。本次設計以矩陣鍵盤為基本的輸入按鍵分別為1,2,3,+,4,5,6,-,7,8,9,x,0,CLR,=,/ 形成計算器對應的基本的數字鍵和功能鍵
顯示設計
LCD1602是一種專門用來顯示字母、數字、符號等的點陣型液晶模塊,它由若干個5X7或者5X11等點陣字符位組成,每個點陣字符位都可以顯示一個字符,每位之間有一個點距的間隔,每行之間也有間隔,起到了字符間距和行間距的作用,因此它比較適合用在計算器的顯示。
三、軟件設計
1. 按鍵掃描
本次設計中在軟件上使用了反轉法進行按鍵的掃描,其過程為先讓行輸出全為0列輸出全為1讀取與按鍵相接的P1口的狀態,讀取按鍵的列值,然后讓行輸出全為1列輸出全為0讀取與按鍵相接的P1口的狀態,讀取按鍵的行值,根據行值和列值可知其鍵值。
[size=9.0000pt] 圖4按鍵掃描流程圖[size=9.0000pt]
2.顯示設計
LCD1602是一個16字雙行的顯示模塊,在使用LCD1602之前我們應該先對其進行初始化,其初始化的內容有光標設置、顯示設置和清屏指令等。初始化完成后從其參考手冊可知LCD1602中已經存儲有基本字模數據,所以想要在LCD1602中顯示字符,只需要對LCD1602寫入該字符相對應的ASCII碼即可顯示出相應的字符。LCD1602的寫入可分為寫數據和寫命令,當要寫入數據時其對應的狀態為RS=1,RW=0,E為下降沿,然后通過單片機I/O口寫入相應的數據。當要寫入命令時其對應的狀態為RS=0,RW=0,E為下降沿,然后通過單片機I/O口寫入相應的命令。
[size=9.0000pt]圖5 LCD1602寫指令圖
3.鍵值處理
首先我們初始化液晶顯示器,然后顯示出第一個被按下的數,并且使光標右移,如果有第二個數按下,則據繼續顯示,以此類推,然后把所有顯示出來的數換算成一個數,如果按下“+”號,則顯示出“+”,并且同理顯示出“+”號后面按下的數字,然后調用加子程序,運算出結果,如果按下的是“-”,則調用減子程序,如果按下“*”,則調用乘子程序,如果按下“/”,則調用除子程序。然后再調用顯示結果子程序,顯示出結果。
圖6鍵值運算流程圖
四、系統測試
1.加法測試
2.減法測試
3.乘法測試
4.除法測試
5.連續運算測試
五、結論
經過調試可知此次設計已經基本達到要求,該計算器能夠完成簡單的四則運算,還可以實現連續運算。但只能進行整數的運算,無法進行浮點型數據運算,運算的連續運行需要一個個數的連續運算,無法做到一次性連續運算。
七、附錄
1.系統電路圖
2.實物運行圖
單片機源程序如下:
- /* 實現兩個數的運算,每個數的位數至少可以八位 */
- #include<reg52.h>
- #include<math.h>
- typedef unsigned char uint8;
- typedef unsigned int uint16;
- #define GPIO_KEY P1
- sbit rw=P2^5;
- sbit rs=P2^6;
- sbit e=P2^7;
- sbit k1=P3^0;
- uint8 num='N'; //鍵值
- uint16 k0,k2,k3; // 數組位
- uint8 fuhao; //定義具體的那個符號,是加減還是乘除。
- uint8 flag,r; //定義符號鍵標志位,小數點標志位和繼續運算標志位 這個是統稱
- float a,b,c,zheng,xiao; //定義運算數據的第一個和第二個及等于的數變量
- uint8 shuzi1[5]={0},shuzi2[5]={0},shuzi3[4]={0};
- uint8 code dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x78-0x30, 0,0x2e-0x30,0x3d-0x30,0xfd-0x30 };//保存顯示的數據 123+ 456- 789* 0.CLR /
- void delay(uint16 i)
- { uint16 x,y;
- for(x=0;x<i;x++)
- for(y=0;y<114;y++);
- }
- void lcdcommand(uint8 m) //寫命令
- {
- delay(1);
- rs=0;
- rw=0;
- e=0;
- P0=m;
- e=1;
- delay(1);
- e=0;
- }
- void lcddata(uint8 dat) //寫數據
- {
- delay(1);
- rs=1;
- rw=0;
- e=0;
- P0=dat;
- e=1;
- delay(1);
- e=0;
- rs=0;
- }
- void lcdcsh() //初始化
- {
- delay(5);
- lcdcommand(0x38); //功能設定 8位總線 兩行 5X7點陣
- delay(5);
- lcdcommand(0x38);
- lcdcommand(0x38);
- lcdcommand(0x0c); // 開顯示 無光標
- lcdcommand(0x06); //光標左移
- lcdcommand(0x01); // 清屏
- lcdcommand(0x80);//數據從左上開始
- num='N';
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;;
- k0=0;k2=0;k3=0;
- }
- void shuchu(float e) //在屏幕上顯示數值e
- {
- char shuzu[10];
- long z;
- int x=0;
- float f;
-
- (long)z=e; //整數處理
- if(z==0)
- lcddata('0');
- while(z!=0)
- { shuzu[x]=z%10;
- z=z/10;
- x++;
- }
- for(x=x-1;x>=0;x--)
- lcddata(shuzu[x]+0x30);
- (long)z=e; //小數處理
- (float)f=e-z;
- if(f>0.000)
- { x=0;
- lcddata('.');
- z=f*1000;
- while(z!=0)
- { shuzu[x]=z%10;
- z=z/10;
- x++;
- }
- for(x=x-1;x>=0;x--)
- lcddata(shuzu[x]+0x30);
- }
- }
- void fuzhi() // 顯示與向數組賦值
- {
-
- if(flag==0) //是否按下符號鍵
- {
- delay(50);
- if(dat1[num]=='.')
- r=1;
- if((r==0)&&(k0<5))
- {
- shuzi1[k0]=dat1[num];
- k0++;
- lcddata(0x30+dat1[num]);
- }
- else if((r==1)&&(k3<4))
- {
-
- shuzi3[k3]=dat1[num];
- k3++;
- lcddata(0x30+dat1[num]);
- }
- }
- r=0;
- if(flag==1) //是否按下符號鍵
- {
- delay(50);
- if(dat1[num]=='.')
- r=1;
- if((r==0)&&(k2<5))
- {
- shuzi2[k2]=dat1[num];
- k2++;
- lcddata(0x30+dat1[num]);
- }
- else if((r==1)&&(k3<4))
- {
-
- shuzi3[k3]=dat1[num];
- k3++;
- lcddata(0x30+dat1[num]);
- }
- }
- }
- void sz(uint8 s[8],int x) //數組轉為數值
- {
- int i,j;
- zheng=0;
- xiao=0;
- i=0; //整數
- while(x>0)
- {
- zheng=zheng*10+s[i];
- i++;
- x--;
- }
- i=1; //小數
- j=k3;
- while(j>0)
- {
- xiao=xiao*10+s[i];
- i++;
- j--;
- }
-
- for(;k3>0;k3--)
- xiao=xiao/10;
- zheng=zheng+xiao;
- k0=k2=k3=0;
- }
- void KeyDown(void)
- {
- char L=0;
- GPIO_KEY=0x0f;
- if(GPIO_KEY!=0x0f)//讀取按鍵是否按下
- {
- delay(10);//延時10ms進行消抖
- if(GPIO_KEY!=0x0f)//再次檢測鍵盤是否按下
- {
- //測試列
- GPIO_KEY=0X0F;
- switch(GPIO_KEY)
- {
- case(0X07): num=0;break;
- case(0X0b): num=1;break;
- case(0X0d): num=2;break;
- case(0X0e): num=3;break;
- }
- //測試行
- GPIO_KEY=0XF0;
- switch(GPIO_KEY)
- {
- case(0X70): num=num;break;
- case(0Xb0): num=num+4;break;
- case(0Xd0): num=num+8;break;
- case(0Xe0): num=num+12;break;
- }
- while((L<50)&&(GPIO_KEY!=0xf0)) //檢測按鍵松手檢測
- {
- delay(10);
- L++;
- }
- }
- }
- }
- void banduan()
- {
- switch(fuhao)
- {
- case 0:
- sz(shuzi1,k0);
- a=zheng;
- lcdcommand(0x01);
- lcdcommand(0x40+0x80);
- shuchu(a);
- b=0;
- flag=0;
- fuhao=0; //全部清除為0
- zheng=0;
- xiao=0;
- break;
- case 1:
-
- lcdcommand(0x40+0x80);
- c=a+b;
- lcddata(0x3d); //顯示等于號=
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除為0
- zheng=0;
- xiao=0;
- break;
- case 2:
- lcdcommand(0x40+0x80);
-
- if(a>b)
- { c=a-b;
- lcddata(0x3d); //顯示等于號=
- }
- else if(a<b)
- {
- c=b-a;
- lcddata(0x3d); //顯示等于號=
- lcddata(0x2d); //顯示負號-
- }
- if(a==b)
- c=0;
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除為0
- zheng=0;
- xiao=0;
- break;
- case 3:
- lcdcommand(0x40+0x80);
- c=a*b;
- lcddata(0x3d); //顯示等于號=
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除為0
- zheng=0;
- xiao=0;
- break;
- case 4:
- lcdcommand(0x40+0x80);
- c=a/b;
- lcddata(0x3d); //顯示等號
- shuchu(c);
- a=0;
- b=0;
- flag=0;
- fuhao=0; //全部清除為0
- zheng=0;
- xiao=0;
-
- break;
- }
-
- }
- void main()
- {
-
-
-
- lcdcsh();
- while(1)
- { num='N';
- KeyDown();
- if(num==13)
- {
- lcdcommand(0x01);//清零
-
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;
- k0=k2=k3=0;
- }
- while(1)
- {
- num='N';
- KeyDown();
- if(num==0||num==1||num==2||num==4||num==5||num==6||num==8||num==9||num==10||num==12||num==16) //1-9-0-.
- fuzhi();
- if(num==13)
- {
- lcdcommand(0x01);//清零
-
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;
- k0=k2=k3=0;
- break;
- }
- if(num==3||num==7||num==11||num==15)
- {
-
- flag=1;
- switch(num)
- { case 3: fuhao=1; break;
- case 7: fuhao=2; break;
- case 11: fuhao=3; break;
- case 15: fuhao=4; break;
- }
- sz(shuzi1,k0);
- c=zheng;
- loop: a=c;
- lcdcommand(0x01);
- lcdcommand(0x80);
- shuchu(a);
- lcddata(0x30+dat1[num]);
- break;
- }
- }
-
- while(1)
- {
- num='N';
- KeyDown();
- if(num==0||num==1||num==2||num==4||num==5||num==6||num==8||num==9||num==10||num==12) //1-9-0
- fuzhi();
- if(num==13)
- {
- lcdcommand(0x01);//清零
-
- flag=0;
- fuhao=0;
- a=0;
- b=0;
- c=0;
- zheng=xiao=0;
- k0=k2=k3=0;
- break;
-
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有程序51hei提供下載:
1.c.zip
(2.41 KB, 下載次數: 129)
2019-10-10 18:38 上傳
點擊文件名下載附件
程序清單
|