|
矩陣鍵盤+數碼管顯示組成的一個簡易計算器單片機項目
下面是單片機計算器的proteus仿真原理圖(工程文件可到本帖附件中下載):
0.png (31.7 KB, 下載次數: 112)
下載附件
2017-5-7 21:43 上傳
單片機計算器源程序如下:
- //#include <reg51.h>
- # include <STC12C5A60S2.h>
- # define uchar unsigned char
- # define uint32 unsigned long int
- # define sint32 signed long int
- # define vtime 3000 //定時3ms,一幀8*3=24ms,頻率=40Hz
- //共陰數碼管段碼表
- uchar code distable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0X00,0x40,0x31};
- //位選碼表
- uchar code numi[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
- //顯示緩存
- uchar V_ram[]={0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10};
- uchar error=0,wi=0,dot1=0,dot2=0,dot=0xff; //位選循環變量
- uint32 num1=0,num2=0,num=0,sum=0;
- void dispsum();
- void delay(uchar);
- uchar scan_key();
- main() //m1:m0 00=標準; 01=推挽; 10=輸入; 11=開漏輸出
- {
- uchar ni,nj,fn='+',key_V=0,dotp=0,j,k,i=0;
- uint32 temp=0;
- //m1:m0 00=標準; 01=推挽; 10=輸入; 11=開漏輸出
- P1M1 = 0X0f;
- P1M0 = 0XF0; //設定低4位為輸入,高4位為輸出
- P0M1 = 0X00;
- P0M0 = 0Xff;
- P2M1 = 0X00;
- P2M0 = 0Xff; //設定P0,P2推挽輸出
- TMOD = 0X01; //設定定時器0為16位計數方式
- TH0 = (65536-vtime )/256;
- TL0 = (65536-vtime )%256; //賦定時器0初值
- ET0 = 1; //開定時器0中斷
- EA = 1; //開總中斷
- TR0 = 1; //啟動定時器0計數
- //sum=123456;
- while(1)
- {
- key_V=scan_key();
- //dispsum();
- if(key_V)
- {
- //有鍵按下
- key_V--;
- switch(key_V)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- if((num+i)==0)
- { //如果是第一個數字輸入,則清黑屏
- dot=0xff; //關閉小數點
- for(j=0;j<8;j++)
- V_ram[j]=0x10; //清黑屏
- }
- num=num*10+key_V; //鍵盤輸入的數字轉化為十進制的數值
- if(i==8) //如果顯示緩沖滿了
- {
- i=7;
- for(j=0;j<7;j++)
- V_ram[j]=V_ram[j+1];//顯示緩存串行移位
- }
- V_ram[i]=key_V; //鍵值放入顯示緩存
- i++;
- break;
- case 10: //dot 小數點符號
- dotp=i; //記錄下小數點位置
- dot=dotp-1; //顯示小數點
- break;
- case 11: //+ 加法符號
- for(j=0;j<8;j++)
- V_ram[j]=0x10; //清黑屏
- num1=num; //獲取從鍵盤輸入的第一個數值
- if(dotp==0)
- {
- dot1=0;
- }
- else
- {
- dot1=i-dotp;
- }
- ni=i;
- dotp=0;
- dot=0xff;
- num=0;
- fn='+';
- i=0;
- break;
- case 12: //- 減法符號
- for(j=0;j<8;j++)
- V_ram[j]=0x10; //清黑屏
- num1=num; //獲取從鍵盤輸入的第一個數值
- if(dotp==0)
- {
- dot1=0;
- }
- else
- {
- dot1=i-dotp;
- }
- ni=i;
- dotp=0;
- dot=0xff;
- num=0;
- fn='-';
- i=0;
- break;
- case 13: //* 乘法符號
- for(j=0;j<8;j++)
- V_ram[j]=0x10; //清黑屏
- num1=num; //獲取從鍵盤輸入的第一個數值
- if(dotp==0)
- {
- dot1=0;
- }
- else
- {
- dot1=i-dotp;
- }
- ni=i;
- dotp=0;
- dot=0xff;
- num=0;
- fn='*';
- i=0;
- break;
- case 14: // / 除法符號
- for(j=0;j<8;j++)
- V_ram[j]=0x10; //清黑屏
- num1=num; //獲取從鍵盤輸入的第一個數值
- if(dotp==0)
- {
- dot1=0;
- }
- else
- {
- dot1=i-dotp;
- }
- ni=i;
- dotp=0;
- dot=0xff;
- num=0;
- fn='/';
- i=0;
- break;
- case 15: //= 等于符號
- if(dotp==0) //計算第二個運算數的小數位數
- {
- dot2=0;
- }
- else
- {
- dot2=i-dotp;
- }
- dotp=0;
- nj=i;
- temp=1;
- if(fn!='*')
- { if(dot1>dot2) //第一個運算數與第二個運算進行對齊
- {
- for(j=dot1-dot2;j>0;j--)
- {
- //if(num>0x19999999)error=1;
- num=num*10;
- nj++;
- if(nj>9)
- {
- j--;
- for(k=j;k>0;k--)
- num1=num1/10;
- dot1=dot1-j;
- break;
- }
- }
- }
- else
- {
- for(j=dot2-dot1;j>0;j--)
- {
- //if(num1>0x19999999)error=1;
- num1=num1*10;
- ni++;
- if(ni>9)
- {
- j--;
- for(k=j;k>0;k--)
- num=num/10;
- dot2=dot2-j;
- break;
- }
- }
- }
- }
- //準備好后,進行運算
- if(fn=='+') //做加法運算
- {
- sum=num+num1;
- if(sum<(num|num1))error=1;
- dispsum(); //顯示對齊后的運算結果
- if(dot2>dot1) //顯示實際小數點的位置
- dot=dot-dot2;
- else
- dot=dot-dot1;
- i=0; //計算結束,初始化關鍵變量
- num1=0;
- num=0;
- break;
- }
- if(fn=='-') //做減法運算
- {
- if(num1<num) //判斷結果是負還是正
- {
- sum=num-num1;
- }
- else
- sum=num1-num;
- dispsum(); //顯示對齊后的運算結果
- if(num>num1) //是負數則第一位顯示“-”,其它位順序往后顯示
- {
- for(j=7;j>0;j--)
- V_ram[j]=V_ram[j-1]; //順序往后顯示
- V_ram[0]=0x11; //第一位顯示“-”
- dot++; //小數點也順延一位
- }
- if(dot2>dot1) //顯示實際小數點的位置
- dot=dot-dot2;
- else
- dot=dot-dot1;
- i=0; //計算結束,初始化關鍵變量
- num1=0;
- num=0;
- break;
- }
- if(fn=='*') //做乘法運算
- {
- sum=num1*num;
- if((ni+nj)>10)error=1;
- dispsum(); //顯示對齊后的運算結果
- //if(dot2>dot1) //顯示實際小數點的位置
- dot=dot-dot2-dot1;
- //else
- // dot=dot-dot1-dot1;
- i=0; //計算結束,初始化關鍵變量
- num1=0;
- num=0;
- break;
- }
- if(fn=='/') //做除法運算
- {
- sum=num1/num;
- dispsum(); //顯示對齊后的運算結果,對于除法,就是實際結果
- temp=num1%num; //顯示小數部分
- for(j=dot;j<7;j++)
- {
- temp=temp*10;
- V_ram[j+1]=temp/num;
- temp=temp%num;
- if(temp==0)break;
- }
- i=0; //計算結束,初始化關鍵變量
- num1=0;
- num=0;
- break;
- }
- break;
-
- default:
- break;
- }
- delay(200);//延時去抖
- }
-
- }
- }
- void t0_isp() interrupt 1
- {
- uchar dm,wx;
- TH0 = (65536-vtime )/256;
- TL0 = (65536-vtime )%256; //賦定時器0初值
- dm=distable[V_ram[wi]]; //取顯示段碼
- wx=numi[wi]; //取位選碼
- P2=0x00; //關顯示
- //P0=dm; //段碼賦給P0口
- if(dot==wi)
- {
- P0=dm|0x80; //點亮位選的那個數碼管+小數點
- }
- else
- {
- P0=dm; //點亮位選的那個數碼管
- }
- P2=wx;
- wi++;
- if(wi==8)wi=0;
- }
- /////////////////////////////////////
- uchar scan_key()
- {
- uchar i,j,vlume=0,temp[4]={0xef,0xdf,0xbf,0x7f};
- for(j=0;j<4;j++)
- {
- P1=temp[j];
- i=P1|0xf0;
- if(i != 0xff) //判斷按鍵
- { //有鍵按下
- i=~i;
- if(i==4)i=3;
- if(i==8)i=4;
- i--; // 計算按鍵所在行號(0--3)
- vlume=i*4+j+1; //計算鍵值
- //delay(200);//延時去抖
- }
- }
- return vlume;
- }
- ////////////////////////////////////////
- void delay(uchar k )
- {
- uchar x,y,z;
- for(x=k;x>0;x--)
- for(y=20;y>0;y--)
- for(z=250;z>0;z--);
- }
- ////////////////////////////////////////
- void dispsum()
- {
- uchar temp[10]=0,k,j;
- uint32 temp1;
- if(error==1)
- {
- V_ram[0]=0x0e;
- V_ram[1]=0x12;
- for(j=2;j<8;j++)
- V_ram[j]=0x10; //清黑屏
- dot=0xff;
- error=0;
- num=0;
- return;
- }
- temp1=sum;
- for(k=0;k<10;k++)
- {
-
- temp[k]=temp1%10; // sum的個位開始放入temp數組,最多可放10位
- temp1=temp1/10; //
- if(temp1==0)
- { // 如果商為零
- dot=k; //當前位小數點點亮
- for(j=0;j<8;j++)
- {
- if(k==0xff)
- {
- V_ram[j]=0x10; // 清黑屏
- }
- else
- {
- V_ram[j]=temp[k]; // 把sum中的數從高位依次放入顯示緩存
- k--;
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
最后給大家分享一些我們老師給的一些經典的單片機程序源碼, 一共有十多個.都有詳細的注釋,然大家快速的理解每一行代碼的意思。而且有proteus仿真原理圖。大家可以直接驗證程序的對錯.

本系列所有源碼打包下載地址(含proteus仿真工程文件和源程序):
http://www.zg4o1577.cn/bbs/dpj-82474-1.html
本例程下載:
計算器.rar
(100.85 KB, 下載次數: 89)
2017-5-7 21:43 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|
|