lcd1602 51單片機(jī)計(jì)算器 5*4鍵盤(pán)掃描,下面是制作出來(lái)的實(shí)物圖:

圖3.2 浮點(diǎn)數(shù)運(yùn)算
0.png (49.53 KB, 下載次數(shù): 99)
下載附件
2018-6-13 00:46 上傳
全部資料51hei下載地址:
計(jì)算器 5乘4.zip
(5.75 MB, 下載次數(shù): 640)
2018-6-12 15:05 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
單片機(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ī)源程序如下:
- #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//數(shù)據(jù)端口
- //全局變量
- float num1;//第一操作數(shù)num1 (初始為零)
- float num2;//第二操作數(shù)num2 (初始為零)
- char yun_flag='+';//運(yùn)算符號(hào) yun_flag (默認(rèn)為+ )
- char key_last;//上次按鍵狀態(tài)標(biāo)志 key_last
- char sqrt_flag;//開(kāi)方鍵按下標(biāo)志 sqrt_flag
- unsigned long pos_flag=1;//小數(shù)位權(quán)pos_flag (默認(rèn)為1)
- char neg_flag;//正負(fù)標(biāo)志 neg_flag
- char data c_num1[15]=" ";//c_num1 字符型第一操作數(shù) (數(shù)組不定義大小與其他變量沖突)
- char data c_num2[15]=" ";//c_num2 字符型第二操作數(shù)
- char error;//運(yùn)算法則錯(cuò)誤;
- char len;//小數(shù)點(diǎn)后位數(shù)
- /* 微秒延時(shí)函數(shù) */
- /******************************************************************/
- void DelayUs(unsigned char us)//delay us
- {
- unsigned char uscnt;
- uscnt=us>>1; /*12MHz頻率*/
- while(--uscnt);
- }
- /******************************************************************/
- /* 毫秒函數(shù)聲明 */
- /******************************************************************/
- void DelayMs(unsigned char ms)
- {
- while(--ms)
- {
- DelayUs(250);
- DelayUs(250);
- DelayUs(250);
- DelayUs(250);
- }
- }
- /******************************************************************/
- /* 寫(xiě)入命令函數(shù) */
- /******************************************************************/
- void WriteCommand(unsigned char c)
- {
- DelayMs(5);//操作前短暫延時(shí),保證信號(hào)穩(wěn)定
- E=0;
- RS=0;
- RW=0;
- _nop_();
- E=1;
- Data=c;
- E=0;
- }
- /******************************************************************/
- /* 寫(xiě)入數(shù)據(jù)函數(shù) */
- /******************************************************************/
- void WriteData(unsigned char c)
- {
- DelayMs(5); //操作前短暫延時(shí),保證信號(hào)穩(wěn)定
- E=0;
- RS=1;
- RW=0;
- _nop_();
- E=1;
- Data=c;
- E=0;
- RS=0;
- }
- /******************************************************************/
- /* 寫(xiě)入字節(jié)函數(shù) */
- /******************************************************************/
- 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);//寫(xiě)命令
- WriteData (c); //寫(xiě)數(shù)據(jù)
- }
- /******************************************************************/
- /* 寫(xiě)入字符串函數(shù) */
- /******************************************************************/
- 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));//循環(huán)顯示16個(gè)字符
- }
- /******************************************************************/
- /* 初始化函數(shù) */
- /******************************************************************/
- void InitLcd()
- {
- DelayMs(15);
- WriteCommand(0x38); //display mode
- WriteCommand(0x38); //display mode
- WriteCommand(0x38); //display mode
- WriteCommand(0x06); //顯示光標(biāo)移動(dòng)位置
- WriteCommand(0x0c); //顯示開(kāi)及光標(biāo)設(shè)置
- 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);//延時(shí)10ms
- }
- l_data=~(P1|0xf0);//記入列標(biāo)志
- P2=P2|0X1F;//P2低五位送1
- P1=P1&0XF0;//P1低四位送0
- h_data=~(P2|0xe0);//記入行標(biāo)志
- for(i=0;i<=4;i++)//計(jì)算行號(hào)(0~4)
- {
- if(h_data==1)break;
- h_data=h_data>>1;
- }
- h_data=i;//行號(hào)
- for(i=1;i<=4;i++)//計(jì)算列號(hào)(1~4)
- {
- if(l_data==1)break;
- l_data=l_data>>1;
- }
- l_data=i;//列號(hào)
- 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);//延時(shí)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轉(zhuǎn)為字符型
- 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);//計(jì)算c_num2長(zhǎng)度
- 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);//計(jì)算c_num2長(zhǎng)度
- for(i=length-1;i>=0;i--)
- {
- c_num2[i+1]=c_num2[i];
- }
- c_num2[length+1]='\0';
- c_num2[0]=0xe8;//字符根號(hào)
- }
-
-
- if(error==0)
- {
- float_to_char(num1,c_num1);//num1轉(zhuǎn)為字符型
- 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)//上次按鍵為 數(shù)字、小數(shù)點(diǎn)、+/-、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)//輸入數(shù)字
- {
- float Data1;
-
- if(keynum==1)Data1=7;//分析輸入數(shù)字
- 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()//輸入小數(shù)點(diǎn)
- {
- if(pos_flag==1)//首次出現(xiàn)小數(shù)點(diǎn)
- {
- pos_flag=pos_flag*10;//小數(shù)位權(quán)*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;//清e(cuò)rror
- 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反轉(zhuǎn)
- neg_flag=1;
- else neg_flag=0;
- key_last=1;//key_last
- refresh();// 更新液晶
- }
- /////////////////////////////////////////////////////////////
- void operation8()//輸入'sqrt'
- {
- if(sqrt_flag==0)//sqrt_flag反轉(zhuǎn)
- 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 : //數(shù)字7
- case 2 : //數(shù)字8
- case 3 : //數(shù)字9
- case 5 : //數(shù)字4
- case 6 : //數(shù)字5
- case 7 : //數(shù)字6
- case 9 : //數(shù)字1
- case 10 : //數(shù)字2
- case 11 : //數(shù)字3
- case 13 : //數(shù)字0
- {
- if(error==0)
- operation2(keynum);
- …………
- …………
- …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼
|