《基于單片機(jī)的萬(wàn)年歷設(shè)計(jì).doc》由會(huì)員分享,可在線閱讀,更多相關(guān)《基于單片機(jī)的萬(wàn)年歷設(shè)計(jì).doc(29頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
基于單片機(jī)的萬(wàn)年歷設(shè)計(jì)
二、實(shí)驗(yàn)要求
設(shè)計(jì)一個(gè)萬(wàn)年歷,將時(shí)鐘顯示在LCD1602的顯示屏上并且可以進(jìn)行年、月、日以及時(shí)、分、秒的設(shè)置。此外還可以通過(guò)按鍵進(jìn)行鬧鐘設(shè)置以及事件提醒功能,用蜂鳴器進(jìn)行鬧鈴提醒。最后附加一個(gè)溫濕度檢測(cè)的功能,用溫濕度傳感器檢測(cè)室內(nèi)的溫濕度并將溫濕度數(shù)據(jù)在顯示屏上顯示出來(lái)。
三、實(shí)驗(yàn)設(shè)備和儀器
1.用 STC89C52芯片作為系統(tǒng)板的主控芯片
2.DHT11溫濕度傳感器
3.DS1302時(shí)鐘芯片
4.LCD1602顯示屏
四、實(shí)驗(yàn)各模塊原理介紹
4.1 STC89C52單片機(jī)
STC89C52是STC公司生產(chǎn)的一種低功耗、高性能CMOS8位微控制器,具有8K字節(jié)系統(tǒng)可編程Flash存儲(chǔ)器。STC89C52使用經(jīng)典的MCS-51內(nèi)核,具有傳統(tǒng)51單片機(jī)不具備的功能。在單芯片上,擁有靈巧的8 位CPU 和在系統(tǒng)可編程Flash,使得STC89C52為眾多嵌入式控制應(yīng)用系統(tǒng)提供高靈活、超有效的解決方案。
(1)主要特性
8K字節(jié)程序存儲(chǔ)空間;
512字節(jié)數(shù)據(jù)存儲(chǔ)空間;
內(nèi)帶4K字節(jié)EEPROM存儲(chǔ)空間;
可直接使用串口下載;
(2)器件參數(shù)
1. 增強(qiáng)型8051單片機(jī),6時(shí)鐘/機(jī)器周期和12時(shí)鐘/機(jī)器周期可以任意選擇,指令代碼完全兼容傳統(tǒng)8051。
2. 工作電壓:5.5V~3.3V(5V單片機(jī))/3.8V~2.0V(3V 單片機(jī))
3.工作頻率范圍:0~40MHz,相當(dāng)于普通8051的0~80MHz,實(shí)際工作頻率可達(dá)48MHz
4. 用戶應(yīng)用程序空間為8K字節(jié)
5. 片上集成512字節(jié)RAM
6. 通用I/O 口(32個(gè)),復(fù)位后為:P1/P2/P3 是準(zhǔn)雙向口/弱上拉,P0口是漏極開(kāi)路輸出,作為總線擴(kuò)展用時(shí),不用加上拉電阻,作為I/O口用時(shí),需加上拉電阻。
7. ISP(在系統(tǒng)可編程)/IAP(在應(yīng)用可編程),無(wú)需專用編程器,無(wú)需專用仿真器,可通過(guò)串口(RXD/P3.0,TXD/P3.1)直接下載用戶程序,數(shù)秒即可完成一片。
8. 具有EEPROM 功能
9. 共3個(gè)16位定時(shí)器/計(jì)數(shù)器。即定時(shí)器T0、T1、T2。
10.外部中斷4 路,下降沿中斷或低電平觸發(fā)電路,Power Down 模式可由外部中斷低電平觸發(fā)中斷方式喚醒。
11. 通用異步串行口(UART),還可用定時(shí)器軟件實(shí)現(xiàn)多個(gè)UART。
12. 工作溫度范圍:-40~+85℃(工業(yè)級(jí))/0~75℃(商業(yè)級(jí))
13. PDIP封裝
1、STC89C52單片機(jī)引腳圖
圖4.1 STC89C52單片機(jī)引腳圖
① 主電源引腳(2根)
VCC(Pin40):電源輸入,接+5V電源
GND(Pin20):接地線
②外接晶振引腳(2根)
XTAL1(Pin19):片內(nèi)振蕩電路的輸入端
XTAL2(Pin20):片內(nèi)振蕩電路的輸出端
③控制引腳(4根)
RST/VPP(Pin9):復(fù)位引腳,引腳上出現(xiàn)2個(gè)機(jī)器周期的高電平將使單片機(jī)復(fù)位。
ALE/PROG(Pin30):地址鎖存允許信號(hào)
PSEN(Pin29):外部存儲(chǔ)器讀選通信號(hào)
EA/VPP(Pin31):程序存儲(chǔ)器的內(nèi)外部選通,接低電平從外部程序存儲(chǔ)器讀指令,如果接高電平則從內(nèi)部程序存儲(chǔ)器讀指令。
④可編程輸入/輸出引腳(32根)
STC89C52單片機(jī)有4組8位的可編程I/O口,分別位P0、P1、P2、P3口,每個(gè)口有8位(8根引腳),共32根。
PO口(Pin39~Pin32):8位雙向I/O口線,名稱為P0.0~P0.7 P1口(Pin1~Pin8):8位準(zhǔn)雙向I/O口線,名稱為P1.0~P1.7 P2口(Pin21~Pin28):8位準(zhǔn)雙向I/O口線,名稱為P2.0~P2.7 P3口(Pin10~Pin17):8位準(zhǔn)雙向I/O口線,名稱為P3.0~P3.7。
2、STC89C52單片機(jī)最小系統(tǒng)
STC89C52單片機(jī)最小系統(tǒng)主要由復(fù)位電路和時(shí)鐘電路組成。復(fù)位功能通過(guò)外部電路來(lái)實(shí)現(xiàn),按下按鍵K1控制單片機(jī)的復(fù)位。時(shí)鐘電路主要通過(guò)晶振來(lái)實(shí)現(xiàn),為單片機(jī)提供運(yùn)行時(shí)鐘。根據(jù)不同的需求選用的晶振頻率會(huì)有差異,在本次課程設(shè)計(jì)中采用11.0592MHZ的晶振頻率。單片機(jī)復(fù)位電路如圖4.2所示,晶振電路如圖4.3所示。
圖4.2 復(fù)位電路
圖4.3晶振電路
4.2 DS1302芯片
DS1302是DALLAS公司出的一款實(shí)時(shí)時(shí)鐘芯片,它廣泛應(yīng)用于電話、傳真、便攜式儀器等產(chǎn)品領(lǐng)域,主要性能指標(biāo)如下:
1、DS1302是一個(gè)實(shí)時(shí)時(shí)鐘芯片,可以提供秒、分、小時(shí)、日期、月、年等信息,具有軟件自動(dòng)調(diào)整的能力,可以通過(guò)配置AM/PM來(lái)決定采用24小時(shí)格式還是12小時(shí)格式。
2、擁有31字節(jié)數(shù)據(jù)存儲(chǔ)RAM。
3、串行I/O通信方式。
4、DS1302的工作電壓比較寬,在2.0V~5.5V范圍內(nèi)均可正常工作。采用雙電源供電,當(dāng)主電源比備用電源高0.2V時(shí),由主電源供電,否則采用備用電源,一般是一個(gè)紐扣電池。
5、DS1302實(shí)時(shí)時(shí)鐘芯片的功耗很低,當(dāng)工作電壓為2.0V時(shí),工作電流小于300nA。
6、DS1302共有8個(gè)引腳,有兩種封裝形式,一種是DIP-8封裝,芯片寬度(不含引腳)是300mil,一種是SOP-8封裝,有兩種寬度,一種是150mil,一種是208mil。
(1) DS1302引腳及其功能
圖 4.4 DS1302芯片引腳圖
(1)Vcc2:主電源引腳,當(dāng)Vcc2比Vcc1高0.2v以上時(shí),DS1302由Vcc2供電,當(dāng)Vcc2低于Vcc1時(shí),由Vcc1供電。
(2、3)X1、X2:這兩個(gè)引腳需要接一個(gè)32.768k的晶振,為了給DS1302提供一個(gè)基準(zhǔn)。但是該晶振的引腳負(fù)載電容必須為6pF,若使用有源晶振,接到X1上即可,X2則懸空。
(4)GND:接地
(5)CE:DS1302的輸入引腳。該引腳內(nèi)部有一個(gè)40k的下拉電阻,當(dāng)該引腳為高電平,對(duì)DS1302進(jìn)行讀寫(xiě)。
(6)I/O:該引腳是一個(gè)雙向通信引腳,且內(nèi)部含有一個(gè)40k的下拉電阻,可進(jìn)行數(shù)據(jù)的讀寫(xiě)。
(7)SCLK:該引腳是輸入引腳,且內(nèi)部含有一個(gè)40k的下拉電阻,作為通信的時(shí)鐘信號(hào)。
(8)Vcc1:備用電源引腳。
(2) DS1302與單片機(jī)接線圖
DS1302引腳與單片機(jī)接線圖如圖4.5所示,從圖4.5可看出,引腳X1與X2之間接一個(gè)32.768K的晶體正振蕩器,Vcc1通過(guò)一個(gè)紐扣能電池再接地。
圖4.5 DS1302與單片機(jī)連接圖
4.3 LCD1602液晶顯示屏
LCD1602液晶屏能夠能夠同時(shí)顯示32個(gè)字符,價(jià)格便宜,編程簡(jiǎn)單而且穩(wěn)定可靠。LCD1602液晶屏是一種圖形點(diǎn)陣顯示器,顯示原理簡(jiǎn)單易懂,都是液晶屏內(nèi)部的液晶材料變化而顯示不同的字符,因?yàn)橐壕蔷哂辛鲃?dòng)特性的物質(zhì),所以只需外加很微小的力量即可使液晶分子運(yùn)動(dòng)。
(1)LCD1602引腳
1602LCD采用標(biāo)準(zhǔn)的14腳(無(wú)背光)或16腳(帶背光)接口,各引腳接口圖如圖4.6所示:
圖4.6 LCD1602引腳圖
(a) 各個(gè)引腳說(shuō)明
1腳:VSS為地電源
2腳:VDD接5V正電源
3腳:V0為液晶顯示器對(duì)比度調(diào)整端,接正電源時(shí)對(duì)比度最弱,接地時(shí)對(duì)比
對(duì)比度過(guò)高時(shí)會(huì)產(chǎn)生“鬼影”,使用時(shí)可以通過(guò)一個(gè)10K的電位器調(diào)整。
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為高電平;
RS為高電平,R/W為低電平時(shí)可以寫(xiě)入數(shù)據(jù)。
6腳:E端為使能端,當(dāng)E端由高電平跳變成低電平時(shí),液晶模塊執(zhí)行命令。
7~14腳:D0~D7為8位雙向數(shù)據(jù)線。
15腳:背光源正極
16腳:背光源負(fù)極
(b)LCD1602主要技術(shù)參數(shù):
顯示容量:32個(gè)字符;
芯片工作電壓:4.5-5.5V;
工作電流:2.0mA(5.0V);
模塊最佳工作電壓:5.0V;
(2)LCD1602與單片機(jī)接線圖
圖4.7 LCD1602與單片機(jī)接線圖
LCD1602與單片機(jī)接線圖如4.7所示,背光源正極(5)與VDD(2)均接電源,將液晶顯示器接地保證對(duì)比度最強(qiáng),可使用一個(gè)10K的電位器進(jìn)行調(diào)整。
4.4 溫濕度傳感器DHT11
DHT11數(shù)字溫濕度傳感器是一款含有已校準(zhǔn)數(shù)字信號(hào)輸出的溫濕度復(fù)合傳感器。它采用專用的數(shù)字模塊采集技術(shù)、溫濕度傳感技術(shù),確保產(chǎn)品的可靠性、長(zhǎng)期穩(wěn)定性。傳感器包括一個(gè)電阻式感濕元件和一個(gè)NTC測(cè)溫元件,并與一個(gè)高性能8位單片機(jī)相連接。因此,該產(chǎn)品具有品質(zhì)卓越、超快響應(yīng)、抗干擾能力強(qiáng)、性價(jià)比極高等優(yōu)點(diǎn)。
每個(gè)DHT11傳感器都在極為精確的濕度校驗(yàn)室中進(jìn)行校準(zhǔn)。校準(zhǔn)系數(shù)以程序的形式儲(chǔ)存在OTP內(nèi)存中,傳感器內(nèi)部在檢測(cè)信號(hào)的處理過(guò)程中要調(diào)用這些校準(zhǔn)系數(shù)。單線制串行接口,使系統(tǒng)集成變得簡(jiǎn)易快捷。超小的體積、極低的功耗,信號(hào)傳輸距離可達(dá)20米以上,使其成為各類應(yīng)用甚至最為苛刻的應(yīng)用場(chǎng)合的最佳選則。產(chǎn)品為4針單排引腳封裝,連接方便,特殊封裝形式可根據(jù)用戶需求而提供。
(1)DHT11引腳及其功能
DHT11的引腳圖如圖4.8所示,一般情況下它有四個(gè)引腳,分別為:VCC、DOUT、NC、GND。各引腳以及功能如表4-1所示。
圖4.8 DHT11引腳圖
表4-1 DHT11引腳及其功能
pin
名稱
注釋
1
VDD
供電3-5.5VDC
2
DATA
串行數(shù)據(jù),單總線
3
NC
空腳,請(qǐng)懸空
4
GND
接地,電源負(fù)極
1.電源引腳
DHT11的供電電壓為3-5.5V。傳感器上電后,要等待 1s 以越過(guò)不穩(wěn)定狀態(tài)在此期間無(wú)需發(fā)送任何指令。電源引腳(VDD,GND)之間可增加一個(gè)100nF 的電容,作用在于去耦濾波。
2.串行接口(單線雙向)
DATA是用于微處理器與DHT11之間的通信和同步的串行雙向接口,采用單總線數(shù)據(jù)格式。每次通信都是以高位先出的順序傳輸40位數(shù)據(jù),用時(shí)約為4 ms。
數(shù)據(jù)格式為:
8位濕度整數(shù)數(shù)據(jù)+8位濕度小數(shù)數(shù)據(jù)+8位溫度整數(shù)數(shù)據(jù)+8位溫度小數(shù)數(shù)據(jù)+8位校驗(yàn)和數(shù)據(jù)。數(shù)據(jù)分小數(shù)部分和整數(shù)部分,當(dāng)前小數(shù)部分用于以后擴(kuò)展,現(xiàn)讀出為零。數(shù)據(jù)傳送正確時(shí),校驗(yàn)和數(shù)據(jù)等于“8位濕度整數(shù)數(shù)據(jù)+8位濕度小數(shù)數(shù)據(jù)+8位溫度整數(shù)數(shù)據(jù)+8位溫度小數(shù)數(shù)據(jù)”所得結(jié)果的末8位。
(2)DHT11與單片機(jī)接線圖
DHT11與單片機(jī)的接線圖如圖4.9所示,由圖4.9中可看出,DHT11第三個(gè)引腳接單片機(jī)的P2.2引腳,第一個(gè)引腳接電阻和發(fā)光二極管。
圖4.9 DHT11與單片機(jī)接線圖
4.5 蜂鳴器
蜂鳴器是一種一體化結(jié)構(gòu)的電子訊響器,采用直流電壓供電,廣泛應(yīng)用于計(jì)算機(jī)、打印機(jī)、復(fù)印機(jī)、報(bào)警器、電子玩具、汽車電子設(shè)備、電話機(jī)、定時(shí)器等電子產(chǎn)品中作發(fā)聲器件。蜂鳴器可分為無(wú)源蜂鳴器和有源蜂鳴器兩種,此處我們用到的是有源蜂鳴器。有源蜂鳴器工作的理想信號(hào)是直流電,通常標(biāo)示為VDC、VDD等。因?yàn)榉澍Q器內(nèi)部有一簡(jiǎn)單的振蕩電路,能將恒定的直流電轉(zhuǎn)化成一定頻率的脈沖信號(hào),從而帶動(dòng)鉬片振動(dòng)發(fā)音。
有源蜂鳴器主要靠壓電效應(yīng)的原理來(lái)發(fā)聲的,且內(nèi)部帶有多諧振蕩器,可產(chǎn)生1.5-2.5kHZ 的電壓信號(hào)。由此有源蜂鳴器才能發(fā)聲。有源蜂鳴器在單片機(jī)中的電路圖較為簡(jiǎn)單,圖4.10為蜂鳴器與單片機(jī)的接線圖。
圖4.10 蜂鳴器與單片機(jī)的接線圖
有源蜂鳴器直接接上額定電源就可連續(xù)發(fā)聲,I/O口輸出后接一個(gè)1K的電阻,目的在于基極限流,以低電平方式,啟動(dòng)蜂鳴器發(fā)聲。
五、流程圖
(1) 主程序流程圖
圖5.1是系統(tǒng)主程序流程圖,系統(tǒng)開(kāi)始時(shí)先進(jìn)行初始化,然后再調(diào)整時(shí)間和鬧鐘,再通過(guò)串口屏將時(shí)間顯示出來(lái)。
圖5.1 主程序流程圖
(2)子程序流程圖
系統(tǒng)從主程序開(kāi)始執(zhí)行,分別調(diào)用各個(gè)子程序,其中子程序包括DS1302子程序,DHT11子程序和LCD1602子程序等。
(1)DS1302芯片子程序流程圖
DS1302為實(shí)時(shí)時(shí)鐘芯片,可以提供秒、分、時(shí)、日、月、年及星期等信息,具有軟件自動(dòng)調(diào)整的能力,可以通過(guò)配置AM/PM來(lái)決定采用24小時(shí)格式還是12小時(shí)格式。從DS1302中可以讀出年、月、日、時(shí)、分、秒等信息。圖5.2為DS1302芯片的子程序流程圖:
圖5.2 DS1302子程序流程圖
(2)DHT11子程序流程圖
DHT11為溫濕度傳感器,可以實(shí)時(shí)顯示環(huán)境中的溫濕度。其數(shù)據(jù)由8位濕度整數(shù)數(shù)據(jù),8位濕度小數(shù)數(shù)據(jù),8位溫度整數(shù)數(shù)據(jù)和8位溫度小數(shù)數(shù)據(jù)以及8位校驗(yàn)和數(shù)據(jù)。DHT11子程序流程圖如5.3所示:
圖5.3 DHT11子程序流程圖
(3)LCD1602子程序流程圖
LCD1602顯示時(shí),也要先進(jìn)行初始化,緊接著讀指令,讀完之后寫(xiě)指令,再對(duì)數(shù)據(jù)進(jìn)行讀寫(xiě),然后顯示出來(lái),其流程圖如圖5.4所示。
圖5.4 LCD1602顯示屏子程序流程圖
六、實(shí)驗(yàn)?zāi)康?
1.學(xué)會(huì)并掌握可keil軟件的使用;
2.學(xué)會(huì)并掌握Altium Designer軟件的使用;
3.實(shí)現(xiàn)萬(wàn)年歷的基本功能;
4.通過(guò)實(shí)驗(yàn)鞏固單片機(jī)相關(guān)知識(shí)和檢驗(yàn)自身動(dòng)手能力
七、實(shí)驗(yàn)內(nèi)容
本次實(shí)驗(yàn)使用STC89C52單片機(jī)作為主控芯片,使用DS1302芯片作為時(shí)鐘芯片,在LCD1602顯示屏上顯示,并可以設(shè)置鬧鐘和事件提醒功能,此外還可以進(jìn)行室內(nèi)溫濕度的檢測(cè)和顯示,最終完成萬(wàn)年歷的設(shè)計(jì)。
八、實(shí)驗(yàn)步驟
1.查詢資料,確定主控芯片、溫濕度傳感器、時(shí)鐘芯片以及LCD1602顯示屏的使用說(shuō)明。
2.根據(jù)功能要求進(jìn)行硬件電路的設(shè)計(jì),使用Altium Designer軟件設(shè)計(jì)電路。整個(gè)電路分為主控芯片控制模塊、LCD1602顯示模塊、按鍵設(shè)置模塊、蜂鳴器電路模塊以及DHT11溫濕度傳感器模塊。硬件電路圖如圖1所示:
圖8.1:硬件電路圖
3.根據(jù)電路圖編寫(xiě)C語(yǔ)言代碼:
代碼如下:
#include
#define uchar unsigned char
#define uint unsigned int
#define lcddata P0
#define readalarmsecond 0xc7 //定義從 DS1302 中讀鬧鐘秒值的命令字節(jié)
#define writealarmsecond 0xc6 //定義往 DS1302 中寫(xiě)鬧鐘秒值的命令字節(jié)
#define readalarmminute 0xc5 //定義從 DS1302 中讀鬧鐘分值的命令字節(jié)
#define writealarmminute 0xc4 //定義往 DS1302 中寫(xiě)鬧鐘分值的命令字節(jié)
#define readalarmhour 0xc3 //定義從 DS1302 中讀鬧鐘小時(shí)值命令字節(jié)
#define writealarmhour 0xc2 //定義往 DS1302 中寫(xiě)鬧鐘小時(shí)值命令字節(jié)
#define readeventday 0xd7 //定義從 DS1302 中讀事件提醒日期值的命令字節(jié)
#define writeeventday 0xd6 //定義往 DS1302 中寫(xiě)事件提醒日期值的命令字節(jié)
#define readeventmonth 0xd5 //定義從 DS1302 中讀事件提醒月份值的命令字節(jié)
#define writeeventmonth 0xd4 //定義往 DS1302 中寫(xiě)事件提醒月份值的命令字節(jié)
#define readeventyear 0xd3 //定義從 DS1302 中讀事件提醒年份值的命令字節(jié)
#define writeeventyear 0xd2 //定義往 DS1302 中寫(xiě)事件提醒年份值的命令字節(jié)
sbit lcdrs=P2^7; //LCD 數(shù)據(jù) /命令選擇端 (H/L)
sbit lcdrw=P2^6; //LCD 讀/寫(xiě)選擇端 (H/L)
sbit lcden=P2^5; //LCD 使能控制
sbit beep=P1^3; //蜂鳴器控制端
sbit DQ = P1^4; //溫濕度傳感器
sbit kmenu=P3^2; //功能鍵
sbit kup=P3^3; //增大鍵
sbit kdown=P3^4; //減小鍵
sbit kalarm=P3^5; //鬧鐘查看鍵 Ring: 顯示鬧鐘需要調(diào)到的時(shí)間
sbit kevent=P3^6; //事件查看鍵 Ding: 顯示事件提醒需要調(diào)到的時(shí)間
//sbit kmode=P3^7; //切換溫濕度顯示
sbit dsclk=P2^2; //ds1302 的時(shí)鐘信號(hào)端
sbit dsdata=P2^1; //ds1302 的數(shù)據(jù) I/O 端
sbit dsrst=P2^0; //ds1302 的復(fù)位端
sbit ACC7=ACC^7; //定義累加器的最高和最低位。
sbit ACC0=ACC^0;
bit flagalarm,flagseta,flagset; // 分別定義鬧鐘響標(biāo)志位,鬧鐘設(shè)置標(biāo)志位,時(shí)間設(shè)置標(biāo)志位
bit flagevent,flagsseta; // 分別定義事件提醒標(biāo)志位,事件提醒設(shè)置標(biāo)志位
uchar FLAG,k;
uchar temp;
uchar T_data_H,T_data_L,RH_data_H,RH_data_L,checkdata;
uchar T_data_H_temp,T_data_L_temp,RH_data_H_temp,RH_data_L_temp,checkdata_temp;
uchar comdata;
uchar kmenunum,s,m,h,dd,mm,yy; //功能鍵被按次數(shù)的計(jì)數(shù)器 .
char second,minute,hour,year,month,day,week;
uchar inittime[7]={0x59,0x59,0x11,0x05,0x07,0x04,0x18}; //初始化后設(shè)置為:
//2018 年 7 月 5 日 星期四, 11 點(diǎn) 59 分 59 秒,
//從左往右的數(shù)據(jù)依次是,秒,分,時(shí),日,月,星期,年。
// 年月日星期: 2018-07-05 THU
// 時(shí)間: 11:59:59
uchar code t1[]=" - - "; //液晶固定顯示部分。
uchar code t2[]=" : : ";
//各函數(shù)聲明
void delay(uint z); //毫秒級(jí)延時(shí)函數(shù)。
void di(); //蜂鳴器發(fā)聲函數(shù)。
void writecom(uchar com); //液晶寫(xiě)命令函數(shù)。
void writedata(uchar dat); //液晶寫(xiě)數(shù)據(jù)函數(shù)。
void writetime(uchar add,uchar dat); // 液晶刷新時(shí)分秒。
void writenyr(uchar add,uchar dat); // 液晶刷新日期。
void writeweek(uchar week); // 液晶星期幾顯示函數(shù)。
void keyscan(); // 鍵盤(pán)掃描函數(shù)。
void dswritebyte(uchar d);// 往 DS1302 寫(xiě)入一個(gè)字節(jié)。
uchar dsreadbyte(); //從 DS1302 讀出一個(gè)字節(jié)。
void dswrite(uchar add, uchar dat); // 向 DS1302 的指定地址寫(xiě)入一個(gè)字節(jié)
uchar dsread(uchar add); //從 DS1302 的指定地址讀出一個(gè)字節(jié)
void init1302time(uchar *pClock); //DS1302 時(shí)間初始化函數(shù)
void init(); //初始化函數(shù)
void Delay_100us(uint j);//延時(shí)100us
void Delay_10us(void);//延時(shí)10us
void COM(void);
void Read_DHT11(void);
void delay(uint z) //毫秒級(jí)延時(shí)函數(shù)。
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void di() //蜂鳴器發(fā)聲函數(shù)。
{
beep=0;
delay(100);
beep=1;
}
void writecom(uchar com) //液晶寫(xiě)命令函數(shù)。
{
lcdrs=0;// 置為寫(xiě)入命令
lcddata=com;// 送入數(shù)據(jù)
delay(1);
lcden=1;// 拉高使能端
delay(1);
lcden=0;// 完成高脈沖
}
void writedata(uchar dat) //液晶寫(xiě)數(shù)據(jù)函數(shù)。
{
lcdrs=1;// 置為寫(xiě)入數(shù)據(jù)
lcddata=dat;// 送入數(shù)據(jù)
delay(1);
lcden=1;
delay(1);
lcden=0;
}
void writetime(uchar add,uchar dat) // 液晶刷新時(shí)分秒。
{ //3為時(shí)的開(kāi)始位置,6 為分, 9 為秒。
uchar shi,ge;
shi=dat/10;
ge=dat%10;
writecom(0x80+0x40+add);
writedata(0x30+shi);
writedata(0x30+ge);
}
void writenyr(uchar add,uchar dat) // 液晶刷新日期。
{ //0 為年, 3 為月, 6 為日。
uchar shi,ge;
shi=dat/10;
ge=dat%10;
writecom(0x80+add);
writedata(0x30+shi);
writedata(0x30+ge);
}
void writeweek(uchar week) // 液晶星期幾顯示函數(shù)。
{
writecom(0x80+9); //從第一行隔十三個(gè)字符后開(kāi)始寫(xiě)星期
switch(week)
{
case 1: writedata(M);
writedata(O);
writedata(N);
break;
case 2: writedata(T);
writedata(U);
writedata(E);
break;
case 3: writedata(W);
writedata(E);
writedata(D);
break;
case 4: writedata(T);
writedata(H);
writedata(U);
break;
case 5: writedata(F);
writedata(R);
writedata(I);
break;
case 6: writedata(S);
writedata(A);
writedata(T);
break;
case 7: writedata(S);
writedata(U);
writedata(N);
break;
}
}
void keyscan() // 鍵盤(pán)掃描函數(shù)。
{
if((flagalarm==1)||(flagevent==1)) // 如果鬧鐘在響或者有事件提醒,任意鍵停止鬧鐘響或者取消事件提醒
{
if((kmenu==0)||(kup==0)||(kdown==0)||(kalarm==0)||(kevent==0))
{
delay(5);
if((kmenu==0)||(kup==0)||(kdown==0)||(kalarm==0)||(kevent==0))
{
while(!(kmenu&&kup&&kdown&&kalarm&&kevent));
di();
flagalarm=0; // 清除鬧鐘標(biāo)志。
flagevent=0; // 清除事件提醒標(biāo)志。
}
}
}
if(kmenu==0) //檢測(cè)功能鍵。
{
delay(5);
if(kmenu==0)
{
kmenunum++; // 記錄功能鍵按下次數(shù)。
if(flagseta==1) // 檢測(cè)是否在進(jìn)行鬧鐘設(shè)置。
if(kmenunum==4) kmenunum=1; // 因?yàn)檫M(jìn)行鬧鐘設(shè)置時(shí),只調(diào)節(jié)時(shí)分秒,所以, kmenunum 只能等于 1,2,3。
if(flagsseta==1) // 檢測(cè)是否在進(jìn)行事件提醒設(shè)置。
if(kmenunum==8) kmenunum=5; // 因?yàn)檫M(jìn)行事件提醒設(shè)置時(shí),只調(diào)節(jié)年月日,所以, kmenunum 只能等于 5,6,7
flagset=1; // 設(shè)置標(biāo)志位,表示在進(jìn)行各種時(shí)間設(shè)置。
while(!kmenu);
di();
switch(kmenunum) //定位光標(biāo)閃爍點(diǎn)。
{
case 1: writecom(0x80+0x40+10); // 秒閃爍。
writecom(0x0f); // 開(kāi)光標(biāo)閃爍。
break;
case 2: writecom(0x80+0x40+7); // 分閃爍。
break;
case 3: writecom(0x80+0x40+4); // 時(shí)閃爍。
break;
case 4: writecom(0x80+10); //星期閃爍 .
break;
case 5: writecom(0x80+7); //日閃爍 .
break;
case 6: writecom(0x80+4); //月閃爍 .
break;
case 7: writecom(0x80+1); //年閃爍 .
break;
case 8: kmenunum=0;
writecom(0x0c); // 取消光標(biāo)閃爍。
flagset=0; //取消時(shí)間調(diào)節(jié)標(biāo)志。
dswrite(0x8e,0x00); /* 允許寫(xiě)操作 */
dswrite(0x80,second/10*16+second%10); dswrite(0x82,minute/10*16+minute%10); dswrite(0x84,hour/10*16+hour%10);
dswrite(0x8a,week/10*16+week%10);
dswrite(0x86,day/10*16+day%10);
dswrite(0x88,month/10*16+month%10);
dswrite(0x8c,year/10*16+year%10);
dswrite(0x8e,0x80); /* 禁止寫(xiě)操作 */
break;
}
}
}
if(kmenunum!=0) //只有當(dāng)功能鍵按下時(shí) ,才檢測(cè)增大 ,減小鍵 .
{
if(kup==0)
{
delay(5);
if(kup==0)
{
while(!kup);
di();
switch(kmenunum) //根據(jù)功能鍵被按下的次數(shù),調(diào)節(jié)相應(yīng)數(shù)值。
{
case 1: second++;
if(second==60)
second=0;
writetime(9,second);
writecom(0x80+0x40+10); // 因?yàn)?,上面送液晶顯示
break; //一次 ,光標(biāo)后移一位 ,所以要將光標(biāo)復(fù)位 .
case 2: minute++;
if(minute==60)
minute=0;
writetime(6,minute);
writecom(0x80+0x40+7);
break;
case 3: hour++;
if(hour==24)
hour=0;
writetime(3,hour);
writecom(0x80+0x40+4);
break;
case 4: week++;
if(week==8)
week=1;
writeweek(week);
writecom(0x80+11);
break;
case 5: day++;
if(day==32)
day=1;
writenyr(6,day);
writecom(0x80+7);
break;
case 6: month++;
if(month==13)
month=1;
writenyr(3,month);
writecom(0x80+4);
break;
case 7: year++;
if(year==100)
year=0;
writenyr(0,year);
writecom(0x80+1);
break;
}
}
}
if(kdown==0)
{
delay(5);
if(kdown==0)
{
while(!kdown);
di();
switch(kmenunum) //根據(jù)功能鍵被按次數(shù)調(diào)節(jié)相應(yīng)數(shù)值 .
{
case 1: second--;
if(second==-1)
second=59;
writetime(9,second);
writecom(0x80+0x40+10);
break;
case 2: minute--;
if(minute==-1)
minute=59;
writetime(6,minute);
writecom(0x80+0x40+7);
break;
case 3: hour--;
if(hour==-1)
hour=23;
writetime(3,hour);
writecom(0x80+0x40+4);
break;
case 4: week--;
if(week==0)
week=7;
writeweek(week);
writecom(0x80+11);
break;
case 5: day--;
if(day==0)
day=31;
writenyr(6,day);
writecom(0x80+7);
break;
case 6: month--;
if(month==0)
month=12;
writenyr(3,month);
writecom(0x80+4);
break;
case 7: year--;
if(year==-1)
year=99;
writenyr(0,year);
writecom(0x80+1);
break;
}
}
}
}
if(kalarm==0) // 檢測(cè)鬧鐘調(diào)節(jié)鍵是否按下,此條if 語(yǔ)句與 if(kmenunum!=0)
{ // 在同一個(gè)層次。
delay(5);
if(kalarm==0)
{
flagseta=~flagseta;
while(!kalarm);
di();
if(flagseta==0) //此時(shí),退出鬧鐘設(shè)置,保存各相關(guān)數(shù)值。
{
flagset=0; //清除時(shí)間設(shè)置標(biāo)志,在 if(kalarm==0) 這個(gè) if 語(yǔ)句writecom(0x80+0x40)中,不用 flagset=1 這條語(yǔ)句來(lái)設(shè)置
//flagset 標(biāo)志位,因?yàn)槿绻M(jìn)行了鬧鐘時(shí)間的設(shè)置就會(huì)執(zhí)行前面 if(kmenunum==0) 語(yǔ)句中的 flagset=1 這條語(yǔ)句。
writedata( ); // 清除液晶上的 “ Ri鬧鐘調(diào)節(jié)標(biāo)志。 ”
writedata( );
writecom(0x0c); //取消光標(biāo)閃爍
dswrite(0x8e,0x00); /* 允許寫(xiě)操作 */
dswrite(writealarmsecond,second/10*16+second%10); // 往 DS1302 中保存鬧鐘的時(shí)分秒值。
dswrite(writealarmminute,minute/10*16+minute%10);
dswrite(writealarmhour,hour/10*16+hour%10);
dswrite(0x8e,0x80); /* 禁止寫(xiě)操作 */
}
else //進(jìn)入鬧鐘設(shè)置。
{
s=dsread(readalarmsecond)/16*10+dsread(readalarmsecond)%16; /* 讀取DS1302 中保存的鬧鐘時(shí)分秒原始值,轉(zhuǎn)化為十進(jìn)制數(shù)存進(jìn) s,m,h 保存,用以后面判斷鬧鐘時(shí)間是否到達(dá)。*/
m=dsread(readalarmminute)/16*10+dsread(readalarmminute)%16;
h=dsread(readalarmhour)/16*10+dsread(readalarmhour)%16;
second=s; //把鬧鐘時(shí)間的十進(jìn)制數(shù)據(jù)傳送給變量 second,minute,hour,用以調(diào)節(jié)其值。
minute=m;
hour=h;
writecom(0x80+0x40);
writedata(R); // 液晶顯示鬧鐘調(diào)節(jié)標(biāo)志。
writedata(i);
writetime(3,hour); // 送液晶顯示鬧鐘時(shí)間。
writetime(6,minute);
writetime(9,second);
}
}
}
if(kevent==0) // 檢測(cè)事件提醒調(diào)節(jié)鍵是否按下,此條 if 語(yǔ)句與 if(kmenunum!=0)
{ // 在同一個(gè)層次。
delay(5);
if(kevent==0)
{
flagsseta=~flagsseta;
while(!kevent);
di();
if(flagsseta==0) //此時(shí),退出事件提醒設(shè)置,保存各相關(guān)數(shù)值。
{
flagset=0; //清除時(shí)間設(shè)置標(biāo)志,在 if(kevent==0) 這個(gè) if 語(yǔ)句
writecom(0x80+9);// 中,不用 flagset=1 這條語(yǔ)句來(lái)設(shè)置
//flagset 標(biāo)志位,因?yàn)?,如果進(jìn)行了事件提醒時(shí)間的設(shè)置
//,就會(huì)執(zhí)行前面 if(kmenunum==0) 語(yǔ)句中的 flagset=1 這條語(yǔ)句。
writedata( ); // 清除液晶上的 “ Ti 事件提醒調(diào)節(jié)標(biāo)志。 ”
writedata( );
writedata( );
writecom(0x0c); //取消光標(biāo)閃爍
dswrite(0x8e,0x00); /* 允許寫(xiě)操作 */
dswrite(writeeventyear,year/10*16+year%10); // 往 DS1302 中保存事件提醒的年月日值。
dswrite(writeeventmonth,month/10*16+month%10);
dswrite(writeeventday,day/10*16+day%10);
dswrite(0x8e,0x80); /* 禁止寫(xiě)操作 */
}
else //進(jìn)入事件提醒設(shè)置。
{
yy=dsread(readeventyear)/16*10+dsread(readeventyear)%16; /* 讀取DS1302 中保存的事件提醒年月日原始值,轉(zhuǎn)化為十進(jìn)制數(shù)存進(jìn) yy,mm,dd 保存,用以后面判斷事件提醒時(shí)間是否到達(dá)。*/
mm=dsread(readeventmonth)/16*10+dsread(readeventmonth)%16;
dd=dsread(readeventday)/16*10+dsread(readeventday)%16;
year=yy; //把事件提醒時(shí)間的十進(jìn)制數(shù)據(jù)傳送給變量 hour,day,month,week用以調(diào)節(jié)其值。
month=mm;
day=dd;
writecom(0x80+9);
writedata(T); // 液晶顯示事件提醒設(shè)置標(biāo)志。
writedata(i);
writedata( );
writenyr(0,year);// 送液晶顯示事件提醒時(shí)間。
writenyr(3,month);
writenyr(6,day);
}
}
}
}
void dswritebyte(uchar d)// 往 DS1302 寫(xiě)入一個(gè)字節(jié)。
{
uchar i;
ACC=d;
for(i=8;i>0;i--)
{
dsdata=ACC0;
dsclk=1; /*為什么這里時(shí)鐘先為 1 后為 0,因?yàn)?dsclk 初始化為 0,而,每次循環(huán)
最后 ,都將其置 0,這樣就形成一個(gè)從 0 開(kāi)始的上升沿 ,恰好滿足 ds1302 寫(xiě)數(shù)據(jù)在上升沿, 但是 ,
時(shí)鐘必須從 0 開(kāi)始的要求 */
dsclk=0;
ACC=ACC>>1;
}
}
uchar dsreadbyte() //從 DS1302 讀出一個(gè)字節(jié)。
{
uchar i;
for(i=8;i>0;i--)
{
ACC=ACC>>1;
ACC7=dsdata;
dsclk=1; // 讀數(shù)據(jù)也一樣 ,雖然是下降沿 ,但是 ,也要從 0 開(kāi)始 .這樣設(shè)置 dsclk 剛好滿足要求。
dsclk=0;
}
return ACC;
}
void dswrite(uchar add,uchar dat) // 向 DS1302 的指定地址寫(xiě)入一個(gè)字節(jié)。
{
dsrst=0;
dsclk=0;
dsrst=1;
dswritebyte(add); /* 先寫(xiě)入地址 ,命令字節(jié) */
dswritebyte(dat); /* 再寫(xiě) 1Byte 數(shù)據(jù) */
dsclk=1;
dsrst=0;
}
uchar dsread(uchar add) //從 DS1302 的指定地址讀出一個(gè)字節(jié) .
{
uchar dat;
dsrst=0;
dsclk=0;
dsrst=1;
dswritebyte(add); /* 先寫(xiě)入地址 ,命令字節(jié) */
dat=dsreadbyte(); /* 再讀 1Byte 數(shù)據(jù) */
dsclk=1;
dsrst=0;
return dat;
}
void init1302time(uchar *pClock) //DS1302 時(shí)間初始化函數(shù) .
{
uchar i;
uchar add=0x80;
dswrite(0x8e,0x00); /* 允許寫(xiě)操作 */
for(i=7;i>0;i--)
{
dswrite(add,*pClock); /* 依次寫(xiě)入秒 分 時(shí) 日 月 星期 年 */
pClock++;
add+=2; //因?yàn)?DS1302 同一個(gè)時(shí)鐘寄存器占兩個(gè)地址,最低位為 0,是
} //用于寫(xiě)的地址 ,最低位為 1,是用于讀的地址 .所以 add 加 2.
dswrite(0x8e,0x80); /* 禁止寫(xiě)操作 */
}
void init() //初始化函數(shù)。
{
uchar num;
//變量初始化 .
flagset=0; // 時(shí)間設(shè)置標(biāo)志位置 0,表示未進(jìn)行時(shí)間設(shè)置
flagseta=0; //鬧鐘設(shè)置標(biāo)志位置 0.
flagalarm=0;// 鬧鐘標(biāo)志位置 0.
kmenunum=0; //功能鍵被按次數(shù)計(jì)數(shù)器置 0.
lcdrw=0;
//DS1302 初始化。
dswrite(0x8e,0x00); /* 允許寫(xiě)操作 */
dswrite(0x80,0x00);// 打開(kāi) DS1302 晶振,使其開(kāi)始工作。
dswrite(0x84,0x00);// 設(shè)置為 24 小時(shí)制。
init1302time(inittime);// 初始化時(shí)間為:
//2018 年 7 月 5 日 星期四, 11 點(diǎn) 59 分 59 秒,
//從左往右的數(shù)據(jù)依次是,秒,分,時(shí),日,月,星期,年。
dswrite(0x8e,0x80); /* 禁止寫(xiě)操作 */
//1602 液晶初始化。
writecom(0x38);//開(kāi)顯示
writecom(0x0c);//開(kāi)顯示不顯示光標(biāo)
writecom(0x06);//寫(xiě)一個(gè)指針加1
writecom(0x01);//清屏
writecom(0x80);//設(shè)置數(shù)據(jù)指針起點(diǎn)
for(num=0;num<16;num++) //寫(xiě)入液晶固定顯示部分。
{
writedata(t1[num]);
delay(1);
}
writecom(0x80+0x40); // 換到液晶第二行。
for(num=0;num<16;num++)
{
writedata(t2[num]);
delay(1);
}
}
void Delay_100us(uint j)//延時(shí)100us
{
uchar i;
for(;j>0;j--)
for(i=0;i<27;i++);//STC89C52RC
}
void Delay_10us(void)//延時(shí)10us
{
uchar i;
i--;i--;i--;i--;i--;i--;//STC89C52RC
}
void COM(void)
{
uchar i;
for(i=0;i<8;i++)
{
FLAG=2;
while((!DQ)&&FLAG++);
Delay_10us();
Delay_10us();
Delay_10us();
temp=0;
if(DQ)temp=1;
FLAG=2;
while((DQ)&&FLAG++);
//超時(shí)則跳出for循環(huán)
if(FLAG==1) break;
//判斷數(shù)據(jù)位是0還是1
// 如果高電平高過(guò)預(yù)定0高電平值則數(shù)據(jù)位為 1
comdata<<=1;
comdata|=temp; //0
}//rof
}
//--------------------------------
//-----濕度讀取子程序 ------------
//--------------------------------
//----以下變量均為全局變量--------
//----溫度高8位== T_data_H------
//----溫度低8位== T_data_L------
//----濕度高8位== RH_data_H-----
//----濕度低8位== RH_data_L-----
//----校驗(yàn) 8位 == checkdata-----
//----調(diào)用相關(guān)子程序如下----------
//---- Delay();, Delay_10us();,COM();
//--------------------------------
鏈接地址:http://www.820124.com/p-6679430.html