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

QQ登錄

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

帖子
查看: 3780|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

51單片機(jī)紅外遙控計(jì)算器設(shè)計(jì)文檔

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:363782 發(fā)表于 2020-6-12 11:08 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
本設(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ō)明

編碼

引腳

引腳說(shuō)明

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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)所用的元器件

元器件名稱(chēng)
數(shù)量
30pf電容
1uf電解電容
2
1
100Ω電阻
1

STC89C52
1

LCD1602
1
排阻
1
滑動(dòng)變阻器
紅外接收頭
1
1

第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ī)源程序如下:
  1. #include <reg52.h>
  2. #include <stdlib.h>        //包含atof(),字符串->實(shí)數(shù)
  3. #include <stdio.h>         //包含sprintf(),實(shí)數(shù)->字符串
  4. #include <string.h>        //包含strcpy(),字符串復(fù)制
  5. #include <math.h>                               //數(shù)學(xué)函數(shù)頭文件
  6. #define uchar unsigned char
  7. #define uint unsigned int
  8. /*************lcd****************/
  9. sbit lcdrs=P2^6;           //LCD控制腳
  10. sbit lcdrw=P2^5;
  11. sbit lcden=P2^7;
  12. bit idata form;            //lcd顯示方式切換
  13. uchar idata state;         //lcd狀態(tài)字存儲(chǔ)
  14. /************計(jì)算器*************/
  15. bit idata eqsign;          //按等號(hào)標(biāo)志
  16. bit idata press;           //鍵按標(biāo)志
  17. bit idata savesign;        //可存儲(chǔ)結(jié)果標(biāo)志
  18. bit idata sc;                                             //復(fù)用標(biāo)志
  19. uchar idata process[30],proc;
  20. uchar idata continu=0;        //連續(xù)計(jì)算運(yùn)算符號(hào)存儲(chǔ)
  21. uchar idata ferror;        //計(jì)算檢錯(cuò)標(biāo)志
  22. uchar idata ywei;                               //屏幕移位
  23. uchar idata count=0;       //輸入計(jì)數(shù)
  24. uchar idata count_num=0;   //組號(hào)計(jì)數(shù)
  25. uchar idata result[15];    //計(jì)算結(jié)果立存,save
  26. uchar idata jieguo[15];    //結(jié)果字符串
  27. uchar idata bdate[2][14];  //待計(jì)算字符串二維組
  28. uchar idata on_symbol;     //運(yùn)算符號(hào)
  29. uchar idata fsym[2];       //函數(shù)前符號(hào)
  30. uchar idata ssym[2];       //存儲(chǔ)組前符號(hào)
  31. uchar idata bfun[2];       //計(jì)算值調(diào)用函數(shù)選擇
  32. double idata date[2];      //計(jì)算值雙精度變量組
  33. double idata resultdate;   //雙精度結(jié)果值                                
  34. sbit IRIN=P3^2;
  35. uchar idata m=0;
  36. unsigned char IrValue[6];


  37. /******************函數(shù)聲明**********************/

  38. /***************延時(shí)******************/
  39. void delay(uchar z);            
  40. /*************lcd寫(xiě)命令***************/
  41. void write_com(uchar com);
  42. /*************lcd寫(xiě)數(shù)據(jù)***************/
  43. void write_date(uchar date);
  44. /*************lcd讀狀態(tài)***************/
  45. void read_date(void);
  46. /*************lcd寫(xiě)字符串*************/
  47. void write_str(uchar *str);
  48. /************液晶初始化***************/
  49. void init(void );
  50. /**************鍵盤(pán)掃描***************/
  51. uchar keyscan(void);
  52. /*************計(jì)算器復(fù)位**************/
  53. void fuwei();         
  54. /************error處理****************/
  55. void callerror(void);
  56. /***************撤銷(xiāo)鍵入**************/
  57. void huifu(void);
  58. /**********函數(shù)組前符號(hào)處理***********/
  59. uchar funqian(void);
  60. /************運(yùn)算符預(yù)處理*************/
  61. void  cullars(uchar);
  62. /***********按鍵功能主處理************/
  63. void process_date(uchar press_date);
  64. /***********按鍵功能子處理************/
  65. void calculator(uchar press_date);
  66. /************************************************/
  67. /*************LCD程序****************/
  68. /**************延時(shí)******************/
  69. void DelayMs(unsigned int x);
  70. void IrInit();
  71. void ReadIr();

  72. void delay(uchar z)                                         
  73. {
  74.       uchar  x,y;
  75.       for(x=z;x>0;x--)
  76.       for(y=115;y>0;y--);
  77. }

  78. void DelayMs(unsigned int x)  
  79. {
  80.               unsigned char i;
  81.               while(x--)
  82.               {
  83.                             for (i = 0; i<13; i++)
  84.                             {}
  85.               }
  86. }

  87. void IrInit()
  88. {
  89.               IT0=1;              //下降沿觸發(fā)
  90.               EX0=1;              //打開(kāi)中斷0允許
  91.               EA=1;              //打開(kāi)總中斷
  92.               IRIN=1;              //初始化端口
  93. }

  94. /**************寫(xiě)命令*****************/
  95. void write_com(uchar com)
  96. {
  97.       lcdrs=0;
  98.       lcdrw=0;
  99.       lcden=0;
  100.       P0=com;
  101.       delay(5);
  102.       lcden=1;
  103.       delay(5);
  104.       lcden=0;
  105. }
  106. /*************寫(xiě)數(shù)據(jù)******************/
  107. void write_date(uchar date)
  108. {
  109.       lcdrs=1;
  110.       lcdrw=0;
  111.       lcden=0;
  112.       P0=date;
  113.       delay(5);
  114.       lcden=1;
  115.       delay(5);
  116.       lcden=0;
  117. }
  118. /*************讀狀態(tài)*****************/
  119. void read_date(void)
  120. {
  121.       lcdrs=0;
  122.       lcdrw=1;
  123.                 delay(5);
  124.                 P0=0xff;
  125.       lcden=1;
  126.       delay(5);
  127.       state=P0;
  128.       delay(5);
  129.       lcden=0;delay(5);
  130.                 state=state&127;
  131. }
  132. /*************寫(xiě)字符串******************/
  133. void write_str(uchar *str)
  134. {   
  135.       uchar idata i;
  136.       for(i=0;str[i]!='\0';i++)
  137.          write_date(str[i]);
  138. }
  139. /***********液晶初始化***************/
  140. void init(void )
  141. {
  142.       write_com(0x38);       //模式:8位數(shù)據(jù),兩行,5*7字體
  143.       write_com(0x0c);       //開(kāi)顯示,無(wú)光標(biāo)
  144.       write_com(0x06);       //向左增量移動(dòng)
  145.       write_com(0x01);       //清屏
  146. }


  147. /**************鍵盤(pán)掃描*************/
  148. uchar keyscan()
  149. {
  150.               uchar idata keyment=0;
  151.               if(IrValue[2]!=0)
  152.               {
  153.               switch (IrValue[2])
  154.                             {
  155.                                           case 0x42:{keyment='7';press=1;}break;
  156.                                           case 0X52:{keyment='8';press=1;}break;
  157.                                           case 0X4a:{keyment='9';press=1;}break;
  158.                                           case 0X40:{keyment=0xfd;press=1;}break; //0xfd除號(hào)在1602液晶中的代碼
  159.                                           case 0X08:{keyment='4';press=1;}break;
  160.                                           case 0X1c:{keyment='5';press=1;}break;
  161.                                           case 0X5a:{keyment='6';press=1;}break;
  162.                                           case 0X44:{keyment='*';press=1;}break;
  163.                                           case 0X0C:{keyment='1';press=1;}break;
  164.                                           case 0X18:{keyment='2';press=1;}break;
  165.                                           case 0X5E:{keyment='3';press=1;}break;
  166.                                           case 0X07:{keyment='-';press=1;}break;
  167.                                           case 0X16:{keyment='0';press=1;}break;
  168.                                           case 0X19:{keyment='.';press=1;}break;
  169.                                           case 0X43:{keyment='=';press=1;}break;
  170.                                           case 0X15:{keyment='+';press=1;}break;
  171.                                           default:break;
  172.                            
  173.                             }
  174.             
  175.               return(keyment);
  176.             
  177.               }            
  178. }


  179. /**************計(jì)算器復(fù)位****************/
  180. void fuwei()
  181. {   uchar idata j,i;
  182.     write_com(0x0f);                  //lcd設(shè)置
  183.     write_com(0x01);
  184.     write_com(0x81);
  185.     resultdate=0;
  186.     for(i=0;i<2;i++)
  187.               { date[i]=0;bfun[i]=0;fsym[i]=0;//各標(biāo)志置0
  188.                 for(j=0;j<14;j++)                            //字符數(shù)組初始化
  189.       {            
  190.         bdate[i][j]='\0';
  191.       }
  192.               }
  193.     count=0;                                                        //各標(biāo)志置0
  194.     count_num=0;
  195.               proc=0;
  196.     ferror=0;
  197.     eqsign=0;
  198.               sc=0;
  199.               savesign=0;
  200.               ywei=0;
  201.               press=0;
  202.               on_symbol=0;
  203. }
  204. /**************error處理******************/
  205. void callerror(void)
  206. {   uchar idata i;
  207.     write_com(0x01);
  208.     write_com(0x81);
  209.     write_str("     error!     ");
  210.     for(i=0;i<200;i++)delay(25); //持續(xù)顯示 1s
  211. }

  212. /*****************運(yùn)算符預(yù)處理*****************/
  213. void  cullars(uchar csym)
  214. {              read_date();                               //看第二組是否有輸入
  215.               ferror++;              //檢錯(cuò)標(biāo)志+1
  216.               continu=csym;                               //存儲(chǔ)運(yùn)算符號(hào)
  217.               write_date(continu);//將用與連續(xù)計(jì)算的運(yùn)算符號(hào)取出
  218.               ywei=0;                                                         
  219.               savesign=0;
  220.               count_num=1;     //組標(biāo)志加1
  221.               count=0;                            //輸入計(jì)數(shù)清零
  222.               on_symbol=continu;  //運(yùn)算符號(hào)調(diào)用
  223.               write_com(0xc2);
  224.             
  225.               return;
  226. }

  227. /**************按鍵功能主處理****************/
  228. void process_date(uchar press_date)
  229. {   
  230.      if(form==0){write_com(0x0f);form=1;}   //顯示方式切換 光標(biāo)閃爍            
  231.      if(eqsign==1&&press==1)fuwei();                            //復(fù)位再次計(jì)算
  232.               press=0;
  233.               if(press_date==0)return;                       //無(wú)按鍵
  234.               process[proc]=press_date;
  235.               proc++;
  236.               calculator(press_date);
  237.             
  238.               return;
  239. }
  240. /***************按鍵功能子處理***************/
  241. void calculator(uchar press_date)
  242. {            
  243.      uchar idata j=0;
  244.               /*************************************/
  245.               IrValue[2]=0xff;
  246.               if((press_date<='9'&&press_date>='0')||(press_date=='.')) //數(shù)字鍵處理
  247.      {              savesign=0;                                            //不可更新存儲(chǔ)數(shù)據(jù)
  248.         if(sc==0)                                            //是否為復(fù)用sc為0,是數(shù)字
  249.         {
  250.            if(count<14-ywei)  //未調(diào)用函數(shù)時(shí)最多輸入14位數(shù),包括小數(shù)點(diǎn)
  251.            {            
  252.                                                  write_date(press_date);
  253.                    bdate[count_num][count]=press_date; //儲(chǔ)存鍵值
  254.                    count++;
  255.            }
  256.            else {callerror();huifu();}  //超出14位出錯(cuò),恢復(fù)

  257.         }
  258.       }

  259.       /****************'+','-'處理*****************/
  260.        else if((press_date=='+')||(press_date=='-'))
  261.        {   
  262.                                   if(count==0)      // 表示輸入數(shù)據(jù)的符號(hào),此時(shí)默認(rèn)數(shù)值為0
  263.               {                                                              
  264.                 write_date(press_date);
  265.                 bdate[count_num][0]=press_date;
  266.                                                         bdate[count_num][1]='0';
  267.                                                         read_date();                                          //讀狀態(tài)
  268.                           write_date('0');
  269.                           write_com(state+0x81);//光標(biāo)還回原來(lái)位置
  270.                 count=1;
  271.               }
  272.               else                                             //為運(yùn)算符號(hào)
  273.               {  
  274.                                               cullars(press_date);
  275.               }                                         
  276.        }                                         
  277.        /****************'*','/'處理*****************/
  278.        else if(press_date==0xfd) //0xfd除號(hào)在1602液晶中的代碼
  279.        {            
  280.                      if(sc==1)                 //幅度 to 角度
  281.                                {  if(count!=0)
  282.                                   {sc=0;write_date(0xDF);count=14;}
  283.                                             else {callerror();huifu();}
  284.                                }
  285.                       else cullars(press_date);
  286.        }
  287.                  else if(press_date=='*') //0xfd除號(hào)在1602液晶中的代碼
  288.        {                                 
  289.                        cullars(press_date);
  290.        }
  291.        /*******************'='號(hào)處理*****************/
  292.        else if(press_date=='=')
  293.        {
  294.             write_com(0x01);           //清屏
  295.             write_com(0x80+0x40+4);
  296.             write_date(press_date);    //顯示等號(hào)
  297.                                 for(j=0;j<2;j++)                               //兩運(yùn)算組的函數(shù)處理
  298.                                           {
  299.                                                            date[j]=atof(bdate[j]);  //倆組數(shù)據(jù),字符串->實(shí)數(shù)
  300.                                                         if(fsym[j]=='-')date[j]=-date[j];              //函數(shù)前的符號(hào)處理
  301.                                           }
  302.                                           if(ferror==0)                                                                                                  //僅僅函數(shù)計(jì)算
  303.                                              {  resultdate=date[0];}
  304.             else                                                                                                                              //運(yùn)算符號(hào)計(jì)算
  305.                                           {
  306.                                              switch(on_symbol)
  307.                {
  308.                   case '+':resultdate=date[0]+date[1];break;
  309.                   case '-':resultdate=date[0]-date[1];break;
  310.                   case '*':resultdate=date[0]*date[1];break;
  311.                   case 0xfd:resultdate=date[0]/date[1];break;       //0xfd除號(hào)在1602液晶中的代碼
  312.                }
  313.                                           }                                         
  314.             sprintf(jieguo,"%g",resultdate);//結(jié)果實(shí)數(shù)->字符串,采用格式字符g,系統(tǒng)選擇%f或%e輸出格式,六位有效數(shù)字         
  315.                       if((jieguo[0]>'9'||jieguo[0]<'0')&&(jieguo[1]>'9'||jieguo[1]<'0')&&jieguo[1]!='\0'&&jieguo[1]!='.')
  316.                                           {   callerror();fuwei();return;  }              //錯(cuò)誤處理,當(dāng)組1或組2不合法時(shí)結(jié)果是幾個(gè)英文字母提示            
  317.                                           else strcpy(result,jieguo);   //沒(méi)錯(cuò)誤,保存結(jié)果                                                                                                                              
  318.             for(j=0;jieguo[j]!='\0';j++)               //顯示結(jié)果
  319.                  write_date(jieguo[j]);
  320.                                           for(;j<15;j++)write_date(' ');              //讓光標(biāo)出屏幕
  321.                                           eqsign=1;                                                                                    //按等號(hào)鍵標(biāo)志置1
  322.                                          
  323.                  }
  324.                  return;
  325. }            
  326.                                                                                                                                           
  327. /*********************主程序**********************/
  328. void main()
  329. {  
  330.       fuwei();                            //計(jì)算器初始化
  331.       init();       //顯示初始化               
  332.                 form=1;                            //顯示方式初始化
  333.                 proc=0;                            //計(jì)算工程存儲(chǔ)初始化
  334.                 write_com(0x81);
  335.                 IrInit();
  336.       while(1)     
  337.       {
  338.                
  339.                  process_date(keyscan()); //計(jì)算器
  340.       }
  341. }

  342. void ReadIr() interrupt 0
  343. {
  344.               unsigned char j,k;
  345.               unsigned int err;
  346.               unsigned char Time;
  347.               Time=0;                                                                     
  348.               DelayMs(70);

  349.               if(IRIN==0)                            //確認(rèn)是否真的接收到正確的信號(hào)
  350.               {            
  351.                            
  352.                             err=1000;                                                        //1000*10us=10ms,超過(guò)說(shuō)明接收到錯(cuò)誤的信號(hào)
  353.                             /*當(dāng)兩個(gè)條件都為真是循環(huán),如果有一個(gè)條件為假的時(shí)候跳出循環(huán),免得程序出錯(cuò)的時(shí)
  354.                             侯,程序死在這里*/            
  355.                             while((IRIN==0)&&(err>0))              //等待前面9ms的低電平過(guò)去                             
  356.                             {                                         
  357.                                           DelayMs(1);
  358.                                           err--;
  359.                             }
  360.                             if(IRIN==1)                                          //如果正確等到9ms低電平
  361.                             {
  362.                                           err=500;
  363.                                           while((IRIN==1)&&(err>0))                            //等待4.5ms的起始高電平過(guò)去
  364.                                           {
  365.                                                         DelayMs(1);
  366.                                                         err--;
  367.                                           }
  368.                                           for(k=0;k<4;k++)                            //共有4組數(shù)據(jù)
  369.                                           {                                                      
  370.                                                         for(j=0;j<8;j++)              //接收一組數(shù)據(jù)
  371.                                                         {

  372.                                                                       err=60;                           
  373.                                                                       while((IRIN==0)&&(err>0))//等待信號(hào)前面的560us低電平過(guò)去
  374.                                                                       {
  375.                                                                                     DelayMs(1);
  376.                                                                                     err--;
  377.                                                                       }
  378.                                                                       err=500;
  379.                                                                       while((IRIN==1)&&(err>0))              //計(jì)算高電平的時(shí)間長(zhǎng)度。
  380.                                                                       {
  381.                                                                                     DelayMs(1);//0.14ms
  382.                                                                                     Time++;
  383.                                                                                     err--;
  384.                                                                                     if(Time>30)
  385.                                                                                     {
  386.                                                                                                   EX0=1;
  387.                                                                                                   return;
  388.                                                                                     }
  389.                                                                       }
  390.                                                                       IrValue[k]>>=1;              //k表示第幾組數(shù)據(jù)
  391.                                                                       if(Time>=8)                                          //如果高電平出現(xiàn)大于565us,那么是1
  392.                                                                       {
  393.                                                                                     IrValue[k]|=0x80;
  394.                                                                       }
  395.                                                                       Time=0;                            //用完時(shí)間要重新賦值                                                                                                
  396.                                                         }
  397.                                           }
  398.                             }
  399.                             if(IrValue[2]!=~IrValue[3])
  400.                             {
  401.                                           return;
  402.                             }
  403.               }                                         
  404. }





  405. 附錄二:仿真源程序
  406. #include "reg52.h"
  407. #include <stdlib.h>        //包含atof(),字符串->實(shí)數(shù)
  408. #include <stdio.h>         //包含sprintf(),實(shí)數(shù)->字符串
  409. #include <string.h>        //包含strcpy(),字符串復(fù)制
  410. #include <math.h>                               //數(shù)學(xué)函數(shù)頭文件
  411. #define uchar unsigned char
  412. #define uint unsigned int
  413. /*************lcd****************/
  414. sbit lcdrs=P2^7;           //LCD控制腳
  415. sbit lcdrw=P2^6;
  416. sbit lcden=P2^5;
  417. bit idata form;            //lcd顯示方式切換
  418. uchar idata state;         //lcd狀態(tài)字存儲(chǔ)
  419. /************計(jì)算器*************/
  420. bit idata eqsign;          //按等號(hào)標(biāo)志
  421. bit idata press;           //鍵按標(biāo)志
  422. bit idata savesign;        //可存儲(chǔ)結(jié)果標(biāo)志
  423. bit idata sc;                                             
  424. uchar idata process[30],proc;
  425. uchar idata continu=0;        //連續(xù)計(jì)算運(yùn)算符號(hào)存儲(chǔ)
  426. uchar idata ferror;        //計(jì)算檢錯(cuò)標(biāo)志
  427. uchar idata ywei;                               //屏幕移位
  428. uchar idata count=0;       //輸入計(jì)數(shù)
  429. uchar idata count_num=0;   //組號(hào)計(jì)數(shù)
  430. uchar idata result[15];    //計(jì)算結(jié)果立存
  431. //uchar idata saveresult[15];//存儲(chǔ)結(jié)果數(shù)組
  432. uchar idata jieguo[15];    //結(jié)果字符串
  433. uchar idata bdate[2][14];  //待計(jì)算字符串二維組
  434. uchar idata on_symbol;     //運(yùn)算符號(hào)
  435. uchar idata fsym[2];       //函數(shù)前符號(hào)
  436. uchar idata ssym[2];       //存儲(chǔ)組前符號(hào)
  437. uchar idata bfun[2];       //計(jì)算值調(diào)用函數(shù)選擇
  438. double idata date[2];      //計(jì)算值雙精度變量組
  439. double idata resultdate;   //雙精度結(jié)果值
  440. /***************時(shí)鐘****************/

  441. /******************函數(shù)聲明**********************/

  442. /***************延時(shí)******************/
  443. void delay(uchar z);            
  444. /*************lcd寫(xiě)命令***************/
  445. void write_com(uchar com);
  446. /*************lcd寫(xiě)數(shù)據(jù)***************/
  447. void write_date(uchar date);
  448. /*************lcd讀狀態(tài)***************/
  449. void read_date(void);
  450. /*************lcd寫(xiě)字符串*************/
  451. void write_str(uchar *str);
  452. /************液晶初始化***************/
  453. void init(void );
  454. /**************鍵盤(pán)掃描***************/
  455. uchar keyscan(void);
  456. /*************計(jì)算器復(fù)位**************/
  457. void fuwei();         
  458. /************error處理****************/
  459. void callerror(void);
  460. /***************撤銷(xiāo)鍵入**************/
  461. void huifu(void);
  462. /**********函數(shù)組前符號(hào)處理***********/
  463. uchar funqian(void);
  464. /************運(yùn)算符預(yù)處理*************/
  465. void  cullars(uchar);
  466. /***********按鍵功能主處理************/
  467. void process_date(uchar press_date);
  468. /***********按鍵功能子處理************/
  469. void calculator(uchar press_date);
  470. /************************************************/
  471. /*************LCD程序****************/
  472. /**************延時(shí)******************/
  473. void delay(uchar z)                                             //0.2 ms
  474. {
  475.       uchar  x,y;
  476.       for(x=z;x>0;x--)
  477.       for(y=100;y>0;y--);
  478. }

  479. /**************寫(xiě)命令*****************/
  480. void write_com(uchar com)
  481. {
  482.       lcdrs=0;
  483. ……………………
  484. …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼

以上文檔51hei提供下載:
基于51單片機(jī)的紅外遙控計(jì)算器.doc (9.77 MB, 下載次數(shù): 34)

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

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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