找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 12582|回復(fù): 17
打印 上一主題 下一主題
收起左側(cè)

基于51單片機(jī)的多功能計(jì)算器全套設(shè)計(jì)資料下載(PCB+源碼+仿真+論文)

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
lcd1602 51單片機(jī)計(jì)算器 5*4鍵盤(pán)掃描,下面是制作出來(lái)的實(shí)物圖:

圖3.2 浮點(diǎn)數(shù)運(yùn)算





全部資料51hei下載地址:
計(jì)算器 5乘4.zip (5.75 MB, 下載次數(shù): 640)




單片機(jī)課程設(shè)計(jì)
設(shè)計(jì)課題     基于51單片機(jī)的多功能計(jì)算器設(shè)計(jì)
【摘要】 當(dāng)今社會(huì),隨著人們物質(zhì)生活的不斷提高,電子產(chǎn)品已經(jīng)走進(jìn)了家家戶(hù)戶(hù),無(wú)論是生活或?qū)W習(xí),還是娛樂(lè)和消遣幾乎樣樣都離不開(kāi)電子產(chǎn)品,大型復(fù)雜的計(jì)算能力是人腦所不能勝任的,而且人腦比較容易出錯(cuò)。計(jì)算器作為一種快速通用的計(jì)算工具方便了用戶(hù)的使用。計(jì)算器可謂是我們最親密的電子伙伴之一。本設(shè)計(jì)著重在于分析計(jì)算器設(shè)計(jì)開(kāi)發(fā)過(guò)程中的環(huán)節(jié)和步驟,并從實(shí)踐經(jīng)驗(yàn)出發(fā)對(duì)計(jì)算器設(shè)計(jì)做了詳細(xì)的分析和研究。
本設(shè)計(jì)是以STC89C52單片機(jī)為核心的計(jì)算器模擬系統(tǒng)設(shè)計(jì),輸入采用5×8矩陣鍵盤(pán),可以進(jìn)行加、減、乘、除等十幾種數(shù)字運(yùn)算,同時(shí)支持括號(hào)的嵌套使用級(jí)浮點(diǎn)數(shù)的運(yùn)算,并在LCD1602上顯示操作過(guò)程。
本次設(shè)計(jì)注重設(shè)計(jì)方法及流程,首先根據(jù)原理設(shè)計(jì)電路,利用keil編程,借助實(shí)驗(yàn)開(kāi)發(fā)平臺(tái)進(jìn)行仿真實(shí)驗(yàn),進(jìn)而利用altium designer 制作PCB,最后到焊接元器件,直至調(diào)試成功。在設(shè)計(jì)的同時(shí),特別注重keil軟件和altium designer軟件的使用方法和技巧以及常用的LCD顯示器和矩陣鍵盤(pán)的設(shè)計(jì)和使用方法。

目錄
1  系統(tǒng)方案設(shè)計(jì)
1.1 設(shè)計(jì)目的及要求
1.1.1 設(shè)計(jì)目的
1.1.2 設(shè)計(jì)要求
1.2 方案論證及選擇
1.2.1 方案一 采用FPGA控制
1.2.2 方案二 采用STC89C52
1.2.3 方案比較及選擇
2  單元電路設(shè)計(jì)
2.1  工作原理
2.2  硬件電路設(shè)計(jì)
2.2.1  單片機(jī)電路設(shè)計(jì)
2.2.2  鍵盤(pán)模塊電路
2.2.3  蜂鳴器提示電路
2.2.4  液晶顯示電路
2.3 軟件設(shè)計(jì)
2.3.1 鍵盤(pán)掃描
2.3.2 表達(dá)式的處理
2.4  altium designer 原理圖設(shè)計(jì)及PCB制作
2.4.1  原理圖設(shè)計(jì)
2.4.2              PCB制作
2.4.3              設(shè)計(jì)結(jié)果
3系統(tǒng)測(cè)試
3.1 整數(shù)運(yùn)算
3.2 浮點(diǎn)數(shù)運(yùn)算
3.3 輸入出錯(cuò)的情況
4  結(jié)論與心得體會(huì)
5  參考文獻(xiàn)
附錄1  元器件清單
附錄2  程序清單

1  系統(tǒng)方案設(shè)計(jì)
1.1 設(shè)計(jì)目的及要求
1.1.1 設(shè)計(jì)目的

通過(guò)本次課題設(shè)計(jì),應(yīng)用《單片機(jī)應(yīng)用基礎(chǔ)》、《數(shù)據(jù)結(jié)構(gòu)》等所學(xué)相關(guān)知識(shí)及查閱資料,完成實(shí)用計(jì)算器的設(shè)計(jì),以達(dá)到理論與實(shí)踐更好的結(jié)合、進(jìn)一步提高綜合運(yùn)用所學(xué)知識(shí)和設(shè)計(jì)的能力的目的。

通過(guò)本次設(shè)計(jì)的訓(xùn)練,可以使我在基本思路和基本方法上對(duì)基于MCS-51單片機(jī)的嵌入式系統(tǒng)設(shè)計(jì)有一個(gè)比較感性的認(rèn)識(shí),并具備一定程度的設(shè)計(jì)能力。

1.1.2 設(shè)計(jì)要求

在本次課程設(shè)計(jì)中,主要完成如下方面的設(shè)計(jì)要求:

1、掌握MCS-51系列某種產(chǎn)品(例如8051)的最小電路及外圍擴(kuò)展電路的設(shè)計(jì)方法;

2、計(jì)算器能實(shí)現(xiàn)加、減、乘、除、平方、開(kāi)方、N次方、開(kāi)N次方、正弦函數(shù)、                                  余弦函數(shù)、正切函數(shù)、反正弦、反余弦、反正切、對(duì)數(shù)運(yùn)算、階乘(N<=34)、排列、                 組合、累加等十九種功能。

3、支持浮點(diǎn)數(shù)運(yùn)算;

4、較為友好的界面顯示,對(duì)輸入實(shí)時(shí)顯示,對(duì)計(jì)算結(jié)果輸出顯示;

5、能夠具備比較完善的報(bào)錯(cuò)系統(tǒng)

1.2 方案論證及選擇

基于設(shè)計(jì)要求,笨設(shè)計(jì)考慮了兩種設(shè)計(jì)方案,他們均可以實(shí)現(xiàn)計(jì)算器的功能,但基于設(shè)計(jì)目的及微控制器的廣泛運(yùn)用,比較兩種方案的優(yōu)劣,最終選擇基于51單片機(jī)的計(jì)算器設(shè)計(jì)。

1.2.1 方案一 采用FPGA控制
FPGA是一種高密度的可編程邏輯器件,自從Xilinx公司1985年推出第一片F(xiàn)PGA以來(lái),FPGA的集成密度和性能提高很快,其集成密度最高達(dá)500萬(wàn)門(mén)/片以上,系統(tǒng)性能可達(dá)200MHz。由于FPGA器件集成度高,方便易用,開(kāi)發(fā)和上市周期短,在數(shù)字設(shè)計(jì)和電子生產(chǎn)中得到迅速普及和應(yīng)用,并一度在高密度的可編程邏輯器件領(lǐng)域中獨(dú)占鰲頭。
但是而基于 SRAM編程的FPGA,其編程信息需存放在外部存儲(chǔ)器上 ,需外部存儲(chǔ)器芯片 ,且使用方法復(fù)雜 ,保密性差,而其對(duì)于一個(gè)簡(jiǎn)單的計(jì)算器而言,實(shí)用FPGA有點(diǎn)大材小用,成本太高。

1.2.2 方案二 采用STC89C52
單片機(jī)是單片微型機(jī)的簡(jiǎn)稱(chēng),故又稱(chēng)為微控制器MCU(Micro Control Unit)。通常由單塊集成電路芯片組成,內(nèi)部包含有計(jì)算機(jī)的基本功能部件:中央處理器CPU,存儲(chǔ)器和I/O接口電路等。因此,單片機(jī)只要和適當(dāng)?shù)能浖巴獠吭O(shè)備相結(jié)合,便可成為一個(gè)單片機(jī)控制系統(tǒng)。單片機(jī)廣泛用于智能產(chǎn)品,智能儀表,測(cè)控技術(shù),智能接口等,具有操作簡(jiǎn)單,實(shí)用方便,價(jià)格便宜等優(yōu)點(diǎn),而其中AT89S52以MCS-51為內(nèi)核,是單片機(jī)中最典型的代表,應(yīng)用于各種控制領(lǐng)域。
1.2.3 方案比較及選擇
通過(guò)以上兩種方案論證和比較,從設(shè)計(jì)的實(shí)用性,方便性和成本出發(fā),選擇了以STC89C52單片機(jī)作為中央處理單元進(jìn)行計(jì)算器的設(shè)計(jì),這樣設(shè)計(jì)能夠?qū)崿F(xiàn)對(duì)六位浮點(diǎn)數(shù)的加減和三位浮點(diǎn)數(shù)的乘除運(yùn)算。


2  單元電路設(shè)計(jì)

2.1  工作原理

利用矩陣鍵盤(pán)進(jìn)行按鍵的輸入,通過(guò)對(duì)矩陣鍵盤(pán)的掃描,獲取用戶(hù)的輸入,并實(shí)時(shí)的顯示在1602液晶上,每次獲取到輸入時(shí),根據(jù)軟件設(shè)計(jì)的相應(yīng)方法對(duì)輸入進(jìn)行處理、運(yùn)算,輸入結(jié)束后(以“=“為標(biāo)志),將最終的運(yùn)算結(jié)果輸出的液晶上。

系統(tǒng)組成及整體框圖如圖2.1所示。

圖2.1 系統(tǒng)組成及總體框圖(見(jiàn)附件)


2.2  硬件電路設(shè)計(jì)
2.2.1  單片機(jī)電路設(shè)計(jì)

為使單片機(jī)正常工作,除電源供電部分外,還需提供晶振電路和復(fù)位電路。具體電路如下:

圖2.2 單片機(jī)工作電路

由圖2.2可知,9腳外接的是按鍵復(fù)位電路,18,19腳外接的是晶振電路,這樣,就構(gòu)成了單片機(jī)正常工作的必備電路。同時(shí),為使P0口正常工作,并增加其帶負(fù)載能力,P0口需接了上拉電阻。圖中EA為外部訪問(wèn)允許,欲使CPU僅訪問(wèn)外部程序存儲(chǔ)器(地址為0000H-FFFFH),EA端必須保持低電平(接地)。在這里,STC89C52單片機(jī)8k的程序存儲(chǔ)器已經(jīng)夠本設(shè)計(jì)使用,無(wú)需外部程序儲(chǔ)存器,故EA直接接高電平。


2.2.2  鍵盤(pán)模塊電路

圖2.3是鍵盤(pán)電路,共20個(gè)按鍵,用來(lái)實(shí)現(xiàn)人機(jī)交互和運(yùn)算表達(dá)式的輸入,S0~S3、S5~S8、S10~S13、S15~S18共16個(gè)按鍵組成一組4*4的矩陣鍵盤(pán),行線第一行到第四行分別接在P3.0~P3.3口,列線第一列到第四列分別接在P3.4~P3.7口,這樣P3口就完成了對(duì)4*4的矩陣鍵盤(pán)的接線。同時(shí),注意到按鍵數(shù)量還達(dá)不到要求,故增加了四個(gè)獨(dú)立按鍵S4,S9,S14,S19。他們依次接在P20~P23口。可見(jiàn),矩陣鍵盤(pán)相對(duì)來(lái)講更節(jié)省I/O口,但本著學(xué)習(xí)的目的,加之本設(shè)計(jì)并不需要太多的I/O口,故為充分學(xué)習(xí)和利用資源,在這里也設(shè)計(jì)了4個(gè)這樣的獨(dú)立按鍵。

圖2.3  鍵盤(pán)模塊電路

2.2.3  蜂鳴器提示電路

蜂鳴器主要用于按鍵時(shí)發(fā)出聲音,提示當(dāng)前的按鍵操作,電路如圖2.5所示,三極管主要用于驅(qū)動(dòng)蜂鳴器,因?yàn)閱纹瑱C(jī)I/O的驅(qū)動(dòng)能力有限。同時(shí)單片機(jī)I/O口還在這里還起到開(kāi)關(guān)作用,為‘0’時(shí)打開(kāi)蜂鳴器通道,使蜂鳴器發(fā)聲。

圖2.4  蜂鳴器提示電路

2.2.4  液晶顯示電路

LCD也是本次設(shè)計(jì)的重要組成部分之一,主要用于顯示輸入和輸出。電路如圖2.5所示,LCD數(shù)據(jù)端與單片機(jī)P0口相連,控制端與P24~P26連接,電位器用于調(diào)節(jié)對(duì)比度。


圖2.5  LCD顯示電路


至此,整個(gè)電容測(cè)量?jī)x的硬件設(shè)計(jì)部分就基本設(shè)計(jì)完成,接下來(lái),需要的就是與之相匹配的軟件支持了。


2.3 軟件設(shè)計(jì)

軟件編程平臺(tái)選擇最常用的keil軟件。由于該程序并未涉及到底層的驅(qū)動(dòng)問(wèn)題,因此選擇方便快捷的C語(yǔ)言編程。在編程中,將該程序分為四個(gè)模塊:延時(shí)模塊、1602顯示模塊、用于處理計(jì)算表達(dá)式的對(duì)戰(zhàn)模塊及主函數(shù)模塊。采用模塊化設(shè)計(jì),方便調(diào)試與理解。具體程序見(jiàn)附錄二。在這里重點(diǎn)介紹軟件核心的表達(dá)式處理程序算法。

2.3.1 鍵盤(pán)掃描

獨(dú)立鍵盤(pán)很好實(shí)現(xiàn),只需不停的檢測(cè)即可,出現(xiàn)低電平即出現(xiàn)按鍵,在經(jīng)過(guò)一定的延時(shí)消抖,再確認(rèn)判斷即可。

矩陣鍵盤(pán)掃描程序,首先讀出P3的低四位,然后讀出P3口的高四位。然后確定鍵值并顯示緩存,最終將按鍵的值通過(guò)一個(gè)預(yù)先定義好的數(shù)組轉(zhuǎn)換為相應(yīng)的ASCII碼值送給LCD顯示和與表達(dá)式相應(yīng)的堆棧進(jìn)行處理,讀鍵程序使用的是反轉(zhuǎn)法讀鍵,不管鍵盤(pán)矩陣的規(guī)模大小,均進(jìn)行兩次讀鍵。第一次所有行線均輸出高電平,從P3口的值讀入鍵盤(pán)信息(行信息);第二次所有列線均輸出高電平,從P3口的值讀入鍵盤(pán)信息(列信息)。

2.3.2 表達(dá)式的處理

表達(dá)式包含加、減、乘、除、括號(hào)等,必須按照相應(yīng)的優(yōu)先級(jí)運(yùn)算,才可能得出正確的結(jié)果。在這兒采用棧結(jié)構(gòu),可以有效的進(jìn)行表達(dá)式的處理。

棧結(jié)構(gòu)具有“后進(jìn)先出”的固有屬性,借助這個(gè)屬性我們可以隨時(shí)對(duì)剛輸入的元素進(jìn)行操作,從而實(shí)現(xiàn)邊輸入邊計(jì)算。

為了實(shí)現(xiàn)算符優(yōu)先算法?梢允褂脙蓚(gè)工作棧。一個(gè)稱(chēng)為OPTR,用以寄存運(yùn)算符,另一個(gè)稱(chēng)做OPND,用以寄存操作數(shù)或運(yùn)算結(jié)果。

1.首先置操作數(shù)棧為空棧,表達(dá)式起始符”#”為運(yùn)算符棧的棧底元素;

2.依次讀入表達(dá)式,若是操作符即進(jìn)OPND棧,若是運(yùn)算符則和OPTR棧的棧頂運(yùn)算符比較優(yōu)先權(quán)后作相應(yīng)的操作,直至整個(gè)表達(dá)式求值完畢(即OPTR棧的棧頂元素和當(dāng)前讀入的字符均為”#”)。

在這里,相應(yīng)的處理指的是,如果當(dāng)前符號(hào)的優(yōu)先級(jí)比棧頂優(yōu)先級(jí)低,則將該符號(hào)繼續(xù)壓入堆棧,不做其它操作;如果當(dāng)前符號(hào)的優(yōu)先級(jí)比棧頂優(yōu)先級(jí)高,則依次取出操作數(shù)棧的棧頂兩個(gè)數(shù)據(jù)和符號(hào)棧的棧頂符號(hào)進(jìn)行這兩個(gè)數(shù)的運(yùn)算,運(yùn)算結(jié)果數(shù)據(jù)再壓入操作數(shù)棧中。若優(yōu)先級(jí)相等,則彈出符號(hào)棧棧頂符號(hào)。算符間的優(yōu)先關(guān)系如下(‘#‘表示開(kāi)始和結(jié)束):


+

-

*

/

(

)

#

+

>

<

<

<

<

>

>

-

>

>

<

<

<

>

>

*

>

>

>

>

<

>

>

/

>

>

>

>

<

>

>

(

<

<

<

<

<

=


)

>

>

>

>


>

>

#

<

<

<

<

<


=

表2.1 運(yùn)算符優(yōu)先級(jí)表


2.4  altium designer 原理圖設(shè)計(jì)及PCB制作
2.4.1  原理圖設(shè)計(jì)

圖2.6 原理圖設(shè)計(jì)(1)——單片機(jī)部分

圖2.7 原理圖設(shè)計(jì)(2)——鍵盤(pán)、蜂鳴器部分

2.4.2          PCB制作

圖2.8 PCB設(shè)計(jì)(1)——單片機(jī)部分

圖2.9 原理圖設(shè)計(jì)(2)——鍵盤(pán)、蜂鳴器部分

注:在此并沒(méi)有布雙層板,紅色的線僅僅只是為了標(biāo)志出跳線或者本質(zhì)上實(shí)物已經(jīng)連接上了。


2.4.3          設(shè)計(jì)結(jié)果

圖2.10   設(shè)計(jì)結(jié)果實(shí)物圖


如圖所示,各個(gè)按鍵功能如圖中文字說(shuō)明,電源為5V直流電源。


3系統(tǒng)測(cè)試

測(cè)試主要測(cè)試其運(yùn)算是否正確,及檢錯(cuò)能力。

3.1 整數(shù)運(yùn)算

在此以整數(shù)運(yùn)算為例,介紹計(jì)算器的使用方法即流程。首先打開(kāi)電源,看到LCD打開(kāi)顯示,說(shuō)明運(yùn)行正常,接著,輸入表達(dá)式:12*(56+23)*2,其結(jié)果本身應(yīng)為1896。

輸入結(jié)束后,點(diǎn)“=”按鍵,即可在第二行顯示出運(yùn)算結(jié)果,由圖可見(jiàn)運(yùn)算完全正確。在使用時(shí),可以通過(guò)聲音開(kāi)關(guān)按鈕控制按鍵音的打開(kāi)和關(guān)閉,在LCD上也有顯示,如果再第二行第一個(gè)位置沒(méi)有顯示,則沒(méi)有打開(kāi)聲音,可以通過(guò)按鈕打開(kāi)。若有顯示,則聲音已經(jīng)打開(kāi),可以通過(guò)按鈕關(guān)閉聲音。如圖3.1所示,此時(shí)已經(jīng)打開(kāi)聲音。

圖3.1  整數(shù)運(yùn)算




3.2 浮點(diǎn)數(shù)運(yùn)算

由圖可以看出,可以進(jìn)行浮點(diǎn)數(shù)運(yùn)算,還可以從第二行第一個(gè)字符,蜂鳴器處于關(guān)閉狀態(tài)。


3.3 輸入出錯(cuò)的情況

輸入一個(gè)錯(cuò)誤的表達(dá)式,如圖3.3所示。

圖3.3 輸入錯(cuò)誤的情況下


再按“=”號(hào),將會(huì)出現(xiàn)出錯(cuò)畫(huà)面。如圖3.4所示。

圖3.4 輸入錯(cuò)誤的顯示


由以上測(cè)試可知,整個(gè)設(shè)計(jì)運(yùn)行正常,能夠正確的進(jìn)行運(yùn)算和出錯(cuò)提示。由此可得,整個(gè)設(shè)計(jì)是成功的。




4  結(jié)論與心得體會(huì)

總之,通過(guò)一系列仿真和設(shè)計(jì),基于單片機(jī)的計(jì)算器設(shè)計(jì)還是比較成功的做出來(lái)了。一路下來(lái)還是比較坎坷,從原理到實(shí)物,從調(diào)試到調(diào)試成功,遇到了很多問(wèn)題,特別是在軟件編程時(shí),開(kāi)始以為既然單片機(jī)具有數(shù)據(jù)處理與運(yùn)算的能力,那么用它來(lái)做一個(gè)計(jì)算器應(yīng)該很簡(jiǎn)單了,可是,后面實(shí)際操作才知道,當(dāng)計(jì)算表達(dá)式時(shí),優(yōu)先級(jí)問(wèn)題非常重要,一開(kāi)始用了很多if語(yǔ)句來(lái)實(shí)現(xiàn),程序繁瑣復(fù)雜,且效果不是很好,很容易出錯(cuò),最后通過(guò)查閱相關(guān)資料,了解到利用數(shù)據(jù)結(jié)構(gòu)中棧的思想來(lái)解決這一問(wèn)題就很方便。但在實(shí)際寫(xiě)程序時(shí)也遇到了很多問(wèn)題,但最終還是克服難關(guān),將整個(gè)軟件比較完善的實(shí)現(xiàn)了。

在硬件的原理圖及PCB設(shè)計(jì)中,也遇到了很多問(wèn)題,先做模塊后做主板,導(dǎo)致我后面的布線就很麻煩,這也教會(huì)了我一些經(jīng)驗(yàn),在PCB分模塊設(shè)計(jì)中,模塊與模塊之間的連接也是必須考慮到的,從左端連接還是從右端連接,都直接影響到整個(gè)PCB板的設(shè)計(jì)。

總之,通過(guò)這次設(shè)計(jì)也收獲了很多,知識(shí)層面上,學(xué)得了很多新知識(shí),解決問(wèn)題的新方法,思考問(wèn)題的新方向。實(shí)踐方面,提高了動(dòng)手能力,提高了解決實(shí)際問(wèn)題的能力等等。在思想上,更加明白的堅(jiān)持不懈的重要性,學(xué)習(xí)探索的重要性,實(shí)踐動(dòng)手的重要性。


5  參考文獻(xiàn)

【1】  《單片機(jī)基礎(chǔ)》第三版 李廣弟 朱月秀 冷祖祁 編著 北京航天大學(xué)出版社,2007

【2】 《數(shù)據(jù)結(jié)構(gòu)》嚴(yán)蔚敏 編著  清華大學(xué)出版社


附錄1  元器件清單

(1)晶振12M一個(gè)

(2)stc89c52芯片一片

(3)30pf 2個(gè);10uf 1個(gè);

(4)40腳活動(dòng)底座一個(gè)

(5)LCD液晶一個(gè)

(6)按鍵21個(gè)

(7)發(fā)光二極管1個(gè)

(8)9引腳排阻 1個(gè)

(9)680Ω 1個(gè);10k 2個(gè);1k  1個(gè);10k滑動(dòng)變阻器 1個(gè); 10Ω 1個(gè);

(10) 開(kāi)關(guān)1個(gè)

(11) 5V有源蜂鳴器1個(gè)

(12) 三極管S8550一個(gè)

(13)排針若干,杜邦線若干


單片機(jī)源程序如下:


  1. #include <REGX51.H>
  2. #include<intrins.h>
  3. #include<stdio.h>
  4. #include<string.h>
  5. #include<math.h>
  6. sbit RS = P2^5;
  7. sbit RW = P2^6;
  8. sbit E  = P2^7;

  9. #define Data  P0//數(shù)據(jù)端口
  10. //全局變量
  11. float num1;//第一操作數(shù)num1     (初始為零)
  12. float num2;//第二操作數(shù)num2     (初始為零)
  13. char yun_flag='+';//運(yùn)算符號(hào) yun_flag    (默認(rèn)為+ )
  14. char key_last;//上次按鍵狀態(tài)標(biāo)志 key_last
  15. char sqrt_flag;//開(kāi)方鍵按下標(biāo)志   sqrt_flag
  16. unsigned long pos_flag=1;//小數(shù)位權(quán)pos_flag      (默認(rèn)為1)
  17. char neg_flag;//正負(fù)標(biāo)志 neg_flag
  18. char data c_num1[15]=" ";//c_num1 字符型第一操作數(shù) (數(shù)組不定義大小與其他變量沖突)
  19. char data c_num2[15]=" ";//c_num2 字符型第二操作數(shù)
  20. char error;//運(yùn)算法則錯(cuò)誤;
  21. char len;//小數(shù)點(diǎn)后位數(shù)
  22. /*                    微秒延時(shí)函數(shù)                                */
  23. /******************************************************************/
  24. void DelayUs(unsigned char us)//delay us
  25. {
  26. unsigned char uscnt;
  27. uscnt=us>>1;        /*12MHz頻率*/
  28. while(--uscnt);
  29. }
  30. /******************************************************************/
  31. /*                    毫秒函數(shù)聲明                                */
  32. /******************************************************************/
  33. void DelayMs(unsigned char ms)
  34. {
  35. while(--ms)
  36.    {
  37.      DelayUs(250);
  38.      DelayUs(250);
  39.          DelayUs(250);
  40.          DelayUs(250);
  41.    }
  42. }
  43. /******************************************************************/
  44. /*                   寫(xiě)入命令函數(shù)                                 */
  45. /******************************************************************/
  46. void WriteCommand(unsigned char c)
  47. {
  48. DelayMs(5);//操作前短暫延時(shí),保證信號(hào)穩(wěn)定
  49. E=0;
  50. RS=0;
  51. RW=0;
  52. _nop_();
  53. E=1;
  54. Data=c;
  55. E=0;
  56. }
  57. /******************************************************************/
  58. /*                   寫(xiě)入數(shù)據(jù)函數(shù)                                 */
  59. /******************************************************************/
  60. void WriteData(unsigned char c)
  61. {
  62. DelayMs(5);  //操作前短暫延時(shí),保證信號(hào)穩(wěn)定
  63. E=0;
  64. RS=1;
  65. RW=0;
  66. _nop_();
  67. E=1;
  68. Data=c;
  69. E=0;
  70. RS=0;
  71. }
  72. /******************************************************************/
  73. /*                   寫(xiě)入字節(jié)函數(shù)                                 */
  74. /******************************************************************/
  75. void ShowChar(unsigned char pos,unsigned char c)
  76. {
  77. unsigned char p;
  78. if (pos>=0x10)
  79.     p=pos+0xb0; //是第二行則命令代碼高4位為0xc
  80. else
  81.     p=pos+0x80; //是第二行則命令代碼高4位為0x8
  82. WriteCommand (p);//寫(xiě)命令
  83. WriteData (c);   //寫(xiě)數(shù)據(jù)
  84. }
  85. /******************************************************************/
  86. /*                   寫(xiě)入字符串函數(shù)                               */
  87. /******************************************************************/
  88. void ShowString (unsigned char line,char *ptr)
  89. {
  90. unsigned char l,i;
  91. l=line<<4;
  92. for (i=0;*(ptr+i)!='\0';i++)
  93.   ShowChar (l++,*(ptr+i));//循環(huán)顯示16個(gè)字符
  94. }
  95. /******************************************************************/
  96. /*                   初始化函數(shù)                                   */
  97. /******************************************************************/
  98. void InitLcd()
  99. {
  100. DelayMs(15);
  101. WriteCommand(0x38); //display mode
  102. WriteCommand(0x38); //display mode
  103. WriteCommand(0x38); //display mode
  104. WriteCommand(0x06); //顯示光標(biāo)移動(dòng)位置
  105. WriteCommand(0x0c); //顯示開(kāi)及光標(biāo)設(shè)置
  106. WriteCommand(0x01); //顯示清屏

  107. }
  108. /*************按鍵掃描****************************/
  109. char scan()
  110. {

  111.   char h_data,l_data,i,key_num;
  112.   P2=P2&0XE0;//P2低5位送0
  113.   P1=P1|0X0F;//P1低4位送1
  114.   while((P1|0xf0)==0xff)//判斷P1低4位是否全為1
  115.   {
  116.    while((P1|0xf0)==0xff);
  117.    DelayMs(10);//延時(shí)10ms
  118.   }
  119.    l_data=~(P1|0xf0);//記入列標(biāo)志
  120.    P2=P2|0X1F;//P2低五位送1
  121.    P1=P1&0XF0;//P1低四位送0
  122.    h_data=~(P2|0xe0);//記入行標(biāo)志
  123.    for(i=0;i<=4;i++)//計(jì)算行號(hào)(0~4)
  124.             {
  125.            if(h_data==1)break;
  126.            h_data=h_data>>1;
  127.          }
  128. h_data=i;//行號(hào)
  129.   for(i=1;i<=4;i++)//計(jì)算列號(hào)(1~4)
  130.          {
  131.           if(l_data==1)break;
  132.           l_data=l_data>>1;
  133.         }
  134. l_data=i;//列號(hào)
  135.    key_num=h_data*4+l_data;        

  136.   P2=P2&0XE0;//P2低5位送0
  137.   P1=P1|0X0F;//P1低4位送1
  138.   while((P1|0xf0)!=0xff)//判斷P1低4位是否全為1
  139.   {
  140.    while((P1|0xf0)!=0xff);
  141.    DelayMs(10);//延時(shí)10ms
  142.   }
  143.   return key_num;
  144. }
  145. void float_to_char(float a,char* p)
  146. {
  147.   char i,flag,length;
  148.   flag=0;
  149.   sprintf(p,"%f",a);
  150.   length=strlen (p);
  151.   for(i=0;i<length;i++)
  152.   {
  153.     if(*(p+i)=='.')flag=1;
  154.   }
  155.   if(flag==1)
  156.   for(i=length-1;i>=0;i--)
  157.   {
  158.     if(*(p+i)=='.'){*(p+i)='\0';break;}
  159.     if(*(p+i)!='0'){*(p+i+1)='\0';break;}
  160.   }
  161. }
  162. /**********************更新液晶*************************/
  163. void refresh()//更新液晶
  164. {
  165.   char length,i,j;
  166.   char dot;
  167.   dot=0;
  168.          
  169.   float_to_char(num2,c_num2);//num2轉(zhuǎn)為字符型
  170.   length=strlen(c_num2);
  171.   for(i=0,j=0;i<length;i++)        
  172.   {
  173.     if(c_num2[i]=='.')
  174.         dot=1;
  175.         if(dot==1)
  176.     j++;
  177.   }
  178.   if(j<len)
  179.   {
  180.           if(dot==1)
  181.           {        
  182.             for(i=length;i<(length+len-j);i++)
  183.                  {
  184.                    c_num2[i]='0';
  185.         
  186.                  }
  187.                  c_num2[i]='\0';
  188.           }
  189.           else
  190.                 {
  191.                   
  192.                   c_num2[length]='.';
  193.                   if(len-j>1)
  194.                   {
  195.                     for(i=length+1;i<(length+len-j);i++)
  196.                          c_num2[i]='0';
  197.                   }
  198.                   c_num2[length+len-j]='\0';
  199.                 }  
  200.   }

  201.   if(neg_flag==1)//'+/-'按下首位加‘-’
  202.    {
  203.       length=strlen(c_num2);//計(jì)算c_num2長(zhǎng)度         
  204.                     for(i=length-1;i>=0;i--)
  205.                   {
  206.                           c_num2[i+1]=c_num2[i];
  207.                   }
  208.                   c_num2[length+1]='\0';
  209.                   c_num2[0]='-';
  210.    }
  211.    
  212.    if(sqrt_flag==1)
  213.            {
  214.       length=strlen(c_num2);//計(jì)算c_num2長(zhǎng)度
  215.              for(i=length-1;i>=0;i--)
  216.           {
  217.                   c_num2[i+1]=c_num2[i];
  218.           }
  219.           c_num2[length+1]='\0';
  220.           c_num2[0]=0xe8;//字符根號(hào)
  221.    }
  222.    
  223.    
  224.    if(error==0)
  225.    {
  226.            float_to_char(num1,c_num1);//num1轉(zhuǎn)為字符型
  227.            WriteCommand(0x01); //顯示清屏
  228.            ShowString(0,c_num1);
  229.            ShowString(1,c_num2);  
  230.            ShowChar(15,yun_flag);
  231.    }else
  232.    {
  233.        WriteCommand(0x01); //顯示清屏
  234.            ShowString(0,"error!!!");
  235.    }
  236. }
  237. //鍵值處理
  238. void operation1(char keynum)//按下 ’+、-、*、/處理
  239. {
  240.   if(key_last==1)//上次按鍵為 數(shù)字、小數(shù)點(diǎn)、+/-、sqrt
  241.    {
  242.      if(neg_flag==1)num2=-num2;//'+/-'按下
  243.          if(sqrt_flag==1)//sqrt按下
  244.          {
  245.          if(num2>=0)
  246.          num2=sqrt(num2);
  247.          else
  248.          error=1;
  249.          }
  250.          if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
  251.          if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
  252.          if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
  253.          if(yun_flag=='/')//按下的是‘/’
  254.          {
  255.            if(num2!=0)
  256.            num1=num1/num2;
  257.            else
  258.            error=1;
  259.          }
  260.          num2=0;//num2清零
  261.          sqrt_flag=0;//sqrt_flag清零
  262.      neg_flag=0;//neg_flag清零
  263.          pos_flag=1;//pos_flag回1
  264.    }
  265.    if(keynum==4)yun_flag='+';//yun_flag更新
  266.    if(keynum==8)yun_flag='-';
  267.    if(keynum==12)yun_flag='*';
  268.    if(keynum==16)yun_flag='/';
  269.    len=0;
  270.    key_last=0;//key_last更新   
  271.    refresh();
  272. }
  273. //////////////////////////////////////////////////////
  274. void operation2(char keynum)//輸入數(shù)字
  275. {
  276.   float Data1;
  277.    
  278.   if(keynum==1)Data1=7;//分析輸入數(shù)字
  279.   if(keynum==2)Data1=8;
  280.   if(keynum==3)Data1=9;
  281.   if(keynum==5)Data1=4;
  282.   if(keynum==6)Data1=5;
  283.   if(keynum==7)Data1=6;
  284.   if(keynum==9)Data1=1;
  285.   if(keynum==10)Data1=2;
  286.   if(keynum==11)Data1=3;
  287.   if(keynum==13)Data1=0;
  288.   if(pos_flag==1)//更新num2
  289.   num2=num2*10+Data1;
  290.   else
  291.   {            
  292.     num2=num2+(Data1/pos_flag);
  293.         pos_flag=pos_flag*10;
  294.         len++;
  295.   }
  296.   key_last=1;//更新key_last        
  297.   refresh();
  298. }
  299. ////////////////////////////////////////////////////////////
  300. void operation3()//輸入小數(shù)點(diǎn)
  301. {
  302.   if(pos_flag==1)//首次出現(xiàn)小數(shù)點(diǎn)
  303.   {
  304.    pos_flag=pos_flag*10;//小數(shù)位權(quán)*10
  305.    len++;
  306.   }
  307.   key_last=1;//更新key_last
  308.   refresh();//更新液晶
  309. }
  310. /////////////////////////////////////////////////////
  311. void operation4()//輸入'='
  312. {
  313.      if(neg_flag==1)num2=-num2;//'+/-'按下
  314.          if(sqrt_flag==1)//sqrt按下
  315.          {
  316.          if(num2>=0)
  317.          num2=sqrt(num2);
  318.          else
  319.          error=1;
  320.          }
  321.          if(yun_flag=='+')num1=num1+num2; //按下的是‘+’
  322.          if(yun_flag=='-')num1=num1-num2;//按下的是‘-’
  323.          if(yun_flag=='*')num1=num1*num2;//按下的是‘*’
  324.          if(yun_flag=='/')//按下的是‘/’
  325.          {
  326.            if(num2!=0)
  327.            num1=num1/num2;
  328.            else
  329.            error=1;
  330.          }
  331.          num2=0;//num2清零
  332.          sqrt_flag=0;//sqrt_flag清零
  333.      neg_flag=0;//neg_flag清零
  334.          pos_flag=1;//pos_flag回1
  335.      yun_flag='+';//yun_flag更新
  336.          len=0;
  337.    key_last=0;//key_last更新   
  338.    refresh();
  339. }
  340. ////////////////////////////////////////////////////
  341. void operation5()//輸入clear all
  342. {

  343.    num1=0;// num1清零
  344.    num2=0;//num2清零
  345.    sqrt_flag=0;//清sqrt_flag
  346.    neg_flag=0;// 清neg_flag
  347.    pos_flag=1;// Pos_flag=1
  348.    yun_flag='+';// yun_flag(為'+')
  349.    error=0;//清e(cuò)rror
  350.    len=0;
  351.    key_last=0;//更新key_flag
  352.    refresh();//更新液晶
  353. }
  354. ///////////////////////////////////////////////////////
  355. void operation6()//輸入'C'
  356. {
  357. num2=0;//num2清零
  358. sqrt_flag=0;//清sqrt_flag
  359. neg_flag=0;//清neg_flag
  360. pos_flag=1;//pos_flag=1
  361. len=0;
  362. key_last=0;//key_last
  363. refresh();//更新液晶
  364. }
  365. ////////////////////////////////////////////////////////////
  366. void operation7()//輸入'+/-'
  367. {
  368.   if(neg_flag==0)//neg_flag反轉(zhuǎn)
  369.   neg_flag=1;
  370.   else neg_flag=0;
  371.   key_last=1;//key_last
  372.   refresh();// 更新液晶
  373. }
  374. /////////////////////////////////////////////////////////////
  375. void operation8()//輸入'sqrt'
  376. {
  377. if(sqrt_flag==0)//sqrt_flag反轉(zhuǎn)
  378.   sqrt_flag=1;
  379. else sqrt_flag=0;
  380. key_last=1;//更新key_last
  381. refresh();//更新液晶
  382. }
  383. //鍵值分析
  384. void key(char keynum)
  385. {
  386.   switch(keynum)
  387.   {
  388.     case 4 :
  389.         case 8 :
  390.         case 12:
  391.         case 16://+、-、*、/
  392.                     {
  393.                          if(error==0)
  394.                  operation1(keynum);
  395.                  break;}
  396.                         
  397.         case 1  : //數(shù)字7
  398.         case 2  : //數(shù)字8
  399.         case 3  : //數(shù)字9
  400.         case 5  : //數(shù)字4
  401.         case 6  : //數(shù)字5
  402.         case 7  : //數(shù)字6
  403.         case 9  : //數(shù)字1
  404.         case 10 : //數(shù)字2
  405.         case 11 : //數(shù)字3
  406.         case 13 : //數(shù)字0
  407.                  {
  408.                          if(error==0)
  409.                          operation2(keynum);
  410. …………
  411. …………
  412. …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼


評(píng)分

參與人數(shù) 3黑幣 +61 收起 理由
DREAK + 5 很給力!
胡來(lái)的饅頭 + 6 很給力!
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏30 分享淘帖 頂3 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:342386 發(fā)表于 2018-6-13 19:10 | 只看該作者
非常感謝 很有幫助!
回復(fù)

使用道具 舉報(bào)

板凳
ID:314053 發(fā)表于 2018-12-25 21:14 | 只看該作者
牛人啊,大神啊。。。。厲害,膜拜
回復(fù)

使用道具 舉報(bào)

地板
ID:450548 發(fā)表于 2018-12-26 08:37 | 只看該作者
非常有用,感謝樓主。
回復(fù)

使用道具 舉報(bào)

5#
ID:450548 發(fā)表于 2018-12-26 10:05 | 只看該作者
大神啊,寫(xiě)的真詳細(xì),里邊還有具體的說(shuō)明。小白進(jìn)階專(zhuān)用。。!
回復(fù)

使用道具 舉報(bào)

6#
ID:404045 發(fā)表于 2018-12-27 12:39 | 只看該作者
很強(qiáng)  感謝分享

回復(fù)

使用道具 舉報(bào)

7#
ID:461954 發(fā)表于 2019-1-4 22:07 來(lái)自手機(jī) | 只看該作者
這里邊的程序沒(méi)有蜂鳴的
回復(fù)

使用道具 舉報(bào)

8#
ID:481555 發(fā)表于 2019-3-1 20:44 | 只看該作者
寫(xiě)的真詳細(xì),里邊還有具體的說(shuō)明。小白進(jìn)階專(zhuān)用。。!
回復(fù)

使用道具 舉報(bào)

9#
ID:262632 發(fā)表于 2019-3-20 19:15 | 只看該作者
感謝樓主,給樓主點(diǎn)贊
回復(fù)

使用道具 舉報(bào)

10#
ID:679940 發(fā)表于 2020-1-4 10:53 | 只看該作者
xbdbox 發(fā)表于 2018-12-26 10:05
大神啊,寫(xiě)的真詳細(xì),里邊還有具體的說(shuō)明。小白進(jìn)階專(zhuān)用啊!!

那他這個(gè)到底怎么連接啊,我用的單片機(jī)開(kāi)發(fā)儀,不顯示東西啊
回復(fù)

使用道具 舉報(bào)

11#
ID:374009 發(fā)表于 2020-4-8 12:44 | 只看該作者
感謝感謝,好想學(xué)習(xí)
回復(fù)

使用道具 舉報(bào)

12#
ID:281879 發(fā)表于 2020-4-8 14:34 | 只看該作者
牛啊 很詳細(xì) 學(xué)習(xí)了
回復(fù)

使用道具 舉報(bào)

13#
ID:743480 發(fā)表于 2020-5-3 18:03 | 只看該作者
這個(gè)可以燒進(jìn)89C51嗎?
回復(fù)

使用道具 舉報(bào)

14#
ID:677756 發(fā)表于 2020-5-23 18:54 | 只看該作者
感謝,幫助很大,就是發(fā)現(xiàn)的太晚了
回復(fù)

使用道具 舉報(bào)

15#
ID:763852 發(fā)表于 2020-5-28 22:57 | 只看該作者
謝謝樓主分享,幫助很大
回復(fù)

使用道具 舉報(bào)

16#
ID:704379 發(fā)表于 2020-6-2 11:47 | 只看該作者
寫(xiě)的真的太好了,一直想找的內(nèi)容
回復(fù)

使用道具 舉報(bào)

17#
ID:701252 發(fā)表于 2020-10-17 09:20 | 只看該作者
高手呀。!
正在學(xué)習(xí)中!!我一直想學(xué)習(xí)一下計(jì)算器的編程呢!謝謝樓主分享!
回復(fù)

使用道具 舉報(bào)

18#
ID:861681 發(fā)表于 2020-12-19 13:59 來(lái)自手機(jī) | 只看該作者
程序里沒(méi)有括號(hào)()啊,怎么混合四則運(yùn)算
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表