基於C51單片機的智能計算器、矩陣鍵盤、lcd1602


目錄

1緒論.............................................................................................................................. 1

1.1選題背景............................................................................................................. 1

1.2起源與發展.......................................................................................................... 1

1.3研究的目的和意義............................................................................................... 2

2項目總體設計框架......................................................................................................... 2

2.1芯片STC89C52.................................................................................................... 2

2.2采用矩陣式鍵盤作為輸入模塊.............................................................................. 2

2.3顯示模塊............................................................................................................. 3

2.4硬件資源分配...................................................................................................... 3

3計算器硬件設計............................................................................................................ 4

3.1系統組成及硬件框圖............................................................................................ 4

3.2元器件簡介.......................................................................................................... 4

3.2.1 STC89C52的特點........................................................................................ 4

3.2.2 LCD1602 液晶顯示屏.................................................................................. 5

4系統電路設計................................................................................................................ 6

4.1鍵盤電路設計...................................................................................................... 7

4.2顯示電路設計...................................................................................................... 8

4.3其他電路部分...................................................................................................... 8

4.3.1 蜂鳴器模塊............................................................................................... 8

4.3.2 電源模塊................................................................................................... 9

4.3.3 單片機最小系統........................................................................................ 9

5計算器軟件設計........................................................................................................... 10

5.1整體設計結構..................................................................................................... 10

5.2液晶屏讀寫函數................................................................................................. 10

5.2.1 初始化函數.............................................................................................. 10

5.2.2 寫命令函數.............................................................................................. 11

5.2.3 寫數據函數.............................................................................................. 11

5.3接收矩陣鍵盤輸入函數....................................................................................... 12

5.4調試和運行程序................................................................................................. 13

5.4.1 Proteus仿真運行程序................................................................................ 13

5.4.2 在實驗箱上運行程序................................................................................ 13

6總結............................................................................................................................ 14

 

 

 

 

 


基於51單片機的簡易計算器

 

摘要:近幾年單片機技術的發展很快,其中,電子產品的更新速度迅猛。計算器是日常生活中比較常見的電子產品之一。如何才能使計算器技術更加的成熟,充分利用已有的硬件和軟件條件,設計出更出色的計算器。

本設計是以STC89C52單片機為核心的計算器模擬系統設計,輸入采用4*4矩陣鍵盤,可以進行加、減、乘、除帶符號數字運算(六位整數或兩位小數點點),並在液晶顯示屏LCD1602上靜態顯示操作過程及結果。對字符液晶顯示模塊的工作原理,如初始化、清屏、顯示、調用及外特性有較清楚的認識,並會使用LCD(液晶顯示模塊)實現計算結果的顯示;掌握液晶顯示模塊的驅動和編程,設計LCD和單片機的接口電路,以及利用單片機對液晶顯示模塊的驅動和操作;在充分分析內部邏輯的概念,進行軟件和調試,學會使用,並能夠以其為平台設計出具有四則運算能力簡易計算器的硬件電路和軟件程序。

關鍵詞:單片機;液晶顯示器;計算器;矩陣鍵盤

 

1緒論

1.1選題背景

現如今,人們的日常生活中已經離不開計算器了,社會的各個角落都有它的身影,比如商店、辦公室、學校……因此設計一款簡單實用的計算器會有很大的實際意義[1]。本設計旨在進一步掌握單片機理論知識,理解單片機系統的硬軟件設計,加強對實際應用系統設計的能力。通過本設計的學習,使我掌握單片機程序設計的基本方法,並能綜合運用本科階段所學軟、硬件知識分析實際問題,提高解決畢業設計實際問題的能力,為單片機應用和開發打下良好的基礎。

1.2起源與發展

計算器是最早的計算工具,例如:奇普(Quipu或khipu)是古代印加人的一種結繩記事的方法,用來計數或者記錄歷史。它是由許多顏色的繩結編成的。

還有古希臘人的安提凱希拉裝置,中國的算盤等。中國古代最早采用的一種計算工具叫籌策,又被叫做算籌。這種算籌多用竹子制成,也有用木頭,獸骨充當材料的。約二百七十枚一束,放在布袋里可隨身攜帶。直到今天仍在使用的珠算盤,是中國古代計算工具領域中的另一項發明,明代時的珠算盤已經與現代的珠算盤幾乎相同。

早期的計算器為純手動式,如算盤、算籌等。算盤通常是以滑動的珠子制成。在西方,算盤在印度阿拉伯數字流行前使用了數個世紀,且在近代中國的記帳與商務上仍廣泛使用。后來出現機械計算器。17世紀初,西方國家的計算工具有了較大的發展,英國數學家納皮爾發明的"納皮爾算籌",英國牧師奧卻德發明了計圓柱型對數算尺,這種計算尺不僅能做加減乘除、乘方、開方運算,甚至可以計算三角函數,指數函數和對數函數,這些計算工具不僅帶動了計算器的發展,也為現代計算器發展奠定了良好的基礎,成為現代社會應用廣泛的計算工具。

1.3研究的目的和意義

計算器使用的是固化的處理程序,只能完成特定的計算任務;而計算機借助操作系統平台和各類應用軟硬件,可以無限擴展其應用領域。也就是說,是否具有擴展性是二者的本質區別[2]

單片機又稱單片微控制器,它不是完成某一個邏輯功能的芯片,而是把一個計算機系統集成到一個芯片上。概括的講:一塊芯片就成了一台計算機。在計算機應用與智能化控制的科學家、工程師手中,它和計算機的本質相同,可以開發出針對各類電子電氣產品的應用,例如洗衣機。但對於用戶來說,他們並不需要知道洗衣機里的單片機的接口和編程語言,只要能操作洗衣服就行,因此單片機用於某個具體的電子產品上就需要配合簡潔方便的人機界面,用戶只使用它的特定功能。

2項目總體設計框架

2.1芯片STC89C52

單片機是單片微型機的簡稱,故又稱為微控制器MCU(Micro Control Unit)。通常由單塊集成電路芯片組成,內部包含有計算機的基本功能部件:中央處理器CPU,存儲器和I/O接口電路等。因此,單片機只要和適當的軟件及外部設備相結合,便可成為一個單片機控制系統。單片機廣泛應用於智能產品,智能儀表,測控技術,智能接口等,具有操作簡單、實用方便、價格便宜等優點[3]

而其中STC89C52是一種帶8K字節閃爍可編程可擦除只讀存儲器(FPEROM-Flash Programable and Erasable Read Only Memory)的低電壓,高性能COMOS8的微處理器。該器件與工業標准的MCS-51指令集和輸出管腳相兼容;且是單片機中最典型的代表,應用於各種控制領域[4]

2.2采用矩陣式鍵盤作為輸入模塊

矩陣式按鍵輸入模塊,其特點是:電路和軟件稍復雜,但相比之下,當鍵數越多時,越節約I/O口,比較節省資源。其原理圖如圖1所示。

 

         圖1 矩陣鍵盤輸入

         Fig.1 Matrix keyboard input

2.3顯示模塊

采用LED數碼管的靜態顯示,其特點是:其亮度較高;這種顯示方式接口,編程容易且管理簡單;不足的是,占用的I/O的線資源較多。如果采用單片機或CPLD/FPGA來控制的話,勢必存在浪費I/O口資源的問題[5]。采用LED數碼管的動態顯示,其特點是:其亮度比靜態顯示的亮度要差一些;但其電路比較簡單,適合於顯示位數較多的情況。采用LCD1602液晶顯示,如圖2所示,其特點是:可以調節其背光亮度,這種顯示方式接口,編程雖然有些麻煩,但管理較方便,占用的I/O口資源線也不多。在計算器運算中,需顯示的數字、符號較多,按很據個方面的特點,而后可以發現LCD液晶顯示,雖然在價格上的確是稍貴於LED數碼管;但數碼管在硬件設計電路中,會因線太多、線路復雜而過於繁瑣,則舍棄LED數碼管,選擇LCD液晶顯示[6]

 

         圖2 LCD 1602液晶顯示屏

         Fig.2 1602 liquid crystal display

2.4硬件資源分配

主要用到的硬件:單片機STC89C52 、液晶顯示屏LCD1602 、4*4按鍵鍵盤

硬件分配:

  1. P1口:作為輸入口,與鍵盤連接,實現數據的輸入。
  2. P0、P2口:作為輸出口(P2口為高位,P0口為低位),控制LCD液晶顯示屏顯示數據的結果。
  3. 液晶顯示屏LCD1602顯示輸出。

3計算器硬件設計

3.1系統組成及硬件框圖

 顯示模塊

 

 

蜂鳴器電路

 

矩陣鍵盤輸入模塊

 

 
   

 

 

 

 

 

 

圖3 系統組成及硬件框圖

Fig.3 System composition and hardware block diagram

3.2元器件簡介

3.2.1 STC89C52的特點

 

圖4 STC89C52 單片機

Fig.4 Single chip microcomputer STC89C52

  1. 主要性能:

與MCS-51單片機產品兼容;8K字節在系統可編程Flash存儲器;1000次擦寫周期;全靜態操作:0Hz-33Hz;三級加密程序存儲器;32個可編程I/O口線、三個16位定時器/計數器、8個中斷源;全雙工UART串行通信;低功耗空閑和掉電模式,掉電后中斷可喚醒;看門狗定時器;雙數據指針;掉電標識符[7]

  1. STC89C52的功能特性概述

STC89C52是一種低功耗、高性能CMOS 8位微控制器,具有8K在系統可編程Flash存儲器。使用高密度非易失性存儲器技術制造,與工業80C51產品指令和引腳完全兼容。片上Flash允許程序存儲器在系統可編程,亦適於常規編程器。

3.2.2 LCD1602 液晶顯示屏

  1. 液晶顯示原理

液晶顯示的原理是利用液晶的物理特性,通過電壓對其顯示區域進行控制,有電就有顯示,這樣即可以顯示出圖形[8]。液晶顯示器有厚度薄、適用於大規模集成電路直接驅動、易於實現全彩色顯示的特點,目前已經被廣泛應用在便攜式計算機、數字攝像機、PDA移動通信工具等眾多領域。

  1. LCD1602的應用簡介

LCD1602液晶顯示器采用HD44780及其兼容芯片作為點陣式LCD的控制器驅動器,還采用HD44100進行LCD的時分割驅動。HD44780的內部結構主要包括顯示數據RAM(DDRAM)、字符發生器ROM(CGROM)、字符發生器RAM(CGRAM)、指令寄存器IR、數據寄存器DR、地址計數器AC(Address Counter)和忙標志BF(Busy Flag)等邏輯電路[9]

1602液晶模塊內部的控制器共有11條控制指令,豐富的指令可以完成液晶的時序控制、工作方式設置和數據顯示等。

采用的LCD1602液晶模塊是標准16針插座,接口電路如圖5所示,及各引腳說明如表1所示。

 

圖5 LCD1602引腳接口電路圖

Fig.5 Pin interface circuit diagram of LCD1602

 

表1 LCD1602 引腳說明

Table.1 LCD1602 pin description

第1腳

Vss為地電源

第2腳

VDD接5V正電源

第3腳

Vo為液晶顯示器對比度調整端,接電源正極時對比度最弱,接地電源時對比度最高,對比度過高時會產生“鬼影”,使用時可以通過一個10K的電位器調整對比度。

第4腳

Rs為寄存器選擇,高電平選擇數據寄存器、低電平選擇指令寄存器。

第5腳

Rw為讀寫信號線,高電平時進行讀操作,低電平時選擇指令寄存器。

第6腳

E端為使能端,當E端由高電平跳變成低電平時,液晶模塊執行命令。

第7-14腳

D0-D7為8位雙向數據線。

第15-16腳

背光陽極和背光陰極。

  1. 其他方面介紹

DDRAM用來暫存顯示字符的代碼,共80個字節,DDRAM的各個單元對應着顯示屏上的各個字符位,如圖6所示。因此,DDRAM的地址也就意味着顯示字符的地址,顯示字符時首先要向LCD傳送顯示字符地址。

LCD

16字*2行

 

 

 

 

 

 

00

01

02

03

04

05

06

07

08

09

0A

0B

0C

0D

OE

OF

10

……

27

40

41

42

43

44

45

46

47

48

49

4A

4B

4C

4D

4E

4F

50

……

67

圖6 DDRAM單元地址與顯示屏字符位的對應關系

Fig.6 Correspondence between DDRAM unit address and display character bits

4系統電路設計

為了更好地實現系統的功能,硬件電路的設計應該遵循以下原則:

  1. 優化硬件電路

采用軟件設計與硬件設計相結合的方法。盡管采用軟件來實現硬件系統的功能時,也許響應的時間會比單純使用硬件時長,而且還要占用微處理器MCU的時間;但是,用軟件實現硬件的功能可以簡化硬件結構,提高電路的可靠性。所以,在設計本系統的時候,在滿足可靠性和實時性的前提下,盡可能地通過軟件來實現硬件功能。

  1. 可靠性及抗干擾設計

根據可靠性設計理論,系統所用芯片數量越少,系統的平均無故障時間越長。而且,所用芯片數量越少,地址和數據總線在電路板上受干擾的可能性也就越小。因此,系統的設計思想是在滿足功能的情況下爭取較少數量的芯片。

  1. 靈活的功能擴展

功能擴展是否靈活是衡量一個系統優劣的重要指標。一次設計往往不能完全考慮到系統的各個方面,系統需要不斷完善以及進行功能升級。進行功能擴展時,應該在原有設計的基礎上,通過修改軟件程序和少量硬件完成。對於本系統而言,就是要求在系統硬件不變的情況下,能夠通過修改軟件程序,完成功能的升級和擴展[10]

根據提出的系統設計方案,結合以上三條原則,確定了系統硬件的設計。計算器主要由以下一些功能模塊組成:非編碼鍵盤模塊、運算模塊(單片機內部)、LCD液晶顯示模塊等。

該系統的硬件設計采用了模塊化的設計方法。STC89C52單片機與LCD液晶顯示屏顯示電路是整個電路的核心,它們能實現系統的功能要求。

簡易計算器主要包括:鍵盤電路、運算電路、輸出顯示電路。

前面說明了該系統的設計,系統采用了比較簡單的設計方案,所以該系統的硬件設計的總外圍電路不會產生過多的干擾。下面對系統的外圍電路分別作了說明。鍵盤部分采用4*4按鍵鍵盤,顯示部分采用LCD液晶顯示屏完全能夠很好地實現顯示方面的要求。

4.1鍵盤電路設計

鍵盤可分為兩類:編碼鍵盤和非編碼鍵盤。編碼鍵盤是較多按鍵(20個以上)和專用驅動芯片的組合;當按下某個按鍵時,它能夠處理按鍵抖動、連擊等問題,直接輸出按鍵的編碼,無需系統軟件干預。

通用計算機使用的鍵盤就是編碼鍵盤。在智能儀器中,使用並行接口芯片8279或串行接口HD7279均可以組成編碼鍵盤,同時還可以兼顧數碼管的顯示驅動,其相關的接口電路和接口軟件均可在芯片資料中得到。當系統功能比較復雜,按鍵數量很多時,采用編碼鍵盤可以簡化軟件設計[11]

非編碼鍵盤成本低廉。從成本角度出發,本設計選用的是非編碼鍵盤。如圖7所示。

 

圖7 鍵盤電路設計     

Fig.7 Keyboard circuit design

4.2顯示電路設計

當系統需要顯示少量數據時,采用LCD液晶顯示屏進行顯示是一種經濟實用的方法。P0口作為液晶顯示的數據端口,P2.0-P2.2口作為其控制端口,控制LCD液晶顯示屏顯示輸出數據。最終顯示電路如圖8所示

 

圖8 液晶顯示電路設計

Fig.8 Liquid crystal display circuit design

4.3其他電路部分

4.3.1 蜂鳴器模塊

蜂鳴器在電路中主要用來每按下一次按鍵后,蜂鳴器就發出一次聲響,以提示用戶已經按下了按鍵,其電路部分如圖9所示。

 

圖9 蜂鳴器模塊電路設計

Fig.9 Buzzer module circuit design

4.3.2 電源模塊

 

圖10 電源模塊電路設計

Fig.10 Power module circuit design

4.3.3 單片機最小系統

 

圖11單片機最小系統電路設計

Fig.11 Minimal system circuit design of single chip microcomputer

5計算器軟件設計

5.1整體設計結構

在軟件中主要定義了delay()延時函數、lcdwrc()寫命令、lcdwrd()寫數據、光標定位、lcdinit()初始化、keyscan()按鍵檢測、main()等幾個函數,其中最為復雜的就是按鍵檢測函數,在主函數中只是調用是初始化函數,然后死循環keyscan()按鍵檢測函數,具體如圖12所示。

 

圖12整體設計結構

Fig.12 Overall design structure

5.2液晶屏讀寫函數

5.2.1 初始化函數

使用lcd1602液晶顯示模塊前,需要對其顯示模式,進行初始化設置,在初始化函數中,使用了lcd中的幾條命令:

寫入0x38:兩行顯示,5x7點陣,8位數據,執行空操作,給硬件反應時間。

寫入0x0f:開整體顯示,打開光標,打開光標閃爍,執行空操作,給硬件反應時間。

寫入0x05:寫入一個字符后,地址指針加一,光標左移,執行空操作,給硬件反應時間。

寫入0x01:清屏。

具體實現的代碼如圖13所示。

 

圖13初始化函數

Fig.13 Initialization function

5.2.2 寫命令函數

按照規定,RS和E必須同時為0時,才可以寫入命令,將命令寫入P0口中,寫命令時,E應為正脈沖,即正跳變,所以前面先置E=0,然后給一點延時,等待機器反應,E由高電平變為低電平,LCD開始執行命令;具體實現的代碼如圖14所示。

 

圖14寫命令函數

Fig.14 Write command function

5.2.3 寫數據函數

寫數據就是將要顯示字符的ACSⅡ碼寫入LCD 1602液晶顯示模塊中的顯示數據RAM(DDRAM);按照規定,寫數據時,E應為正脈沖,首先先置E=0,其中RS=1和RW=0時,才可以寫入數據,然后將數據從P0口輸入,即寫入LCD 1602液晶顯示模塊,當E有高電平變為低電平,寫數據操作結束,具體實現代碼如圖15所示。

 

圖15寫數據函數

Fig.15 Write data function

5.3接收矩陣鍵盤輸入函數

接收舉證鍵盤輸入函數是整個程序中最主要的函數,在此函數中,通過八根 I/O 口線組成一個 4×4=16 的矩陣鍵盤,單片機對其進行掃描,把按下鍵的鍵值顯示在顯示屏上。

查看實驗箱上的電路圖(見圖16),可看到 16 個按鍵分別通過 4 根行線和 4 根列線交叉組成,其中 4 根行線分別接到了單片機的 P1.4~P1.7 口,4 根列線分別接到了單片機的 P1.0~P1.3 口,這樣一個 P1 端口就接了 16 個按鍵。

 

圖16矩陣鍵盤電路

Fig.16 Matrix keyboard circuit

矩陣式鍵盤的按鍵識別方法一般有三種,即:行掃描法、行列掃描法和行反轉法。在實際應用中,由於行反轉法速度較快,所以應用較為廣泛,本例就采用這種方法;

行反轉法的基本原理是:將行線接一個數據端口,讓它先工作在輸出模式,將列線也接到一個數據端口,讓它先工作在輸入模式;讓 CPU 通過輸出端口向行線上全部送出低電平,然后讀入列線上的值,如果此時有鍵被按下,則必定會使某列線值為低電平;接着對兩個端口進行模式改變,使接行線的端口改為輸入模式,接列線的端口改為輸出模式,並且將剛才讀得的列值從列線所接端口輸出,再讀取行線的值, 那么閉合健所在的行線值必定為低電平;這樣,當一個按鍵被按下時, 必定可以讀得一對唯一的行值和列值;

這樣我們就可以把得到的值通過寫命令,把值寫入到液晶顯示屏中,並保存記錄下這個值,當輸入符號位時,進行清屏操作,並記錄下所按下符號的鍵值,最后當用戶按下等號時,根據所輸入的數據和運算符,得出相應的結果,並把結果輸出到顯示屏中,這樣就完成了一次運算;當按下清屏鍵時,lcd 1602執行清屏操作,又恢復到光標閃爍,初始化界面。

5.4調試和運行程序

5.4.1 Proteus仿真運行程序

首先在電腦上搭建Proteus仿真平台,在平台上繪制出本次設計的電路圖,把程序生產的hex文件下載到C52單片機中,然后啟動仿真,在仿真環境中就可以測試程序設計是否符合要求,其效果如圖17所示。

圖17 Proteus仿真

Fig.17 Proteus simulation

5.4.2 在實驗箱上運行程序

首先將實驗箱ME850通過數據線與電腦連接,打開實驗箱開關,將實驗箱上的JP15(蜂鳴器)和JP25(背光)跳線帽接上,JP24跳線帽改接到NO上,4x4矩陣鍵盤的8個跳線帽也接上,試驗箱的主板電路布局如圖18所示。

 

圖18 ME850硬件布局

Fig.18 ME850 hardware layout

通過專用的燒寫工具MEFlash,將hex文件燒寫到ME850試驗箱中,就可以運行程序了,燒寫完成以后實現的效果如圖19所示。

 

圖19 在開發板上的實現效果

Fig.19 Implementation effect on the development board

6總結

我認為,學編程讀別人的程序非常重要,每個人都有不同的思維,相同的任務卻有很多不同的方法,在每個程序里都能找到些經典的段子,讓人回味。從中可以學到很多的方法,並且有些可以直接的引用。一個出色的程序員在編程時,並不是從零開始,而應該是先找出類似的例子進行分析,參考,看看有沒有值得引用和借鑒的地方,加以修改,為自己所用。實踐證明,這樣做是對的。

基本功要雜實,要有一定的數模電基礎。學單片機首先要搞清楚它的基本結構和存儲單元的分配。          

多讀有代表性的程序,讀得多了自然就會學到很多的好方法。可買本單片機子程序集看看,也可網上下載程序分析。

我覺得以上幾點相當重要,因為它對我幫助很大,算是將我領進了單片機的大門,以至於我學起來不那么吃力,沒有感覺到 像大家說的那樣的難。我看過很多的程序,也調試過很多的程序,每一次收獲都不小。我的實驗室就是KEIL和PROTEUS。這使我做實驗很方便。雖是虛擬的,但調試程序還是可以的,省去了很多的時間提高了效率。最近我在學C51,因為學單片機掌握C語言是非常重要的,C語言的通用性對學習其它類型的單片機有很大的幫助。今后,我想做嵌入式系統工程師,想學ARM,想搞操作系統。所以我現在必須打好基礎,這樣才能進步。

通過這種途徑的實踐教學活動,我們將前幾年所學的知識綜合起來了,將所學的知識應用於實踐中去了。這樣,到了社會上我們就更有競爭力了。

實踐證明,通過該課程設計,不僅提高了學生學習的興趣,加深了對專業知識的理解,開闊了視野,也為以后畢業設計打下良好的基礎。單片機課程設計這一實踐教學環節的有效開展,有助於學生有效地掌握所學知識,縮短從理論知識到實際應用的過程,很好地培養了學生的專業興趣,增強了學生的創新意識,提高了學生的動手能力和實際應用能力。

 

 

結語

經過了兩個多星期的學習和工作,我終於完成了《基於51單片機的簡易計算器》的課程設計。從開始接到課程設計題目到系統的實現,再到課程設計文章的完成,每走一步對我來說都是新的嘗試與挑戰,這也是我在大學期間獨立完成的最大的項目。在這段時間里,我學到了很多知識也有很多感受,從對C52單片機的一無所知,對動態掃描,矩陣鍵盤等相關技術很不了解的狀態,我開始了獨立的學習和試驗,查看相關的資料和書籍,讓自己頭腦中模糊的概念逐漸清晰,使自己非常稚嫩作品一步步完善起來,每一次改進都是我學習的收獲,每一次試驗的成功都會讓我興奮好一段時間。從中我也充分認識到了單片機給我們生活帶來的樂趣,在屬於自己的編程器件上,盡情宣泄自己的情感,表達自己的感受,並且把自己的想法與他人分享,我也有了一個屬於自己可控制的單片機。

雖然我的課程設計作品不是很成熟,還有很多不足之處,但我可以自豪的說,這里面的每一段代碼,都有我的勞動。當看着自己的程序,自己成天相伴的系統能夠健康的運行,真是莫大的幸福和欣慰。我相信其中的酸甜苦辣最終都會化為甜美的甘泉。      

這次做課程設計的經歷也會使我終身受益,我感受到做課程設計是要真真正正用心去做的一件事情,是真正的自己學習的過程和研究的過程,沒有學習就不可能有研究的能力,沒有自己的研究,就不會有所突破,那也就不叫課程設計了。希望這次的經歷能讓我在以后學習中激勵我繼續進步。

 

 

先上仿真圖

實測效果圖

 

源代碼:

#include<reg52.h>            
typedef unsigned char uint8;
typedef unsigned int uint16;
unsigned char dataw;

sbit BEEP=P3^7;
sbit rw=P2^1;
sbit rs=P2^0;
sbit e=P2^2;
//sbit rw=P2^5;
//sbit rs=P2^6;
//sbit e=P2^7;
//sbit BEEP=P1^5;

uint8 key,num;
uint8 fuhao;//定義具體的那個符號,是加減還是乘除。
uint8 flag;    //定義有沒有按下符號鍵
long a,b,c,d;    //定義運算數據的第一個和第二個及等於的數變量
uint8 k; //定義小數點后面顯示的位數
uint8 biao;
int bz=0;
uint8 dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x2a-0x30, 0,0x01-0x30,0x3d-0x30,0x2b-0x30 };//保存顯示的數據
const unsigned char str0[] = {"    NUM INPUT   "};
const unsigned char str1[] = {" NUM INPUT NEXT "};
const unsigned char str2[] = {"  RESULT SHOW   "};
//const unsigned char str3[] = {"                "};

    
    
void delay(uint16 i)//延時
{
    while(i--);
}

void buzzer()//蜂鳴器
{
        for(bz=490;bz>0;bz--){
            BEEP=~BEEP;
          delay(10);
                }
        BEEP=1;
}

void lcdwrc(uint8 c)//寫入命令
{
    delay(1000);
    rs=0;
    rw=0;
    e=0;
    P0=c;
    e=1;
    delay(1000);
    e=0;
}

void lcdwrd(unsigned char dataw)//寫入數據
{
    delay(1000);
    rs=1;
    rw=0;
    e=0;
    P0=dataw;
    e=1;
    delay(1000);
    e=0;
    rs=0;
}



void ePutstr(unsigned char const *ptr)
{
    unsigned char i,j = 0; 
    lcdwrc(0x01);
    while(ptr[j] > 31)
    j++;    //ptr[j]>31 時為 ASCII 碼,j 累加,計算出字符串長度
    for(i = 0; i < j; i++)
    {
        lcdwrd(ptr[i]); //顯示單個字符,同時x坐標遞增
    }
    //lcdwrc(0x4f+0x80);
}

void lcdinit()//初始化,復位過程
{
    delay(1500);
    lcdwrc(0x38);//不檢測忙信號
    delay(500);
    lcdwrc(0x38);//不檢測忙信號
    delay(500);
    lcdwrc(0x38);//不檢測忙信號
    delay(500);
    lcdwrc(0x38);//不檢測忙信號
    lcdwrc(0x08);//顯示關閉
    lcdwrc(0x01);//顯示清屏
    lcdwrc(0x06);//顯示光標移動設置
    ePutstr(str0);
    lcdwrc(0x4f+0x80);
    lcdwrc(0x0f);//顯示開及光標設置
    key=0;
    num=0;
    flag=0;
    fuhao=0;
    a=0;
    b=0;
    c=0;
    d=0;
    biao=0;
}


void qingpin(){
        lcdwrc(0x01);
        ePutstr(str1);
        lcdwrc(0x4f+0x80);
        lcdwrc(0x0f);
}

void zhongduan(void) interrupt 0 using 0 //外部中斷0中斷函數
{
        lcdwrc(0x01);
        a=0;
        b=0;
        flag=0;
        fuhao=0;
        ePutstr(str0);
        lcdwrc(0x4f+0x80);
        lcdwrc(0x0f);
}


void keyscan()//按鍵檢測
{
    P1=0xfe;   //令第一行為0,然后判斷是哪一列按下
    if(P1!=0xfe)
    {
        buzzer();
        delay(1000);
        if(P1!=0xfe)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=0;break;      //1
                case 0xd0: num=1;break;      //2
                case 0xb0: num=2;break;      //3
                case 0x70: num=3;break;      //
            }
        }
        while(P1!=0xfe);
        if(num==0||num==1||num==2)     //確認第一行的數1,2,3
        {
            if(flag==0)     //沒有按下符號鍵
            {
                a=a*10+dat1[num];    
                lcdwrc(0x0f);//光標閃爍
                lcdwrc(0x04);//設置光標左移,屏幕不移動
                lcdwrd(0x30+dat1[num]);
                //lcdwrc(0x1c);
                //ePutstr(str0);
            }
            else
            {
                b=b*10+dat1[num];
                lcdwrc(0x0f);//光標閃爍
                lcdwrc(0x04);//設置光標左移,屏幕不移動
                lcdwrd(0x30+dat1[num]);
                //lcdwrc(0x1c);
                //ePutstr(str0);
                //lcdwrc(0x4f+0x80);
            }
        }
        if(num==3)
        {
            flag=1;//有符號鍵按下
            fuhao=1;//加號+    
    //        ePutstr(0,1,str3);
  //        lcdwrc(0x0c);
            qingpin();
        }
    }

    

    P1=0xfd;        //令第二行為0,判斷是哪一列按下
    if(P1!=0xfd)
    {
        buzzer();
        delay(1000);
        if(P1!=0xfd)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=4;break;      //4
                case 0xd0: num=5;break;      //5
                case 0xb0: num=6;break;      //6
                case 0x70: num=7;break;      //減—
            }    
        }
        while(P1!=0xfd);
        if(num==4||num==5||num==6)
        {
            if(flag==0)     //沒有按下符號鍵
            {
                a=a*10+dat1[num];    
                lcdwrc(0x0f);//光標閃爍
                lcdwrc(0x04);//設置光標左移,屏幕不移動
                lcdwrd(0x30+dat1[num]);
            }
            else
            {
                b=b*10+dat1[num];
                lcdwrc(0x0f);//光標閃爍
                lcdwrc(0x04);//設置光標左移,屏幕不移動
                lcdwrd(0x30+dat1[num]);
            }            
        }
        else
        {
            flag=1;//有符號鍵按下
            fuhao=2;//帶表減號
            //ePutstr(0,1,str3);
            //lcdwrc(0xc);
            qingpin();
        }
    }


    P1=0xfb;         //令第三行為0,判斷哪一列按下
    if(P1!=0xfb)
    {        
        buzzer();    
        delay(1000);
        if(P1!=0xfb)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=8;break;      //7
                case 0xd0: num=9;break;      //8
                case 0xb0: num=10;break;  //9
                case 0x70: num=11;break;  //乘*
            }    
        }
        while(P1!=0xfb);
        if(num==8||num==9||num==10)
        {
            if(flag==0)     //沒有按下符號鍵
            {
                a=a*10+dat1[num];
                lcdwrc(0x0f);//光標閃爍
                lcdwrc(0x04);//設置光標左移,屏幕不移動
                lcdwrd(0x30+dat1[num]);
            }
            else
            {
                b=b*10+dat1[num];
                lcdwrc(0x0f);//光標閃爍
                lcdwrc(0x04);//設置光標左移,屏幕不移動
                lcdwrd(0x30+dat1[num]);
            }            
        }
        else
        {
            flag=1;
            fuhao=3;//帶表乘號*
            //ePutstr(0,1,str3);
            //lcdwrc(0xc);
            qingpin();
        }

    }

    
    P1=0xf7;         //令第四行為0,判斷哪一列按下
    if(P1!=0xf7)
    {
        buzzer();
        delay(1000);
        if(P1!=0xf7)
        {
            key=P1&0xf0;
            switch(key)
            {
                case 0xe0: num=12;break;  //0
                case 0xd0: num=13;break;  //清除rst
                case 0xb0: num=14;break;  //等號=
                case 0x70: num=15;break;  //除/
            }    
        }
        while(P1!=0xf7);
        switch(num)
        {
            case 12: 
                    if(flag==0)     //沒有按下符號鍵
                    {
                        a=a*10+dat1[num];
                        lcdwrd(0x30);    
                        lcdwrc(0x0f);//光標閃爍
                        lcdwrc(0x04);//設置光標左移,屏幕不移動
                        buzzer();                        
                    }
                    else
                    {
                        b=b*10+dat1[num];
                        lcdwrc(0x0f);//光標閃爍
                        lcdwrc(0x04);//設置光標左移,屏幕不移動
                        lcdwrd(0x30);
                    }
                    break;
            
            case 13: 
                    lcdwrc(0x01);    //清屏指令    
                    a=0;
                    b=0;
                    flag=0;
                    fuhao=0;
                    ePutstr(str0);
                    lcdwrc(0x4f+0x80);
                    lcdwrc(0x0f);//光標閃爍
                    break;

            case 15:
                    flag=1;
                    fuhao=4;
                    //ePutstr(0,1,str3);//除號/
                    //lcdwrc(0xc);
                    qingpin();
                    break;
                    
            case 14:
                    lcdwrc(0xc);
                    ePutstr(str2);
                    lcdwrc(0x04);//設置光標左移,屏幕不移動    
                    if(fuhao==1)//
                    {
                        lcdwrc(0x4f+0x80);
                        c=a+b;
                        while(c!=0)     //一位一位顯示
                        {
                            lcdwrd(0x30+c%10);//顯示結果的最后一位在0x4f的位置
                            c=c/10;//取前面的結果數據    
                        }
                        lcdwrd(0x3d); //顯示等於號=
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除為0
                    }
                    if(fuhao==2)   //
                    {
                        lcdwrc(0x4f+0x80);
                        if(a>b)
                            c=a-b;
                        else
                            c=b-a;
                        while(c!=0)     //一位一位顯示
                        {    
                            lcdwrd(0x30+c%10);//顯示結果的最后一位在0x4f的位置
                            c=c/10;//取前面的結果數據    
                        }
                        if(a<b)    lcdwrd(0x2d); //顯示-號
                        lcdwrd(0x3d); //顯示等於號=
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除為0
                    }
                    if(fuhao==3)//乘法        
                    {
                        lcdwrc(0x4f+0x80);
                        c=a*b;
                        while(c!=0)     //一位一位顯示
                        {
                            lcdwrd(0x30+c%10);//顯示結果的最后一位在0x4f的位置
                            c=c/10;//取前面的結果數據    
                        }
                        lcdwrd(0x3d); //顯示等於號=
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除為0    
                    }
                    if(fuhao==4)//除法
                    {
                        lcdwrc(0x4f+0x80);
                        k=0;
                        c=(long)(((float)a/b)*1000);//強制轉換為long。
                        while(c!=0)     //一位一位顯示
                        {
                            k++;
                            lcdwrd(0x30+c%10);//顯示結果的最后一位在0x4f的位置
                            c=c/10;//取前面的結果數據
                            if(k==3)
                            {                    
                                lcdwrd(0x2e);//顯示點
                                k=0;
                            }        
                        }
                        if(a/b<1)      //如果a比b小的話那么除的結果最高位是0
                        {
                        lcdwrd(0x30);    
                        }
                        lcdwrd(0x3d); //顯示等號
                        a=0;
                        b=0;
                        flag=0;
                        fuhao=0;//全部清除為0
                    }
                    break;
        }
    }

}

void main()
{
    EA=1;//總中斷允許
    EX0=1;//允許外部中斷0中斷
    IT0=1;//選擇外部中斷0為觸發方式
    lcdinit();
    while(1)
    {
        keyscan();    
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM