本設(shè)計(jì)是實(shí)現(xiàn)一個(gè)有四則運(yùn)算功能計(jì)算器。它的硬件部分包括:一個(gè)STC89C52單片機(jī),一塊LCD1602液晶顯示器,一個(gè)紅外遙控器。是一個(gè)以STC89C52單片機(jī)為核心控制電路,LCD1602負(fù)責(zé)顯示輸入輸出數(shù)據(jù),利用紅外遙控器完成電路的鍵入操作部分,電路簡(jiǎn)單,操作方便。
設(shè)計(jì)的目的(1)計(jì)算器是我們生活中必不可少的工具,結(jié)合自身所學(xué),設(shè)計(jì)一個(gè)基于51單片機(jī)的計(jì)算器,使其能實(shí)現(xiàn)加減乘除的功能。 (2)在電路設(shè)計(jì)中熟悉元器件選型,及Protues下單片機(jī)系統(tǒng)仿真與調(diào)試,不斷完善電路與程序。 (3)理解紅外解碼以及LCD1602顯示原理,將所學(xué)知識(shí)運(yùn)用到計(jì)算器設(shè)計(jì)中。
(1)能實(shí)現(xiàn)多位數(shù)加減乘除四則運(yùn)算。 (2)LCD1602液晶顯示按鍵值與計(jì)算結(jié)果。 (3)紅外遙控按鍵。 (4)利用proteus和keil進(jìn)行仿真調(diào)試。 第2章 總體方案設(shè)計(jì) 計(jì)算器系統(tǒng)設(shè)計(jì)可采用兩種方案,方案一:以51單片機(jī)為核心配合相關(guān)硬件來(lái)實(shí)現(xiàn)。方案二:以FPGA芯片為核心配合相關(guān)硬件實(shí)現(xiàn)。 方案一:選用51單片機(jī)控制 單片機(jī)一個(gè)小而完善的微型計(jì)算機(jī)系統(tǒng),它很容易和其他硬件配合實(shí)現(xiàn)各種各樣的功能。具有應(yīng)用范圍廣泛、易于操作和使用、開(kāi)支小等優(yōu)點(diǎn)。完全滿(mǎn)足本次設(shè)計(jì)要求。 方案二:選用FPGA控制 在1985年,Xilinx公司研制出第一個(gè)FPGA芯片。因?yàn)槠渚哂幸子谑褂�、較高的集成度、開(kāi)發(fā)時(shí)間短等優(yōu)點(diǎn),F(xiàn)PGA在電子領(lǐng)域中得到快速發(fā)展和應(yīng)用。用戶(hù)可對(duì)FPGA內(nèi)部的邏輯模塊和I/O模塊重新配置,以實(shí)現(xiàn)用戶(hù)的邏輯。它還具有靜態(tài)可重復(fù)編程和動(dòng)態(tài)在系統(tǒng)重構(gòu)的特性,使得硬件的功能可以像軟件一樣通過(guò)編程來(lái)修改。作為專(zhuān)用集成電路領(lǐng)域中的一種半定制電路,F(xiàn)PGA既解決了定制電路的不足,又克服了原有可編程器件門(mén)電路數(shù)有限的缺點(diǎn)。 但是對(duì)于我來(lái)說(shuō),F(xiàn)PGA還是很陌生的。沒(méi)有專(zhuān)門(mén)學(xué)習(xí)過(guò)這個(gè)芯片,應(yīng)用FPGA芯片很困難。另外,由于芯片還需外部存儲(chǔ)芯片,并且運(yùn)行較麻煩,保密性不好,總之,采用FPGA設(shè)計(jì)計(jì)算器成本開(kāi)支比較大,開(kāi)發(fā)困難。 經(jīng)過(guò)兩個(gè)方案的綜合比較,我們從價(jià)格、可操作性等角度來(lái)考慮,本次設(shè)計(jì)將采用以STC89C52單片機(jī)為核心構(gòu)成計(jì)算器系統(tǒng)。 第3 章 硬件設(shè)計(jì) 3.1 整體硬件設(shè)計(jì)本次設(shè)計(jì)設(shè)計(jì)的計(jì)算器由單片機(jī)最小系統(tǒng)、LCD1602液晶屏、紅外遙控器三個(gè)部分組成。將 STC89C52作為計(jì)算器系統(tǒng)核心,完成對(duì)紅外遙控或鍵盤(pán)的響應(yīng)、LCD1602液晶顯示等功能的控制。利用C語(yǔ)言程序在KEIL軟件中進(jìn)行編程,對(duì)STC89C52的 I/O 口進(jìn)行充分的利用,使得STC89C52能夠正確讀取被使用者按下的相應(yīng)功能鍵,然后通過(guò)單片機(jī)內(nèi)部相關(guān)運(yùn)算,控制LCD1602 液晶屏顯示相應(yīng)鍵值與運(yùn)算結(jié)果。
3.2 時(shí)鐘電路及復(fù)位電路時(shí)鐘電路:時(shí)鐘電路的核心是個(gè)比較穩(wěn)定的振蕩器(一般用晶體振蕩器),振蕩器所產(chǎn)生的是正弦波,頻率不一定是電路工作的時(shí)鐘頻率,因此就要把這正弦波進(jìn)行分頻,處理,最后形成時(shí)鐘脈沖,然后分配到需要的地方。 本次設(shè)計(jì)采用內(nèi)部時(shí)鐘模式,首先,需要在XTAL1和XTAL2兩端之間連接一個(gè)晶體振蕩器,然后,在兩端接兩個(gè)一樣大的電容,最后,再把兩個(gè)電容接到地上;電容器容量的大小對(duì)振蕩頻率有輕微調(diào)控的作用,電容值一般情況下大概是30pF,振蕩的頻率重點(diǎn)由石英晶振的頻率確定,振蕩電路的頻率也就是晶體的固有頻率。具體如圖2所示。
復(fù)位電路:復(fù)位是單片機(jī)的初始化操作,其功能是把系統(tǒng)初始化。 單片機(jī)的復(fù)位條件是:1、RST必須接上連續(xù)的兩個(gè)機(jī)器周期2、RST必須接高電平。電路將在RST的高電平后的第二個(gè)周期進(jìn)行復(fù)位。復(fù)位電路有兩種,一種是通過(guò)按鍵復(fù)位即按鍵復(fù)位,另一種是通過(guò)上電進(jìn)行復(fù)位即上電復(fù)位。本設(shè)計(jì)采用的是按鍵復(fù)位,因?yàn)楸容^方便,只要輕輕按下開(kāi)關(guān)鍵,就能輕松的實(shí)現(xiàn)復(fù)位功能。具體如圖3所示。
3.3 紅外遙控模塊紅外遙控是一種無(wú)線(xiàn)、非接觸控制技術(shù),具有抗干擾能力強(qiáng),信息傳輸可靠,功耗低,成本低,易實(shí)現(xiàn)等顯著優(yōu)點(diǎn)。當(dāng)紅外遙控器按下指令鍵時(shí),指令編碼電路產(chǎn)生所需的指令編碼信號(hào),指令編碼信號(hào)對(duì)載波進(jìn)行調(diào)制,再由驅(qū)動(dòng)電路進(jìn)行功率放大后由發(fā)射電路向外發(fā)射經(jīng)調(diào)制定的指令編碼信號(hào)。 紅外接收頭內(nèi)部電路包括紅外監(jiān)測(cè)二極管,放大器,限幅器,帶通濾波器,積分電路,比較器等。紅外接收頭將紅外遙控器發(fā)出的已調(diào)制的編碼指令信號(hào)接收下來(lái),并進(jìn)行放大和濾波后送解調(diào)電路,解調(diào)電路將已調(diào)制的指令編碼信號(hào)解調(diào)出來(lái),即還原為編碼信號(hào)。之后將編碼信號(hào)進(jìn)入單片機(jī)內(nèi)部進(jìn)行解碼,最后由驅(qū)動(dòng)電路來(lái)驅(qū)動(dòng)執(zhí)行電路實(shí)現(xiàn)各種指令的操作控制。 由于設(shè)計(jì)的計(jì)算器僅有加減乘除四則運(yùn)算,故紅外遙控設(shè)置的有效按鍵只需要數(shù)字鍵(0~9) 、符號(hào)鍵(+、-、*、/)、等號(hào)鍵、小數(shù)點(diǎn)鍵等16個(gè)按鍵即可。具體如圖4所示。
3.4 4*4鍵盤(pán)模塊考慮到軟件Proteus中無(wú)法進(jìn)行紅外遙控仿真,故在仿真環(huán)節(jié)將紅外遙控變?yōu)?*4鍵盤(pán),實(shí)物環(huán)節(jié)采用紅外遙控。4*4鍵盤(pán)鍵位設(shè)置與紅外遙控一樣包括數(shù)字鍵(0~9)、符號(hào)鍵(+、-、*、/)、等號(hào)鍵、小數(shù)點(diǎn)鍵等16個(gè)按鍵。 如果采用獨(dú)立按鍵的方式,在這種情況下,編程會(huì)很簡(jiǎn)單,但是會(huì)占用大量的I/O 口資源,為此,引入了矩陣鍵盤(pán)的應(yīng)用,采用四條I/O 線(xiàn)作為行線(xiàn),四條I/O 線(xiàn)作為列線(xiàn)組成鍵盤(pán)。在行線(xiàn)和列線(xiàn)的每個(gè)交叉點(diǎn)上設(shè)置一個(gè)按鍵。這樣鍵盤(pán)上按鍵的個(gè)數(shù)就為4×4個(gè)。這種行列式鍵盤(pán)結(jié)構(gòu)能有效地提高單片機(jī)系統(tǒng)中I/O 口的利用率,如圖5所示。具體如圖5所示。
3.5 LCD1602液晶顯示模塊LCD是一種工業(yè)型字符液晶,它能夠顯示32個(gè)字符(16列×2行),工作電壓為3.3V或5V,對(duì)比度可自行調(diào)節(jié),LCD的內(nèi)部?jī)?nèi)部含有復(fù)位電路,用來(lái)提供各種控制命令,如:清屏、字符閃爍、光標(biāo)閃爍、顯示移位等多種功能。由于LCD1602功耗低、體積小、顯示多樣,應(yīng)用較為廣泛。本次設(shè)計(jì)采用LCD1602無(wú)背光14腳接口,具體如圖6所示。
LCD1602各個(gè)管腳說(shuō)明如表1所示。 表1 LCD各管腳說(shuō)明 | | | | VSS VDD VEE RS RW E D0 D1 D2 D3 D4 D5 D6 D7 | 接地 電源正極 對(duì)比度調(diào)整 數(shù)據(jù)/命令 讀/寫(xiě) 使能信號(hào) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) 數(shù)據(jù) |
第1腳:VSS接地。 第2腳:VDD接3.3V或5V正電源。 第3腳:VEE端可以用來(lái)調(diào)整液晶對(duì)比度,接正電源時(shí)對(duì)比度最弱,接地時(shí)對(duì)比度最高。(對(duì)比度過(guò)高時(shí)會(huì) 產(chǎn)生“鬼影”,通常接一個(gè)10K的電位器調(diào)整對(duì)比度)。 第4腳:RS端為寄存器選擇端口,高電平時(shí)為數(shù)據(jù)寄存器、低電平時(shí)則是指令寄存器。 第5腳:R/W為讀寫(xiě)信號(hào)端口,高電平時(shí)進(jìn)行讀操作,低電平時(shí)進(jìn)行寫(xiě)操作。當(dāng)RS和R/W共同為低電平時(shí)可以寫(xiě)入指令或者顯示地址,當(dāng)RS為低電平R/W為高電平時(shí)可以讀忙信號(hào),當(dāng)RS為高電平R/W為低電平時(shí)可以寫(xiě)入數(shù)據(jù)。 第6腳:E端口為使能端,當(dāng)E端由高電平跳變成低電平時(shí),液晶模塊執(zhí)行命令。 第7~14腳:D0~D7為8位雙向數(shù)據(jù)線(xiàn)。 3.6 整體電路圖由于紅外遙控器在電路中無(wú)法模擬,因此在整體電路圖中采用了4*4鍵盤(pán)模擬。 采用4*4鍵盤(pán)時(shí)計(jì)算器系統(tǒng)運(yùn)行過(guò)程:使用者按下任意按鍵后,STC89C52檢測(cè)、識(shí)別出被使用者按下的相應(yīng)功能鍵,然后通過(guò)單片機(jī)內(nèi)部相關(guān)邏輯運(yùn)算,控制LCD1602 液晶屏顯示相應(yīng)鍵值。 采用紅外遙控時(shí)計(jì)算器系統(tǒng)運(yùn)行過(guò)程:使用者按下任意鍵后,紅外接收頭收到信號(hào),然后將信號(hào)還原為編碼信號(hào)后送入STC89C52,STC89C52解碼后,通過(guò)單片機(jī)內(nèi)部相關(guān)運(yùn)算,控制LCD1602 液晶屏顯示相應(yīng)鍵值。具體如圖7所示。
3.7 系統(tǒng)所用元器件本系統(tǒng)所用的元器件清單如表2所示。 表2 本系統(tǒng)所用的元器件
第4章 程序設(shè)計(jì) 4.1 整體程序設(shè)計(jì)程序?qū)崿F(xiàn)的具體功能為:任意整數(shù)(最大14位)或小數(shù)加減乘除運(yùn)算。 主程序流程圖如圖8所示。
如圖8所示,系統(tǒng)主要主要由主程序、紅外遙控輸入子程序、LCD顯示子程序、運(yùn)算部分組成。主程序主要完成初始化功能;紅外遙控器主要負(fù)責(zé)鍵入數(shù)據(jù),STC89C52進(jìn)行數(shù)據(jù)運(yùn)算。LCD液晶主要負(fù)責(zé)顯示輸入數(shù)據(jù)和輸出結(jié)果的工作;系統(tǒng)進(jìn)入工作時(shí)首先進(jìn)行初始化工作,之后系統(tǒng)將在循環(huán)以下這一過(guò)程:顯示,紅外信號(hào)接收,解碼處理,檢測(cè)輸入數(shù)據(jù)是否能夠正確進(jìn)行運(yùn)算處理,如果數(shù)據(jù)正確則進(jìn)行數(shù)據(jù)運(yùn)算,反之,報(bào)錯(cuò)后返回到按鍵,重新輸入。 4.2 接收紅外信號(hào)解碼子程序設(shè)計(jì)紅外信號(hào)接收子程序流程圖見(jiàn)圖9。 當(dāng)我們按下遙控器后,遙控器發(fā)出一幀數(shù)據(jù)。這一幀數(shù)據(jù)由前導(dǎo)碼、用戶(hù)碼高8位、用戶(hù)碼低8位、數(shù)據(jù)碼、數(shù)據(jù)反碼組成。其中前導(dǎo)碼為9ms高電平接著4.5ms低電平,標(biāo)志數(shù)據(jù)幀的開(kāi)始;用戶(hù)碼(共16位)為紅外接收器識(shí)別遙控器的身份的標(biāo)志,不同的遙控器一般用戶(hù)碼不同,以防止不同電器設(shè)備之間遙控碼的干擾;數(shù)據(jù)碼為紅外接收器識(shí)別遙控器上不同的按鍵的標(biāo)志,對(duì)同一遙控器來(lái)說(shuō),按不同的鍵所發(fā)出的二進(jìn)制編碼具有相同的用戶(hù)碼,不同的數(shù)據(jù)碼。當(dāng)紅外接收頭在遙控有效距離內(nèi),接收到紅外遙控脈沖信號(hào)后,由內(nèi)部轉(zhuǎn)換成電壓信號(hào)并經(jīng)放大、長(zhǎng)時(shí)控制、干擾抑制、帶通濾波并整形后輸出遙控代碼脈沖并送往單片機(jī)解碼。 單片機(jī)解碼就是將紅外接收頭輸出的脈沖還原為二進(jìn)制的“0”和“1”,得到二進(jìn)制“0”,“1”序列,進(jìn)而分析所含的用戶(hù)碼和數(shù)據(jù)碼。接收的用戶(hù)碼與設(shè)定的用戶(hù)碼正反碼相比較 ,接收的數(shù)據(jù)碼與設(shè)定的數(shù)據(jù)碼正反碼相比較,正反碼一樣后執(zhí)行后續(xù)程序。
4.3 LCD1602液晶顯示子程序設(shè)計(jì)LCD1602流程顯示如圖10所示。
由圖10可以看出LCD1602顯示的基本流程。顯示模塊程序首先要對(duì)顯示模塊進(jìn)行初始化,然后控制光標(biāo)的位置。然后設(shè)置清屏、顯示位置的首地址等等相關(guān)指令。 4.4 四則運(yùn)算子程序設(shè)計(jì)四則運(yùn)算流程如圖11所示。
運(yùn)算過(guò)程中,檢測(cè)到運(yùn)算符號(hào)時(shí),應(yīng)判斷運(yùn)算結(jié)果是否溢出,若是數(shù)據(jù)溢出,則LCD顯示錯(cuò)誤指令,反之?dāng)?shù)值顯示。特別是檢測(cè)到除號(hào)時(shí),應(yīng)判斷除數(shù)是否為0,若除數(shù)為0,則LCD顯示錯(cuò)誤指令,反之?dāng)?shù)值結(jié)果顯示。 第5章 仿真與調(diào)試 5.1 Proteus仿真第三章已提到過(guò)紅外遙控?zé)o法進(jìn)行仿真,所以在仿真中用4*4鍵盤(pán)代替紅外輸入。計(jì)算器系統(tǒng)仿真如圖12所示,圖中所舉例子運(yùn)算結(jié)果正確。
5.1.1 加法功能的調(diào)試 加法功能仿真如圖13所示。
 

加法功能能夠成功實(shí)現(xiàn)任意14位數(shù)以?xún)?nèi)的加法,若是數(shù)據(jù)溢出,則系統(tǒng)報(bào)錯(cuò)。 5.1.2 減法功能的調(diào)試減法功能仿真如圖14所示。  

減法功能能夠成功實(shí)現(xiàn)任意14位數(shù)以?xún)?nèi)的減法,若是數(shù)據(jù)溢出,則系統(tǒng)報(bào)錯(cuò)。 5.1.3 乘法功能的調(diào)試 乘法功能仿真如圖15所示
乘法功能能夠成功實(shí)現(xiàn)任意14位數(shù)以?xún)?nèi)的乘法,若是數(shù)據(jù)溢出,則系統(tǒng)報(bào)錯(cuò)。 5.1.4 除法功能的調(diào)試除法功能仿真如圖16所示
除法功能能夠成功實(shí)現(xiàn)任意14位數(shù)以?xún)?nèi)的除法,若是數(shù)據(jù)溢出或除數(shù)為0,則系統(tǒng)報(bào)錯(cuò)。 5.2 實(shí)物電路調(diào)試基于51單片機(jī)的紅外遙控計(jì)算器實(shí)物如圖17所示
實(shí)物調(diào)試過(guò)程中,遇到了LCD1602不顯示數(shù)據(jù)、按一次鍵出現(xiàn)好多個(gè)數(shù)據(jù)、紅外遙控按鍵與LCD1602顯示不對(duì)應(yīng)、計(jì)算結(jié)果顯示時(shí)間過(guò)短等問(wèn)題。不過(guò),最終都一一解決,LCD1602不顯示是由于程序中引腳沒(méi)能與與單片機(jī)內(nèi)部接線(xiàn)相一致,導(dǎo)致LCD1602無(wú)法正常運(yùn)行,故沒(méi)有顯示數(shù)據(jù)。而第二個(gè)問(wèn)題是由于沒(méi)有在程序中加入延時(shí)去抖動(dòng),導(dǎo)致系統(tǒng)對(duì)實(shí)際按鍵的錯(cuò)誤識(shí)別。第三個(gè)問(wèn)題是由于遙控器編碼與程序中沒(méi)有一一對(duì)應(yīng),導(dǎo)致按鍵沒(méi)有對(duì)應(yīng)。最后一個(gè)問(wèn)題同樣是由于延時(shí)程序問(wèn)題,好在最后都一一解決。
單片機(jī)源程序如下: - #include <reg52.h>
- #include <stdlib.h> //包含atof(),字符串->實(shí)數(shù)
- #include <stdio.h> //包含sprintf(),實(shí)數(shù)->字符串
- #include <string.h> //包含strcpy(),字符串復(fù)制
- #include <math.h> //數(shù)學(xué)函數(shù)頭文件
- #define uchar unsigned char
- #define uint unsigned int
- /*************lcd****************/
- sbit lcdrs=P2^6; //LCD控制腳
- sbit lcdrw=P2^5;
- sbit lcden=P2^7;
- bit idata form; //lcd顯示方式切換
- uchar idata state; //lcd狀態(tài)字存儲(chǔ)
- /************計(jì)算器*************/
- bit idata eqsign; //按等號(hào)標(biāo)志
- bit idata press; //鍵按標(biāo)志
- bit idata savesign; //可存儲(chǔ)結(jié)果標(biāo)志
- bit idata sc; //復(fù)用標(biāo)志
- uchar idata process[30],proc;
- uchar idata continu=0; //連續(xù)計(jì)算運(yùn)算符號(hào)存儲(chǔ)
- uchar idata ferror; //計(jì)算檢錯(cuò)標(biāo)志
- uchar idata ywei; //屏幕移位
- uchar idata count=0; //輸入計(jì)數(shù)
- uchar idata count_num=0; //組號(hào)計(jì)數(shù)
- uchar idata result[15]; //計(jì)算結(jié)果立存,save
- uchar idata jieguo[15]; //結(jié)果字符串
- uchar idata bdate[2][14]; //待計(jì)算字符串二維組
- uchar idata on_symbol; //運(yùn)算符號(hào)
- uchar idata fsym[2]; //函數(shù)前符號(hào)
- uchar idata ssym[2]; //存儲(chǔ)組前符號(hào)
- uchar idata bfun[2]; //計(jì)算值調(diào)用函數(shù)選擇
- double idata date[2]; //計(jì)算值雙精度變量組
- double idata resultdate; //雙精度結(jié)果值
- sbit IRIN=P3^2;
- uchar idata m=0;
- unsigned char IrValue[6];
-
-
- /******************函數(shù)聲明**********************/
-
- /***************延時(shí)******************/
- void delay(uchar z);
- /*************lcd寫(xiě)命令***************/
- void write_com(uchar com);
- /*************lcd寫(xiě)數(shù)據(jù)***************/
- void write_date(uchar date);
- /*************lcd讀狀態(tài)***************/
- void read_date(void);
- /*************lcd寫(xiě)字符串*************/
- void write_str(uchar *str);
- /************液晶初始化***************/
- void init(void );
- /**************鍵盤(pán)掃描***************/
- uchar keyscan(void);
- /*************計(jì)算器復(fù)位**************/
- void fuwei();
- /************error處理****************/
- void callerror(void);
- /***************撤銷(xiāo)鍵入**************/
- void huifu(void);
- /**********函數(shù)組前符號(hào)處理***********/
- uchar funqian(void);
- /************運(yùn)算符預(yù)處理*************/
- void cullars(uchar);
- /***********按鍵功能主處理************/
- void process_date(uchar press_date);
- /***********按鍵功能子處理************/
- void calculator(uchar press_date);
- /************************************************/
- /*************LCD程序****************/
- /**************延時(shí)******************/
- void DelayMs(unsigned int x);
- void IrInit();
- void ReadIr();
-
- void delay(uchar z)
- {
- uchar x,y;
- for(x=z;x>0;x--)
- for(y=115;y>0;y--);
- }
-
- void DelayMs(unsigned int x)
- {
- unsigned char i;
- while(x--)
- {
- for (i = 0; i<13; i++)
- {}
- }
- }
-
- void IrInit()
- {
- IT0=1; //下降沿觸發(fā)
- EX0=1; //打開(kāi)中斷0允許
- EA=1; //打開(kāi)總中斷
- IRIN=1; //初始化端口
- }
-
- /**************寫(xiě)命令*****************/
- void write_com(uchar com)
- {
- lcdrs=0;
- lcdrw=0;
- lcden=0;
- P0=com;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- /*************寫(xiě)數(shù)據(jù)******************/
- void write_date(uchar date)
- {
- lcdrs=1;
- lcdrw=0;
- lcden=0;
- P0=date;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- /*************讀狀態(tài)*****************/
- void read_date(void)
- {
- lcdrs=0;
- lcdrw=1;
- delay(5);
- P0=0xff;
- lcden=1;
- delay(5);
- state=P0;
- delay(5);
- lcden=0;delay(5);
- state=state&127;
- }
- /*************寫(xiě)字符串******************/
- void write_str(uchar *str)
- {
- uchar idata i;
- for(i=0;str[i]!='\0';i++)
- write_date(str[i]);
- }
- /***********液晶初始化***************/
- void init(void )
- {
- write_com(0x38); //模式:8位數(shù)據(jù),兩行,5*7字體
- write_com(0x0c); //開(kāi)顯示,無(wú)光標(biāo)
- write_com(0x06); //向左增量移動(dòng)
- write_com(0x01); //清屏
- }
-
-
- /**************鍵盤(pán)掃描*************/
- uchar keyscan()
- {
- uchar idata keyment=0;
- if(IrValue[2]!=0)
- {
- switch (IrValue[2])
- {
- case 0x42:{keyment='7';press=1;}break;
- case 0X52:{keyment='8';press=1;}break;
- case 0X4a:{keyment='9';press=1;}break;
- case 0X40:{keyment=0xfd;press=1;}break; //0xfd除號(hào)在1602液晶中的代碼
- case 0X08:{keyment='4';press=1;}break;
- case 0X1c:{keyment='5';press=1;}break;
- case 0X5a:{keyment='6';press=1;}break;
- case 0X44:{keyment='*';press=1;}break;
- case 0X0C:{keyment='1';press=1;}break;
- case 0X18:{keyment='2';press=1;}break;
- case 0X5E:{keyment='3';press=1;}break;
- case 0X07:{keyment='-';press=1;}break;
- case 0X16:{keyment='0';press=1;}break;
- case 0X19:{keyment='.';press=1;}break;
- case 0X43:{keyment='=';press=1;}break;
- case 0X15:{keyment='+';press=1;}break;
- default:break;
-
- }
-
- return(keyment);
-
- }
- }
-
-
- /**************計(jì)算器復(fù)位****************/
- void fuwei()
- { uchar idata j,i;
- write_com(0x0f); //lcd設(shè)置
- write_com(0x01);
- write_com(0x81);
- resultdate=0;
- for(i=0;i<2;i++)
- { date[i]=0;bfun[i]=0;fsym[i]=0;//各標(biāo)志置0
- for(j=0;j<14;j++) //字符數(shù)組初始化
- {
- bdate[i][j]='\0';
- }
- }
- count=0; //各標(biāo)志置0
- count_num=0;
- proc=0;
- ferror=0;
- eqsign=0;
- sc=0;
- savesign=0;
- ywei=0;
- press=0;
- on_symbol=0;
- }
- /**************error處理******************/
- void callerror(void)
- { uchar idata i;
- write_com(0x01);
- write_com(0x81);
- write_str(" error! ");
- for(i=0;i<200;i++)delay(25); //持續(xù)顯示 1s
- }
-
- /*****************運(yùn)算符預(yù)處理*****************/
- void cullars(uchar csym)
- { read_date(); //看第二組是否有輸入
- ferror++; //檢錯(cuò)標(biāo)志+1
- continu=csym; //存儲(chǔ)運(yùn)算符號(hào)
- write_date(continu);//將用與連續(xù)計(jì)算的運(yùn)算符號(hào)取出
- ywei=0;
- savesign=0;
- count_num=1; //組標(biāo)志加1
- count=0; //輸入計(jì)數(shù)清零
- on_symbol=continu; //運(yùn)算符號(hào)調(diào)用
- write_com(0xc2);
-
- return;
- }
-
- /**************按鍵功能主處理****************/
- void process_date(uchar press_date)
- {
- if(form==0){write_com(0x0f);form=1;} //顯示方式切換 光標(biāo)閃爍
- if(eqsign==1&&press==1)fuwei(); //復(fù)位再次計(jì)算
- press=0;
- if(press_date==0)return; //無(wú)按鍵
- process[proc]=press_date;
- proc++;
- calculator(press_date);
-
- return;
- }
- /***************按鍵功能子處理***************/
- void calculator(uchar press_date)
- {
- uchar idata j=0;
- /*************************************/
- IrValue[2]=0xff;
- if((press_date<='9'&&press_date>='0')||(press_date=='.')) //數(shù)字鍵處理
- { savesign=0; //不可更新存儲(chǔ)數(shù)據(jù)
- if(sc==0) //是否為復(fù)用sc為0,是數(shù)字
- {
- if(count<14-ywei) //未調(diào)用函數(shù)時(shí)最多輸入14位數(shù),包括小數(shù)點(diǎn)
- {
- write_date(press_date);
- bdate[count_num][count]=press_date; //儲(chǔ)存鍵值
- count++;
- }
- else {callerror();huifu();} //超出14位出錯(cuò),恢復(fù)
-
- }
- }
-
- /****************'+','-'處理*****************/
- else if((press_date=='+')||(press_date=='-'))
- {
- if(count==0) // 表示輸入數(shù)據(jù)的符號(hào),此時(shí)默認(rèn)數(shù)值為0
- {
- write_date(press_date);
- bdate[count_num][0]=press_date;
- bdate[count_num][1]='0';
- read_date(); //讀狀態(tài)
- write_date('0');
- write_com(state+0x81);//光標(biāo)還回原來(lái)位置
- count=1;
- }
- else //為運(yùn)算符號(hào)
- {
- cullars(press_date);
- }
- }
- /****************'*','/'處理*****************/
- else if(press_date==0xfd) //0xfd除號(hào)在1602液晶中的代碼
- {
- if(sc==1) //幅度 to 角度
- { if(count!=0)
- {sc=0;write_date(0xDF);count=14;}
- else {callerror();huifu();}
- }
- else cullars(press_date);
- }
- else if(press_date=='*') //0xfd除號(hào)在1602液晶中的代碼
- {
- cullars(press_date);
- }
- /*******************'='號(hào)處理*****************/
- else if(press_date=='=')
- {
- write_com(0x01); //清屏
- write_com(0x80+0x40+4);
- write_date(press_date); //顯示等號(hào)
- for(j=0;j<2;j++) //兩運(yùn)算組的函數(shù)處理
- {
- date[j]=atof(bdate[j]); //倆組數(shù)據(jù),字符串->實(shí)數(shù)
- if(fsym[j]=='-')date[j]=-date[j]; //函數(shù)前的符號(hào)處理
- }
- if(ferror==0) //僅僅函數(shù)計(jì)算
- { resultdate=date[0];}
- else //運(yùn)算符號(hào)計(jì)算
- {
- switch(on_symbol)
- {
- case '+':resultdate=date[0]+date[1];break;
- case '-':resultdate=date[0]-date[1];break;
- case '*':resultdate=date[0]*date[1];break;
- case 0xfd:resultdate=date[0]/date[1];break; //0xfd除號(hào)在1602液晶中的代碼
- }
- }
- sprintf(jieguo,"%g",resultdate);//結(jié)果實(shí)數(shù)->字符串,采用格式字符g,系統(tǒng)選擇%f或%e輸出格式,六位有效數(shù)字
- if((jieguo[0]>'9'||jieguo[0]<'0')&&(jieguo[1]>'9'||jieguo[1]<'0')&&jieguo[1]!='\0'&&jieguo[1]!='.')
- { callerror();fuwei();return; } //錯(cuò)誤處理,當(dāng)組1或組2不合法時(shí)結(jié)果是幾個(gè)英文字母提示
- else strcpy(result,jieguo); //沒(méi)錯(cuò)誤,保存結(jié)果
- for(j=0;jieguo[j]!='\0';j++) //顯示結(jié)果
- write_date(jieguo[j]);
- for(;j<15;j++)write_date(' '); //讓光標(biāo)出屏幕
- eqsign=1; //按等號(hào)鍵標(biāo)志置1
-
- }
- return;
- }
-
- /*********************主程序**********************/
- void main()
- {
- fuwei(); //計(jì)算器初始化
- init(); //顯示初始化
- form=1; //顯示方式初始化
- proc=0; //計(jì)算工程存儲(chǔ)初始化
- write_com(0x81);
- IrInit();
- while(1)
- {
-
- process_date(keyscan()); //計(jì)算器
- }
- }
-
- void ReadIr() interrupt 0
- {
- unsigned char j,k;
- unsigned int err;
- unsigned char Time;
- Time=0;
- DelayMs(70);
-
- if(IRIN==0) //確認(rèn)是否真的接收到正確的信號(hào)
- {
-
- err=1000; //1000*10us=10ms,超過(guò)說(shuō)明接收到錯(cuò)誤的信號(hào)
- /*當(dāng)兩個(gè)條件都為真是循環(huán),如果有一個(gè)條件為假的時(shí)候跳出循環(huán),免得程序出錯(cuò)的時(shí)
- 侯,程序死在這里*/
- while((IRIN==0)&&(err>0)) //等待前面9ms的低電平過(guò)去
- {
- DelayMs(1);
- err--;
- }
- if(IRIN==1) //如果正確等到9ms低電平
- {
- err=500;
- while((IRIN==1)&&(err>0)) //等待4.5ms的起始高電平過(guò)去
- {
- DelayMs(1);
- err--;
- }
- for(k=0;k<4;k++) //共有4組數(shù)據(jù)
- {
- for(j=0;j<8;j++) //接收一組數(shù)據(jù)
- {
-
- err=60;
- while((IRIN==0)&&(err>0))//等待信號(hào)前面的560us低電平過(guò)去
- {
- DelayMs(1);
- err--;
- }
- err=500;
- while((IRIN==1)&&(err>0)) //計(jì)算高電平的時(shí)間長(zhǎng)度。
- {
- DelayMs(1);//0.14ms
- Time++;
- err--;
- if(Time>30)
- {
- EX0=1;
- return;
- }
- }
- IrValue[k]>>=1; //k表示第幾組數(shù)據(jù)
- if(Time>=8) //如果高電平出現(xiàn)大于565us,那么是1
- {
- IrValue[k]|=0x80;
- }
- Time=0; //用完時(shí)間要重新賦值
- }
- }
- }
- if(IrValue[2]!=~IrValue[3])
- {
- return;
- }
- }
- }
-
-
-
-
-
- 附錄二:仿真源程序
- #include "reg52.h"
- #include <stdlib.h> //包含atof(),字符串->實(shí)數(shù)
- #include <stdio.h> //包含sprintf(),實(shí)數(shù)->字符串
- #include <string.h> //包含strcpy(),字符串復(fù)制
- #include <math.h> //數(shù)學(xué)函數(shù)頭文件
- #define uchar unsigned char
- #define uint unsigned int
- /*************lcd****************/
- sbit lcdrs=P2^7; //LCD控制腳
- sbit lcdrw=P2^6;
- sbit lcden=P2^5;
- bit idata form; //lcd顯示方式切換
- uchar idata state; //lcd狀態(tài)字存儲(chǔ)
- /************計(jì)算器*************/
- bit idata eqsign; //按等號(hào)標(biāo)志
- bit idata press; //鍵按標(biāo)志
- bit idata savesign; //可存儲(chǔ)結(jié)果標(biāo)志
- bit idata sc;
- uchar idata process[30],proc;
- uchar idata continu=0; //連續(xù)計(jì)算運(yùn)算符號(hào)存儲(chǔ)
- uchar idata ferror; //計(jì)算檢錯(cuò)標(biāo)志
- uchar idata ywei; //屏幕移位
- uchar idata count=0; //輸入計(jì)數(shù)
- uchar idata count_num=0; //組號(hào)計(jì)數(shù)
- uchar idata result[15]; //計(jì)算結(jié)果立存
- //uchar idata saveresult[15];//存儲(chǔ)結(jié)果數(shù)組
- uchar idata jieguo[15]; //結(jié)果字符串
- uchar idata bdate[2][14]; //待計(jì)算字符串二維組
- uchar idata on_symbol; //運(yùn)算符號(hào)
- uchar idata fsym[2]; //函數(shù)前符號(hào)
- uchar idata ssym[2]; //存儲(chǔ)組前符號(hào)
- uchar idata bfun[2]; //計(jì)算值調(diào)用函數(shù)選擇
- double idata date[2]; //計(jì)算值雙精度變量組
- double idata resultdate; //雙精度結(jié)果值
- /***************時(shí)鐘****************/
-
- /******************函數(shù)聲明**********************/
-
- /***************延時(shí)******************/
- void delay(uchar z);
- /*************lcd寫(xiě)命令***************/
- void write_com(uchar com);
- /*************lcd寫(xiě)數(shù)據(jù)***************/
- void write_date(uchar date);
- /*************lcd讀狀態(tài)***************/
- void read_date(void);
- /*************lcd寫(xiě)字符串*************/
- void write_str(uchar *str);
- /************液晶初始化***************/
- void init(void );
- /**************鍵盤(pán)掃描***************/
- uchar keyscan(void);
- /*************計(jì)算器復(fù)位**************/
- void fuwei();
- /************error處理****************/
- void callerror(void);
- /***************撤銷(xiāo)鍵入**************/
- void huifu(void);
- /**********函數(shù)組前符號(hào)處理***********/
- uchar funqian(void);
- /************運(yùn)算符預(yù)處理*************/
- void cullars(uchar);
- /***********按鍵功能主處理************/
- void process_date(uchar press_date);
- /***********按鍵功能子處理************/
- void calculator(uchar press_date);
- /************************************************/
- /*************LCD程序****************/
- /**************延時(shí)******************/
- void delay(uchar z) //0.2 ms
- {
- uchar x,y;
- for(x=z;x>0;x--)
- for(y=100;y>0;y--);
- }
-
- /**************寫(xiě)命令*****************/
- void write_com(uchar com)
- {
- lcdrs=0;
- ……………………
- …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼
以上文檔51hei提供下載:
|