題 目:基于單片機簡易計算器的設計
院 (系):信息與通信學院
專 業(yè): 電子信息工程
摘 要
簡易計算器是一種非常廣泛日常工具,對現(xiàn)代社會越來越流行。它可以進行一些簡易的計算。本系統(tǒng)提供詳細的時、分、秒、年、月、日的時間信息,同時還可進行簡易的計算信息,還具有時間校準等功能。該電路采用AT89S52單片機作為核心,功耗小,能在3V的低壓工作,電壓可選用3~5V電壓供電。本系統(tǒng)硬件部分由AT89S52單片機、LCD1602液晶屏、鍵盤、指示燈系統(tǒng)等部分構(gòu)成。軟件部分在keil環(huán)境下用C51語言編寫,包括時間設置、時間顯示、簡易計算顯示等。
目錄
摘要1
引言 3
1 單片機及其應用3
11單片機介紹3
12單片機的應用4
13 AT89S52單片機4
2 液晶屏LCD1602原理及應用 7
21液晶屏LCD1602介紹及工作原理 7
22 液晶屏LCD1602的功能及應用7
3 設計思路、仿真及調(diào)試12
31設計方法12
32硬件設計 12
321按鍵調(diào)整電路12
322復位電路13
323 液晶屏LCD1602顯示電路13
324 LED指示電路13
325 4*4鍵盤的設計14
326 簡易計算器的總電路14
33軟件設計 15
34軟件仿真15
35硬件調(diào)試16
4 結(jié)束語 17
謝辭18
參考文獻19
附件20
引言 眾所周知單片機是一種集成在電路芯片,是采用超大規(guī)模集成電路技術(shù)把具有數(shù)據(jù)處理能力的中央處理器CPU隨機存儲器RAM、只讀存儲器ROM、多種I/O口和中斷系統(tǒng)、定時器/計時器等功能(可能還包括顯示驅(qū)動電路、脈寬調(diào)制電路、模擬多路轉(zhuǎn)換器、A/D轉(zhuǎn)換器等電路)集成到一塊硅片上構(gòu)成的一個小而完善的計算機系統(tǒng)。本設計要制作的就是單片機于生活中最為常見的異種應用——簡易計算器。本簡易計算器AT89S52單片機作為核心,可以顯示簡易的計算和時間,時間可以人為設定;另外還可以顯示當前的日歷,顯示格式為年(四位),月(兩位),日(兩位)。設置時間時的位切換、設定數(shù)值、啟動定時器、切換日歷通過外部中斷來實現(xiàn)。簡易計算器不僅可以進行簡易的計算還可以顯示時間。簡易計算器顯示電路由LCD1602組成, 制作一個單片機計時裝置需要的材料需要有軟硬件的支持,硬件方面AT89C51單片機,晶振,電源,液晶屏LCD1602。 單片機是一種集成在電路芯片,是采用超大規(guī)模集成電路技術(shù)把具有數(shù)據(jù)處理能力的中央處理器CPU隨機存儲器RAM、只讀存儲器ROM、多種I/O口和中斷系統(tǒng)、定時器/計時器等功能(可能還包括顯示驅(qū)動電路、脈寬調(diào)制電路、模擬多路轉(zhuǎn)換器、A/D轉(zhuǎn)換器等電路)集成到一塊硅片上構(gòu)成的一個小而完善的計算機系統(tǒng)。
1.1 單片機介紹: 單片微型計算機簡稱單片機,是典型的嵌入式微控制器(Microcontroller Unit),常用英文字母的縮寫MCU表示單片機,它最早是被用在工業(yè)控制領(lǐng)域。單片機由芯片內(nèi)僅有CPU的專用處理器發(fā)展而來。最早的設計理念是通過將大量外圍設備和CPU集成在一個芯片中,使計算機系統(tǒng)更小,更容易集成進復雜的而對體積要求嚴格的控制設備當中。INTEL的Z80是最早按照這種思想設計出的處理器,從此以后,單片機和專用處理器的發(fā)展便分道揚鑣 單片機是靠程序運行的,并且可以修改。通過不同的程序?qū)崿F(xiàn)不同的功能,尤其是特殊的獨特的一些功能,這是別的器件需要費很大力氣才能做到的,有些則是花大力氣也很難做到的。一個不是很復雜的功能要是用美國50年代開發(fā)的74系列,或者60年代的CD4000系列這些純硬件來搞定的話,電路一定是一塊大PCB板!但是如果要是用美國70年代成功投放市場的系列單片機,結(jié)果就會有天壤之別!只因為單片機的通過你編寫的程序可以實現(xiàn)高智能,高效率,以及高可靠性! 單片機的硬件特性:單片機集成度高。單片機包括CPU、4KB容量的ROM(8031 無)、128 B容量的RAM、 2個16位定時/計數(shù)器、4個8位并行口、全雙工串口行口。系統(tǒng)結(jié)構(gòu)簡單,使用方便,實現(xiàn)模塊化。
1.2 單片機的應用 目前單片機滲透到我們生活的各個領(lǐng)域,幾乎很難找到哪個領(lǐng)域沒有單片機的蹤跡。導彈的導航裝置,飛機上各種儀表的控制,計算機的網(wǎng)絡通訊與數(shù)據(jù)傳輸,工業(yè)自動化過程的實時控制和數(shù)據(jù)處理,廣泛使用的各種智能IC卡,民用豪華轎車的安全保障系統(tǒng),錄像機、攝像機、全自動洗衣機的控制,以及程控玩具、電子寵物等等,這些都離不開單片機。更不用說自動控制領(lǐng)域的機器人、智能儀表、醫(yī)療器械了。因此,單片機的學習、開發(fā)與應用將造就一批計算機應用與智能化控制的科學家、工程師。單片機廣泛應用于儀器儀表、家用電器、醫(yī)用設備、航空航天、專用設備的智能化管理及過程控制等領(lǐng)域,大致可分如下幾個范疇: (1)在智能儀器儀表上的應用 (2)在工業(yè)控制中的應用 (3)在家用電器中的應用 (4)在計算機網(wǎng)絡和通信領(lǐng)域中的應用 (5)單片機在醫(yī)用設備領(lǐng)域中的應用 (6)在各種大型電器中的模塊化應用 (7)單片機在汽車設備領(lǐng)域中的應用 此外,單片機在工商,金融,科研、教育,國防航空航天等領(lǐng)域都有著十分廣泛的用途。
1.3 AT89S52單片機 AT89S52是一種低功耗、高性能CMOS8位微控制器,具有8K 在系統(tǒng)可編程Flash 存儲器。使用Atmel 公司高密度非易失性存儲器技術(shù)制造,與工業(yè)80C51 產(chǎn)品指令和引腳完全兼容。片上Flash允許程序存儲器在系統(tǒng)可編程,亦適于常規(guī)編程器。在單芯片上,擁有靈巧的8 位CPU 和在系統(tǒng)可編程Flash,使AT89S52為眾多嵌入式控制應用系統(tǒng)提供高靈活、超有效的解決方案。 AT89S52具有以下標準功能: 8k字節(jié)Flash,256字節(jié)RAM,32 位I/O 口線,看門狗定時器,2 個數(shù)據(jù)指針,三個16 位定時器/計數(shù)器,一個6向量2級中斷結(jié)構(gòu),全雙工串行口,片內(nèi)晶振及時鐘電路。另外,AT89S52 可降至0Hz 靜態(tài)邏輯操作,支持2種軟件可選擇節(jié)電模式。空閑模式下,CPU停止工作,允許RAM、定時器/計數(shù)器、串口、中斷繼續(xù)工作。掉電保護方式下,RAM內(nèi)容被保存,振蕩器被凍結(jié),單片機一切工作停止,直到下一個中斷或硬件復位為止。 主要性能 1、與MCS-51單片機產(chǎn)品兼容 2 、8K字節(jié)在系統(tǒng)可編程Flash存儲器 3 、1000次擦寫周期 4 、全靜態(tài)操作:0Hz~33Hz 5 、三級加密程序存儲器 6 、32個可編程I/O口線 7 、三個16位定時器/計數(shù)器 8、八個中斷源 9、全雙工UART串行通道 10、 低功耗空閑和掉電模式 l 1、掉電后中斷可喚醒 l 2、看門狗定時器 l3、 雙數(shù)據(jù)指針 l4、 掉電標識符 引腳結(jié)構(gòu) P0 口:P0口是一個8位漏極開路的雙向I/O口。作為輸出口,每位能驅(qū)動8個TTL邏輯電平。對P0端口寫“1”時,引腳用作高阻抗輸入。當訪問外部程序和數(shù)據(jù)存儲器時,P0口也被作為低8位地址/數(shù)據(jù)復用。在這種模式下,P0具有內(nèi)部上拉電阻。在flash編程時,P0口也用來接收指令字節(jié);在程序校驗時,輸出指令字節(jié)。程序校驗時,需要外部上拉電阻。 P1 口:P1 口是一個具有內(nèi)部上拉電阻的8 位雙向I/O 口,p1 輸出緩沖器能驅(qū)動4 個TTL 邏輯電平。對P1 端口寫“1”時,內(nèi)部上拉電阻把端口拉高,此時可以作為輸入口使用。作為輸入使用時,被外部拉低的引腳由于內(nèi)部電阻的原因,將輸出電流(IIL)。此外,P1.0和P1.2分別作定時器/計數(shù)器2的外部計數(shù)輸入(P1.0/T2)和時器/計數(shù)器2的觸發(fā)輸入(P1.1/T2EX),具體如下表所示。在flash編程和校驗時,P1口接收低8位地址字節(jié)。 引腳號第二功能 P1.0 T2(定時器/計數(shù)器T2的外部計數(shù)輸入),時鐘輸出 P1.1 T2EX(定時器/計數(shù)器T2的捕捉/重載觸發(fā)信號和方向控制) P1.5 MOSI(在系統(tǒng)編程用) P1.6 MISO(在系統(tǒng)編程用) P1.7 SCK(在系統(tǒng)編程用) P2 口:P2 口是一個具有內(nèi)部上拉電阻的8 位雙向I/O 口,P2 輸出緩沖器能驅(qū)動4 個TTL 邏輯電平。對P2 端口寫“1”時,內(nèi)部上拉電阻把端口拉高,此時可以作為輸入口使用。作為輸入使用時,被外部拉低的引腳由于內(nèi)部電阻的原因,將輸出電流(IIL)。在訪問外部程序存儲器或用16位地址讀取外部數(shù)據(jù)存儲器(例如執(zhí)行MOVX @DPTR)時,P2 口送出高八位地址。在這種應用中,P2 口使用很強的內(nèi)部上拉發(fā)送1。在使用8位地址(如MOVX @RI)訪問外部數(shù)據(jù)存儲器時,P2口輸出P2鎖存器的內(nèi)容。在flash編程和校驗時,P2口也接收高8位地址字節(jié)和一些控制信號。P3 口:P3 口是一個具有內(nèi)部上拉電阻的8 位雙向I/O 口,p2 輸出緩沖器能驅(qū)動4 個TTL 邏輯電平。對P3 端口寫“1”時,內(nèi)部上拉電阻把端口拉高,此時可以作為輸入口使用。作為輸入使用時,被外部拉低的引腳由于內(nèi)部電阻的原因,將輸出電流(IIL)。 P3口亦作為AT89S52特殊功能(第二功能)使用,如下表所示。在flash編程和校驗時,P3口也接收一些控制信號。 引腳號第二功能 P3.0 RXD(串行輸入) P3.1 TXD(串行輸出) P3.2 INT0(外部中斷0) P3.3 INT0(外部中斷0) P3.4 T0(定時器0外部輸入) P3.5 T1(定時器1外部輸入) P3.6 WR(外部數(shù)據(jù)存儲器寫選通) P3.7 RD(外部數(shù)據(jù)存儲器寫選通) RST: 復位輸入。晶振工作時,RST腳持續(xù)2 個機器周期高電平將使單片機復位?撮T狗計時完成后,RST 腳輸出96 個晶振周期的高電平。特殊寄存器AUXR(地址8EH)上的DISRTO位可以使此功能無效。DISRTO默認狀態(tài)下,復位高電平有效。ALE/PROG:地址鎖存控制信號(ALE)是訪問外部程序存儲器時,鎖存低8 位地址的輸出脈沖。在flash編程時,此引腳(PROG)也用作編程輸入脈沖。在一般情況下,ALE 以晶振六分之一的固定頻率輸出脈沖,可用來作為外部定時器或時鐘使用。然而,特別強調(diào),在每次訪問外部數(shù)據(jù)存儲器時,ALE脈沖將會跳過。如果需要,通過將地址為8EH的SFR的第0位置“1”,ALE操作將無效。這一位置“1”,ALE 僅在執(zhí)行MOVX 或MOVC指令時有效。否則,ALE 將被微弱拉高。這個ALE 使能標志位(地址為8EH的SFR的第0位)的設置對微控制器處于外部執(zhí)行模式下無效。PSEN:外部程序存儲器選通信號(PSEN)是外部程序存儲器選通信號。 當AT89S52從外部程序存儲器執(zhí)行外部代碼時,PSEN在每個機器周期被激活兩次,而在訪問外部數(shù)據(jù)存儲器時,PSEN將不被激活。EA/VPP:訪問外部程序存儲器控制信號。為使能從0000H 到FFFFH的外部程序存儲器讀取指令,EA必須接GND。為了執(zhí)行內(nèi)部程序指令,EA應該接VCC。在flash編程期間,EA也接收12伏VPP電壓。XTAL1:振蕩器反相放大器和內(nèi)部時鐘發(fā)生電路的輸入端。XTAL2:振蕩器反相放大器的輸出端。 2 LCD1602的原理及其應用 2.1 液晶屏LCD1602的介紹: LCD1602已很普遍了,具體介紹我就不多說了,市面上字符液晶絕大多數(shù)是基于HD44780液晶芯片的,控制原理是完全相同的,因此HD44780寫的控制程序可以很方便地應用于市面上大部分的字符型液晶。字符型LCD通常有14條引腳線或16條引腳線的LCD,多出來的2條線是背光電源線VCC(15腳)和地線GND(16腳),其控制原理與14腳的LCD完全一樣。 2.2 液晶屏LCD1602的功能及應用 1602LCD采用標準的14腳(無背光)或16腳(帶背光)接口,各引腳接口說明如表10-13所示: 編號 | 符號 | 引腳說明 | 編號 | 符號 | 引腳說明 | 1 | VSS | 電源地 | 9 | D2 | 數(shù)據(jù) | 2 | VDD | 電源正極 | 10 | D3 | 數(shù)據(jù) | 3 | VL | 液晶顯示偏壓 | 11 | D4 | 數(shù)據(jù) | 4 | RS | 數(shù)據(jù)/命令選擇 | 12 | D5 | 數(shù)據(jù) | 5 | R/W | 讀/寫選擇 | 13 | D6 | 數(shù)據(jù) | 6 | E | 使能信號 | 14 | D7 | 數(shù)據(jù) | 7 | D0 | 數(shù)據(jù) | 15 | BLA | 背光源正極 | 8 | D1 | 數(shù)據(jù) | 16 | BLK | 背光源負極 |
表10-13:引腳接口說明表 第1腳:VSS為地電源。 第2腳:VDD接5V正電源。 第3腳:VL為液晶顯示器對比度調(diào)整端,接正電源時對比度最弱,接地時對比度最高,對比度過高時會產(chǎn)生“鬼影”,使用時可以通過一個10K的電位器調(diào)整對比度。 第4腳:RS為寄存器選擇,高電平時選擇數(shù)據(jù)寄存器、低電平時選擇指令寄存器。 第5腳:R/W為讀寫信號線,高電平時進行讀操作,低電平時進行寫操作。當RS和R/W共同為低電平時可以寫入指令或者顯示地址,當RS為低電平R/W為高電平時可以讀忙信號,當RS為高電平R/W為低電平時可以寫入數(shù)據(jù)。 第6腳:E端為使能端,當E端由高電平跳變成低電平時,液晶模塊執(zhí)行命令。 第7~14腳:D0~D7為8位雙向數(shù)據(jù)線。 第15腳:背光源正極。 第16腳:背光源負極。 10.8.2.3 1602LCD的指令說明及時序 1602液晶模塊內(nèi)部的控制器共有11條控制指令,如表10-14所示: 序號 | 指令 | RS | R/W | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 1 | 清顯示 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 2 | 光標返回 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | * | 3 | 置輸入模式 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | I/D | S | 4 | 顯示開/關(guān)控制 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | D | C | B | 5 | 光標或字符移位 | 0 | 0 | 0 | 0 | 0 | 1 | S/C | R/L | * | * | 6 | 置功能 | 0 | 0 | 0 | 0 | 1 | DL | N | F | * | * | 7 | 置字符發(fā)生存貯器地址 | 0 | 0 | 0 | 1 | 字符發(fā)生存貯器地址 | 8 | 置數(shù)據(jù)存貯器地址 | 0 | 0 | 1 | 顯示數(shù)據(jù)存貯器地址 | 9 | 讀忙標志或地址 | 0 | 1 | BF | 計數(shù)器地址 | 10 | 寫數(shù)到CGRAM或DDRAM) | 1 | 0 | 要寫的數(shù)據(jù)內(nèi)容 | 11 | 從CGRAM或DDRAM讀數(shù) | 1 | 1 | 讀出的數(shù)據(jù)內(nèi)容 |
表10-14:控制命令表 1602液晶模塊的讀寫操作、屏幕和光標的操作都是通過指令編程來實現(xiàn)的。(說明:1為高電平、0為低電平) 指令1:清顯示,指令碼01H,光標復位到地址00H位置。 指令2:光標復位,光標返回到地址00H。 指令3:光標和顯示模式設置 I/D:光標移動方向,高電平右移,低電平左移 S:屏幕上所有文字是否左移或者右移。高電平表示有效,低電平則無效。 指令4:顯示開關(guān)控制。 D:控制整體顯示的開與關(guān),高電平表示開顯示,低電平表示關(guān)顯示 C:控制光標的開與關(guān),高電平表示有光標,低電平表示無光標 B:控制光標是否閃爍,高電平閃爍,低電平不閃爍。 指令5:光標或顯示移位 S/C:高電平時移動顯示的文字,低電平時移動光標。 指令6:功能設置命令 DL:高電平時為4位總線,低電平時為8位總線 N:低電平時為單行顯示,高電平時雙行顯示 F: 低電平時顯示5x7的點陣字符,高電平時顯示5x10的點陣字符。 指令7:字符發(fā)生器RAM地址設置。 指令8:DDRAM地址設置。 指令9:讀忙信號和光標地址 BF:為忙標志位,高電平表示忙,此時模塊不能接收命令或者數(shù)據(jù),如果為低電平表示不忙。 指令10:寫數(shù)據(jù)。 指令11:讀數(shù)據(jù)。 與HD44780相兼容的芯片時序表如下: 讀狀態(tài) | 輸入 | RS=L,R/W=H,E=H | 輸出 | D0—D7=狀態(tài)字 | 寫指令 | 輸入 | RS=L,R/W=L,D0—D7=指令碼,E=高脈沖 | 輸出 | 無 | 讀數(shù)據(jù) | 輸入 | RS=H,R/W=H,E=H | 輸出 | D0—D7=數(shù)據(jù) | 寫數(shù)據(jù) | 輸入 | RS=H,R/W=L,D0—D7=數(shù)據(jù),E=高脈沖 | 輸出 | 無 |
表10-15:基本操作時序表 讀寫操作時序如圖10-55和10-56所示: 圖10-56 寫操作時序 10.8.2.4 1602LCD的RAM地址映射及標準字庫表 液晶顯示模塊是一個慢顯示器件,所以在執(zhí)行每條指令之前一定要確認模塊的忙標志為低電平,表示不忙,否則此指令失效。要顯示字符時要先輸入顯示字符地址,也就是告訴模塊在哪里顯示字符,圖10-57是1602的內(nèi)部顯示地址。 圖10-57 1602LCD內(nèi)部顯示地址 例如第二行第一個字符的地址是40H,那么是否直接寫入40H就可以將光標定位在第二行第一個字符的位置呢?這樣不行,因為寫入顯示地址時要求最高位D7恒定為高電平1所以實際寫入的數(shù)據(jù)應該是01000000B(40H)+10000000B(80H)=11000000B(C0H)。 在對液晶模塊的初始化中要先設置其顯示模式,在液晶模塊顯示字符時光標是自動右移的,無需人工干預。每次輸入指令前都要判斷液晶模塊是否處于忙的狀態(tài)。 1602液晶模塊內(nèi)部的字符發(fā)生存儲器(CGROM)已經(jīng)存儲了160個不同的點陣字符圖形,如圖10-58所示,這些字符有:阿拉伯數(shù)字、英文字母的大小寫、常用的符號、和日文假名等,每一個字符都有一個固定的代碼,比如大寫的英文字母“A”的代碼是01000001B(41H),顯示時模塊把地址41H中的點陣字符圖形顯示出來,我們就能看到字母“A” 圖10-58 字符代碼與圖形對應圖 3 設計思路、仿真及調(diào)試 3.1 設計方法 本電路設計采用AT89S52單片機為核心,利用晶振產(chǎn)生頻率為1HZ的時鐘脈沖信號,利用液晶屏LCD1602顯示計算及其時間信息,通過對AT89S52單片機的編程控制液晶屏LCD1602的顯示。顯示計算和簡易計算的信息同在LCD1602,通過按鍵切換選擇。外部按鍵可及時設定或調(diào)整時間或計算的信息。 3.2 硬件設計 本系統(tǒng)以AT89S52單片機為核心,本系統(tǒng)選用12MHZ的晶振,,使得單片機有合理的運行速度。起振電容30pF對振蕩器的頻率高低、振蕩器的穩(wěn)定性和起振的快速性影響較合適,復位電路為按鍵高電平復位。
3.2.1按鍵調(diào)整電路 第 1 頁 共 34 頁
桂林電子科技大課程設計(論文)專用紙 第 1 頁 共 34 頁 S0為調(diào)秒的按鍵,當按下S0時秒加1,S1為調(diào)分的按鍵,當按S1時分加1,S2按鍵為調(diào)時,當按下S2時,時加1,S3按鍵為調(diào)日,當按下S3時日加1,S4為調(diào)月,當按下S4時月加1,S5為調(diào)年,當按下S5時年加1;S6為時間顯示建,S7為計算顯示鍵。 3.2.2復位電路 3.2.3液晶屏LCD1602顯示 3.2.4 LED指示電路 當單片機通電時LED亮 3.2.5 4*4鍵盤的設計 鍵盤功能如下: 3.2.6簡易計算器的總電路 硬件設計中用Protel99se畫原理圖和PCB圖 如圖1所示原理圖: 圖1 3.3 軟件設計 本電路軟件設計采用C語言編寫程序(具體程序在附件中給出)。程序設計主要包括簡易計算的編程,按鍵編程,時間控制編程,液晶屏LCD1602的顯示編程。
3.4 軟件仿真 在硬件設計完成后,利用軟件對其進行仿真,以盡可能的減少做板的次數(shù)。本次我采用Proteus軟件仿真。 如圖2所示,簡易計算器的時間顯示 如圖3所示 簡易計算器的計算顯示軟件仿真正常,可進行硬件制作。 圖2 圖3 3.5 硬件調(diào)試 做好電路板,按鍵使用正確,時間顯示正常,計算功能也正常!如下圖: 4 結(jié)論 在用單片機實現(xiàn)簡易計算的設計中使用到了AT89s52、LCD1602及其4*4鍵盤的使用。在設計過程中我通過在網(wǎng)上和圖書館查閱資料,收集了關(guān)于單片機和液晶屏LCD1602顯示方面的資料,通過對這些資料的學習,我了解了單片機的基本結(jié)構(gòu)和單片機在生活和生產(chǎn)中所發(fā)揮的作用;液晶屏LCD1602的原理和使用。本次課程設計完成的主要工作和任務如下:對設計方案的理論研究,單片機的合理選型,硬件電路的設計,電路板的制作,元器件的焊接,軟件的編寫和調(diào)試以及課設論文的制作。通過設計簡易計算器的過程中我掌握了單片機的基本原理及其各種應用,對它的各種硬件接口與軟件設計方法有較深入的認識。通過對電路原理圖、pcb圖的繪制,電路仿真、電路板的制作掌握了對proteus仿真軟件的使用。
附 件 硬件電路原理圖:
單片機源程序如下: - #include <reg52.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit rs=P0^0;
- sbit rw=P0^1;
- sbit e=P0^2;
- sbit k0=P1^0;
- sbit k1=P1^1;
- sbit k2=P1^2;
- sbit k3=P1^3;
- sbit k4=P1^4;
- sbit k5=P1^5;
- sbit k6=P1^6;
- sbit k7=P1^7;
- unsigned char code digit[ ]={"0123456789"}; //定義字符數(shù)組顯示數(shù)字
- unsigned char s,m,h,day,month,year,count;
- void write_dat(uchar dat);
- void write_com(uchar com);
- void keyscan();
- /**********************
- 功能說明:
- 顯示編碼,加上0x30,
- 分別為'1','2','3','+',
- '4','5','6','-',等
- **********************/
- uchar code table1[]=
- {
- 1,2,3,0x2b-0x30,
- 4,5,6,0x2d-0x30,
- 7,8,9,0x2a-0x30,
- 0,0x3d-0x30,0x01-0x30,0x2f-0x30
- };
-
- uchar k=0,flag=0,num,fuhao,i;
-
- long a,b,c;
-
-
- void delay(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- /*****************************************************
- 函數(shù)功能:指定字符顯示的實際地址
- 入口參數(shù):x
- ***************************************************/
- void WriteAddress(unsigned char x)
- {
- write_com(x|0x80); //顯示位置的確定方法規(guī)定為"80H+地址碼x"
- }
- /******************************************************************************
- 函數(shù)功能:顯示小時
- ******************************************************************************/
- void DisplayHour()
- {
- unsigned char i,j;
- i=h/10; //取整運算,求得十位數(shù)字
- j=h%10; //取余運算,求得各位數(shù)字
- WriteAddress(0x45); //寫顯示地址,將十位數(shù)字顯示在第2行第0列
- write_dat(digit[i]); //將十位數(shù)字的字符常量寫入LCD
- write_dat(digit[j]); //將個位數(shù)字的字符常量寫入LCD
-
- }
- /******************************************************************************
- 函數(shù)功能:顯示分鐘
- ******************************************************************************/
- void DisplayMinute()
- {
- unsigned char i,j;
- i=m/10; //取整運算,求得十位數(shù)字
- j=m%10; //取余運算,求得各位數(shù)字
- WriteAddress(0x48); //寫顯示地址,將十位數(shù)字顯示在第2行第3列
- write_dat(digit[i]); //將十位數(shù)字的字符常量寫入LCD
- write_dat(digit[j]); //將個位數(shù)字的字符常量寫入LCD
-
- }
- /******************************************************************************
- 函數(shù)功能:顯示秒
- ******************************************************************************/
- void DisplaySecond()
- {
- unsigned char i,j;
- i=s/10; //取整運算,求得十位數(shù)字
- j=s%10; //取余運算,求得各位數(shù)字
- WriteAddress(0x4b); //寫顯示地址,將十位數(shù)字顯示在第2行第6列
- write_dat(digit[i]); //將十位數(shù)字的字符常量寫入LCD
- write_dat(digit[j]); //將個位數(shù)字的字符常量寫入LCD
- }
-
-
- /******************************************************************************
- 函數(shù)功能:顯示小時
- ******************************************************************************/
- void DisplayYear()
- {
- unsigned char i,j;
- i=year/10; //取整運算,求得十位數(shù)字
- j=year%10; //取余運算,求得各位數(shù)字
- WriteAddress(0x07); //寫顯示地址,將十位數(shù)字顯示在第2行第0列
- write_dat(digit[i]); //將十位數(shù)字的字符常量寫入LCD
- write_dat(digit[j]); //將個位數(shù)字的字符常量寫入LCD
-
- }
- /******************************************************************************
- 函數(shù)功能:顯示分鐘
- ******************************************************************************/
- void DisplayMonth()
- {
- unsigned char i,j;
- i=month/10; //取整運算,求得十位數(shù)字
- j=month%10; //取余運算,求得各位數(shù)字
- WriteAddress(0x0a); //寫顯示地址,將十位數(shù)字顯示在第2行第3列
- write_dat(digit[i]); //將十位數(shù)字的字符常量寫入LCD
- write_dat(digit[j]); //將個位數(shù)字的字符常量寫入LCD
-
- }
- /******************************************************************************
- 函數(shù)功能:顯示秒
- ******************************************************************************/
- void DisplayDay()
- {
- unsigned char i,j;
- i=day/10; //取整運算,求得十位數(shù)字
- j=day%10; //取余運算,求得各位數(shù)字
- WriteAddress(0x0d); //寫顯示地址,將十位數(shù)字顯示在第2行第6列
- write_dat(digit[i]); //將十位數(shù)字的字符常量寫入LCD
- write_dat(digit[j]); //將個位數(shù)字的字符常量寫入LCD
- }
- void keyscan2()
- {if(k0==0)
- {delay(5);
- if(k0==0)
- {
- s++;
- if(s==60)
- s=0;
- }
- }
- if(k1==0)
- {delay(5);
- if(k1==0)
- {m++;
- if(m==60)
- m=0;
- }
- }
- if(k2==0)
- {delay(5);
- if(k2==0)
- {h++;
- if(h==60)
- h=0;
- }
- }
-
- if(k3==0)
- {delay(5);
- if(k3==0)
- {day++;
- if(day==30)
- day=0;
- }
- }
- if(k4==0)
- {delay(5);
- if(k4==0)
- {month++;
- if(month==13)
- month=0;
- }
- }
- if(k5==0)
- {delay(5);
- if(k5==0)
- {year++;
- if(year==99)
- year=0;
- }
- }
-
- }
-
- void keyscan()
- {
- uchar temp;
- P3=0xfe;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp)
- {
- case 0xee:num=0;
- break;
- case 0xde:num=1;
- break;
- case 0xbe:num=2;
- break;
- case 0x7e:num=3;
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
-
- /*當按下1,2,3,松手后執(zhí)行下面這段語句*/
- if(num==0||num==1||num==2)
- {
-
- if(flag==0)
- a=a*10+table1[num];//如果沒有按符號鍵,符號前的數(shù)值為a
- else if(flag==1)
- b=b*10+table1[num]; //如果按了符號鍵,符號后的數(shù)值為b
-
- if(k==1) //如果之前按了'='號,再按鍵時清屏,進行下一次計算
- {
- k=0;
- write_com(0x01);
- }
- }
- else if(num==3) //判斷按下'+'
- {
- flag=1;
- fuhao=1;
- }
-
- i=table1[num]; //顯示按下的鍵
- write_dat(0x30+i);
-
- }
- P3=0xfd;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp)
- {
- case 0xed:num=4;
- break;
- case 0xdd:num=5;
- break;
- case 0xbd:num=6;
- break;
- case 0x7d:num=7;
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
- if(num==4||num==5||num==6) //判斷是否按下'4','5','6'
- {
- if(k==1)
- {
- k=0;
- write_com(0x01);
- }
- if(flag==0)
- a=a*10+table1[num];
- else if(flag==1)
- b=b*10+table1[num];
- }
- else if(num==7)
- {
- flag=1;
- fuhao=2;
- }
- i=table1[num]; //顯示按下的鍵
- write_dat(0x30+i);
-
- }
- P3=0xfb;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp) //
- {
- case 0xeb:num=8;
- break;
- case 0xdb:num=9;
- break;
- case 0xbb:num=10;
- break;
- case 0x7b:num=11;
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
- if(num==8||num==9||num==10) //判斷是否按下'7','8','9'
- {
- if(k==1)
- {
- k=0;
- write_com(0x01);
- }
- if(flag==0)
- a=a*10+table1[num];
- else if(flag==1)
- b=b*10+table1[num];
-
- }
- else if(num==11) //判斷是否按下'*'
- {
- flag=1;
- fuhao=3;
-
- }
- i=table1[num];
- write_dat(0x30+i);
-
- }
- P3=0xf7;
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- delay(5);
- temp=P3;
- temp=temp&0xf0;
- while(temp!=0xf0)
- {
- temp=P3;
- switch(temp)
- {
- case 0xe7:num=12; // 0鍵
- break;
- case 0xd7:num=13; // '='
- break;
- case 0xb7:num=14; //清零鍵
- break;
- case 0x77:num=15; //'/'
- break;
- }
- while(temp!=0xf0)
- { temp=P3;
- temp=temp&0xf0;
- }
- }
- switch(num)
- {
- case 12:
- {
- if(k==1)
- {
- k=0;
- write_com(0x01);
- }
- if(flag==0)
- a=a*10;
- else if(flag==1)
- b=b*10;
-
- write_dat(0x30);
- }
- break;
- case 13: //按=鍵
- {
- k=1;
- if(fuhao==1) //如果符號鍵是+,執(zhí)行+運算
- {
-
- write_com(0x80+0x4f);
- write_com(0x04);
- c=a+b;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
-
-
- }
- write_dat(0x3d);
- fuhao=0;
- a=0;b=0;flag=0;
- }
- if(fuhao==2)
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- if(a>=b)
- {
- c=a-b;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
- }
-
- }
- else if(a<b)
- {
- c=b-a;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
- }
- write_dat(0x2d);
- }
-
- write_dat(0x3d);
- a=0;b=0;flag=0;fuhao=0;
-
- }
- if(fuhao==3) //如果符號鍵是*
- {
- write_com(0x80+0x4f);
- write_com(0x04);
- c=a*b;
- while(c!=0)
- {
- write_dat(0x30+c%10);
- c=c/10;
- }
- write_dat(0x3d);
- a=0;b=0;flag=0;fuhao=0;
-
- }
- if(fuhao==4) //如果符號鍵是/
- {
- i=0;
- write_com(0x80+0x4f);
- write_com(0x04);
- c=(long)(((float)a/b)*1000000); //結(jié)果保留6位小數(shù)
- while(c!=0
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
|