本設計是以STC89C52單片機為核心的計算器模擬系統設計,輸入采用5×8矩陣鍵盤,可以進行加、減、乘、除等十幾種數字運算,同時支持括號的嵌套使用級浮點數的運算,并在LCD1602上顯示操作過程。 本次設計注重設計方法及流程,首先根據原理設計電路,利用keil編程,借助實驗開發平臺進行仿真實驗,進而利用altium designer 制作PCB,最后到焊接元器件,直至調試成功。在設計的同時,特別注重keil軟件和altium designer軟件的使用方法和技巧以及常用的LCD顯示器和矩陣鍵盤的設計和使用方法。
Altium Designer畫的原理圖和PCB圖如下:(51hei附件中可下載工程文件)
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
制作出來的實物圖如下:
單片機源程序如下:
- #include <REGX51.H>
- #include<intrins.h>
- #include<stdio.h>
- #include<string.h>
- #include<math.h>
- sbit RS = P2^5;
- sbit RW = P2^6;
- sbit E = P2^7;
- #define Data P0//數據端口
- //全局變量
- float num1;//第一操作數num1 (初始為零)
- float num2;//第二操作數num2 (初始為零)
- char yun_flag='+';//運算符號 yun_flag (默認為+ )
- char key_last;//上次按鍵狀態標志 key_last
- char sqrt_flag;//開方鍵按下標志 sqrt_flag
- unsigned long pos_flag=1;//小數位權pos_flag (默認為1)
- char neg_flag;//正負標志 neg_flag
- char data c_num1[15]=" ";//c_num1 字符型第一操作數 (數組不定義大小與其他變量沖突)
- char data c_num2[15]=" ";//c_num2 字符型第二操作數
- char error;//運算法則錯誤;
- char len;//小數點后位數
- /* 微秒延時函數 */
- /******************************************************************/
- void DelayUs(unsigned char us)//delay us
- {
- unsigned char uscnt;
- uscnt=us>>1; /*12MHz頻率*/
- while(--uscnt);
- }
- /******************************************************************/
- /* 毫秒函數聲明 */
- /******************************************************************/
- void DelayMs(unsigned char ms)
- {
- while(--ms)
- {
- DelayUs(250);
- DelayUs(250);
- DelayUs(250);
- DelayUs(250);
- }
- }
- /******************************************************************/
- /* 寫入命令函數 */
- /******************************************************************/
- void WriteCommand(unsigned char c)
- {
- DelayMs(5);//操作前短暫延時,保證信號穩定
- E=0;
- RS=0;
- RW=0;
- _nop_();
- E=1;
- Data=c;
- E=0;
- }
- /******************************************************************/
- /* 寫入數據函數 */
- /******************************************************************/
- void WriteData(unsigned char c)
- {
- DelayMs(5); //操作前短暫延時,保證信號穩定
- E=0;
- RS=1;
- RW=0;
- _nop_();
- E=1;
- Data=c;
- E=0;
- RS=0;
- }
- /******************************************************************/
- /* 寫入字節函數 */
- /******************************************************************/
- void ShowChar(unsigned char pos,unsigned char c)
- {
- unsigned char p;
- if (pos>=0x10)
- p=pos+0xb0; //是第二行則命令代碼高4位為0xc
- else
- p=pos+0x80; //是第二行則命令代碼高4位為0x8
- WriteCommand (p);//寫命令
- WriteData (c); //寫數據
- }
- /******************************************************************/
- /* 寫入字符串函數 */
- /******************************************************************/
- void ShowString (unsigned char line,char *ptr)
- {
- unsigned char l,i;
- l=line<<4;
- for (i=0;*(ptr+i)!='\0';i++)
- ShowChar (l++,*(ptr+i));//循環顯示16個字符
- }
- /******************************************************************/
- /* 初始化函數 */
- /******************************************************************/
- void InitLcd()
- {
- DelayMs(15);
- WriteCommand(0x38); //display mode
- WriteCommand(0x38); //display mode
- WriteCommand(0x38); //display mode
- WriteCommand(0x06); //顯示光標移動位置
- WriteCommand(0x0c); //顯示開及光標設置
- WriteCommand(0x01); //顯示清屏
- }
- /*************按鍵掃描****************************/
- char scan()
- {
- char h_data,l_data,i,key_num;
- P2=P2&0XE0;//P2低5位送0
- P1=P1|0X0F;//P1低4位送1
- while((P1|0xf0)==0xff)//判斷P1低4位是否全為1
- {
- while((P1|0xf0)==0xff);
- DelayMs(10);//延時10ms
- }
- l_data=~(P1|0xf0);//記入列標志
- P2=P2|0X1F;//P2低五位送1
- P1=P1&0XF0;//P1低四位送0
- h_data=~(P2|0xe0);//記入行標志
- for(i=0;i<=4;i++)//計算行號(0~4)
- {
- if(h_data==1)break;
- h_data=h_data>>1;
- }
- h_data=i;//行號
- for(i=1;i<=4;i++)//計算列號(1~4)
- {
- if(l_data==1)break;
- l_data=l_data>>1;
- }
- l_data=i;//列號
- key_num=h_data*4+l_data;
-
- P2=P2&0XE0;//P2低5位送0
- P1=P1|0X0F;//P1低4位送1
- while((P1|0xf0)!=0xff)//判斷P1低4位是否全為1
- {
- while((P1|0xf0)!=0xff);
- DelayMs(10);//延時10ms
- }
- return key_num;
- }
- void float_to_char(float a,char* p)
- {
- char i,flag,length;
- flag=0;
- sprintf(p,"%f",a);
- length=strlen (p);
- for(i=0;i<length;i++)
- {
- if(*(p+i)=='.')flag=1;
- }
- if(flag==1)
- for(i=length-1;i>=0;i--)
- {
- if(*(p+i)=='.'){*(p+i)='\0';break;}
- if(*(p+i)!='0'){*(p+i+1)='\0';break;}
- }
- }
- /**********************更新液晶*************************/
- void refresh()//更新液晶
- {
- char length,i,j;
- char dot;
- dot=0;
-
- float_to_char(num2,c_num2);//num2轉為字符型
- length=strlen(c_num2);
- for(i=0,j=0;i<length;i++)
- {
- if(c_num2[i]=='.')
- dot=1;
- if(dot==1)
- j++;
- }
- if(j<len)
- {
- if(dot==1)
- {
- for(i=length;i<(length+len-j);i++)
- {
- c_num2[i]='0';
-
- }
- c_num2[i]='\0';
- }
- else
- {
-
- c_num2[length]='.';
- if(len-j>1)
- {
- for(i=length+1;i<(length+len-j);i++)
- c_num2[i]='0';
- }
- c_num2[length+len-j]='\0';
- }
- }
- if(neg_flag==1)//'+/-'按下首位加‘-’
- {
- length=strlen(c_num2);//計算c_num2長度
- for(i=length-1;i>=0;i--)
- {
- c_num2[i+1]=c_num2[i];
- }
- c_num2[length+1]='\0';
- c_num2[0]='-';
- }
-
- if(sqrt_flag==1)
- {
- length=strlen(c_num2);//計算c_num2長度
- for(i=length-1;i>=0;i--)
- {
- c_num2[i+1]=c_num2[i];
- }
- c_num2[length+1]='\0';
- c_num2[0]=0xe8;//字符根號
- }
-
-
- if(error==0)
- {
- float_to_char(num1,c_num1);//num1轉為字符型
- WriteCommand(0x01); //顯示清屏
- ShowString(0,c_num1);
- ShowString(1,c_num2);
- ShowChar(15,yun_flag);
- }else
- {
- WriteCommand(0x01); //顯示清屏
- ShowString(0,"error!!!");
- }
- }
- //鍵值處理
- void operation1(char keynum)//按下 ’+、-、*、/處理
- {
- if(key_last==1)//上次按鍵為 數字、小數點、+/-、sqrt
- {
- if(neg_flag==1)num2=-num2;//'+/-'按下
- if(sqrt_flag==1)//sqrt按下
- {
- if(num2>=0)
- num2=sqrt(num2);
- else
- error=1;
- }
- if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
- if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
- if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
- if(yun_flag=='/')//按下的是‘/’
- {
- if(num2!=0)
- num1=num1/num2;
- else
- error=1;
- }
- num2=0;//num2清零
- sqrt_flag=0;//sqrt_flag清零
- neg_flag=0;//neg_flag清零
- pos_flag=1;//pos_flag回1
- }
- if(keynum==4)yun_flag='+';//yun_flag更新
- if(keynum==8)yun_flag='-';
- if(keynum==12)yun_flag='*';
- if(keynum==16)yun_flag='/';
- len=0;
- key_last=0;//key_last更新
- refresh();
- }
- //////////////////////////////////////////////////////
- void operation2(char keynum)//輸入數字
- {
- float Data1;
-
- if(keynum==1)Data1=7;//分析輸入數字
- if(keynum==2)Data1=8;
- if(keynum==3)Data1=9;
- if(keynum==5)Data1=4;
- if(keynum==6)Data1=5;
- if(keynum==7)Data1=6;
- if(keynum==9)Data1=1;
- if(keynum==10)Data1=2;
- if(keynum==11)Data1=3;
- if(keynum==13)Data1=0;
- if(pos_flag==1)//更新num2
- num2=num2*10+Data1;
- else
- {
- num2=num2+(Data1/pos_flag);
- pos_flag=pos_flag*10;
- len++;
- }
- key_last=1;//更新key_last
- refresh();
- }
- ////////////////////////////////////////////////////////////
- void operation3()//輸入小數點
- {
- if(pos_flag==1)//首次出現小數點
- {
- pos_flag=pos_flag*10;//小數位權*10
- len++;
- }
- key_last=1;//更新key_last
- refresh();//更新液晶
- }
- /////////////////////////////////////////////////////
- void operation4()//輸入'='
- {
- if(neg_flag==1)num2=-num2;//'+/-'按下
- if(sqrt_flag==1)//sqrt按下
- {
- if(num2>=0)
- num2=sqrt(num2);
- else
- error=1;
- }
- if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
- if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
- if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
- if(yun_flag=='/')//按下的是‘/’
- {
- if(num2!=0)
- num1=num1/num2;
- else
- error=1;
- }
- num2=0;//num2清零
- sqrt_flag=0;//sqrt_flag清零
- neg_flag=0;//neg_flag清零
- pos_flag=1;//pos_flag回1
- yun_flag='+';//yun_flag更新
- len=0;
- key_last=0;//key_last更新
- refresh();
- }
- ////////////////////////////////////////////////////
- void operation5()//輸入clear all
- {
- num1=0;// num1清零
- num2=0;//num2清零
- sqrt_flag=0;//清sqrt_flag
- neg_flag=0;// 清neg_flag
- pos_flag=1;// Pos_flag=1
- yun_flag='+';// yun_flag(為'+')
- error=0;//清error
- len=0;
- key_last=0;//更新key_flag
- refresh();//更新液晶
- }
- ///////////////////////////////////////////////////////
- void operation6()//輸入'C'
- {
- num2=0;//num2清零
- sqrt_flag=0;//清sqrt_flag
- neg_flag=0;//清neg_flag
- pos_flag=1;//pos_flag=1
- len=0;
- key_last=0;//key_last
- refresh();//更新液晶
- }
- ////////////////////////////////////////////////////////////
- void operation7()//輸入'+/-'
- {
- if(neg_flag==0)//neg_flag反轉
- neg_flag=1;
- else neg_flag=0;
- key_last=1;//key_last
- refresh();// 更新液晶
- }
- /////////////////////////////////////////////////////////////
- void operation8()//輸入'sqrt'
- {
- if(sqrt_flag==0)//sqrt_flag反轉
- sqrt_flag=1;
- else sqrt_flag=0;
- key_last=1;//更新key_last
- refresh();//更新液晶
- }
- //鍵值分析
- void key(char keynum)
- {
- switch(keynum)
- {
- case 4 :
- case 8 :
- case 12:
- case 16://+、-、*、/
- {
- if(error==0)
- operation1(keynum);
- break;}
-
- case 1 : //數字7
- case 2 : //數字8
- case 3 : //數字9
- case 5 : //數字4
- case 6 : //數字5
- case 7 : //數字6
- case 9 : //數字1
- case 10 : //數字2
- case 11 : //數字3
- case 13 : //數字0
- {
- if(error==0)
- operation2(keynum);
- break;}
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
計算器 5乘4.7z
(3.74 MB, 下載次數: 108)
2020-3-13 21:03 上傳
點擊文件名下載附件
|