單片機課程設(shè)計,電子萬年歷_第1頁
單片機課程設(shè)計,電子萬年歷_第2頁
單片機課程設(shè)計,電子萬年歷_第3頁
單片機課程設(shè)計,電子萬年歷_第4頁
單片機課程設(shè)計,電子萬年歷_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

/本科課程設(shè)計課程名稱:單片機原理與接口技術(shù)課設(shè)項目:電子萬年歷課程設(shè)計課設(shè)地點:專業(yè)班級:學號學生姓名:同組人:指導教師:20XX05月30日設(shè)計題目:電子萬年歷設(shè)計任務(wù)與要求:1、顯示年月日時分秒及星期信息2、具有可調(diào)整日期和時間功能3、增加閏年計算功能4、增加了顯示溫度的模塊設(shè)計方案:由于我是在網(wǎng)上購買的現(xiàn)成的開發(fā)板來學習和使用的,故在方案的選擇上也只能限于開發(fā)板設(shè)計好的電路和芯片.系統(tǒng)分為主控模塊、時鐘電路模塊、溫度檢測模塊,按鍵掃描模塊.LCD顯示模塊.電源電路、復位電路、晶振電路等模塊。主控模塊采用AT89C52單片機.按鍵模塊用四個按鍵.用于調(diào)整時間.顯示模塊采用LCD1602.時鐘電路模塊采用DS1302時鐘芯片實現(xiàn)對時間、日期的操作,溫度模塊使用18B20實現(xiàn)度溫度的操作。STC89C52.ATMEL的51系列單片機.價格便宜.在國內(nèi)使用者非常多。支持串口下載.使用非常方便.且具有很大的價格優(yōu)勢。缺點是僅支持串口下載.不支持在線下載.使用中會有些不方便。1.顯示模塊:方案一:普通的共陰LED數(shù)碼管,用點陣LED實現(xiàn)文字的顯示.方案二:LCD1602液晶顯示屏.LED數(shù)碼管價格適中.對于數(shù)字顯示效果較好.而且使用單片機的端口也較少;LCD1602液晶顯示屏.顯示功能強大.可以顯示大量文字、圖形.顯示多樣性.清晰可見.價格相對LED數(shù)碼管來說要昂貴些.但是基于本設(shè)計顯示的東西較多.若采用LED數(shù)碼管的話.所需數(shù)碼管較多.而且不利于控制.因此選擇LCD1602作為顯示模塊.故選擇方案二.2.時鐘電路模塊:方案一:用單片機的定時器產(chǎn)生1S的時基信號.然后用程序來實現(xiàn)時鐘的時、分、秒計時.同時用程序來產(chǎn)生年、月、日。該方案優(yōu)點是減少使用外設(shè)芯片;缺點是用單片機模擬時鐘.使編程量增大.且用定時器產(chǎn)生時基信號.精度不高。方案二:DS1302是一款高性能的實時時鐘芯片.以計時準確、接口簡單、使用方便、工作電壓范圍寬和低功耗等優(yōu)點.得到廣泛的應(yīng)用.實時時鐘有秒、分、時、星期、日、月和年.月小于31天時可以自動調(diào)整.并具有閏年補償功能.而且在掉電時能夠在外部紐扣電池的供電下繼續(xù)工作。單片機有定時器的功能.但時間誤差較大.且需要編寫時鐘程序.因此采用DS1302方案二作為時鐘電路。3.溫度模塊:直接采用常用的18B20.系統(tǒng)框圖:液晶顯示〔LED1602單片AT89C52時鐘芯片DS1302溫度傳感器18B20單元電路設(shè)計:單片機中央處理系統(tǒng)的方案設(shè)計.選用AT89C52單片機作為中央處理器.如圖所示。該單片機除了擁有MCS-51系列單片機的所有優(yōu)點外.內(nèi)部還具有8K的在系統(tǒng)可編程FLASH存儲器.低功耗的空閑和掉電模式.極大的降低了電路的功耗.還包含了定時器、程序存儲器、數(shù)據(jù)存儲器等硬件.其硬件能符合整個控制系統(tǒng)的要求.不需要外接其他存儲器芯片和定時器件.方便地構(gòu)成一個最小系統(tǒng)。整個系統(tǒng)結(jié)構(gòu)緊湊.抗干擾能力強.性價比高。2、時鐘振蕩電路用主振11.0592 MHZ的晶振,使用內(nèi)部晶振接法并上倆個30PF的電容,如圖所示.3、復位電路復位電路由電阻和極性電容組成.通過高電平使單片機復位.在時鐘電路開始工作后.當高電平的時間超過大約2us時.即可實現(xiàn)復位。此復位電路為上電復位.較為簡單。若改進可以添加手動復位的功能.上電復位發(fā)生在開機加電時.由系統(tǒng)自動完成.手動復位通過一個按鍵來實現(xiàn).在程序運行時.若遇到死機.死循環(huán)等情況.通過手動復位就可以實現(xiàn)重新啟動的操作。手動按鈕復位需要人為在復位輸入端RST上加入高電平。一般采用的辦法是在RST端和正電源Vcc之間接一個按鈕和一個電阻。4、DS1302時鐘電路時鐘電路主要由時鐘芯片DS1302、備用電池、晶振等幾部分組成.如圖<6>所示。DS1302采用3線串行接口.占用引腳少.內(nèi)部集成了可編程日歷時鐘.用戶可以根據(jù)需要通過單片機的控制來自行設(shè)置.支持雙電源供電.可以使用外部主電源和備用電源.備份電源能夠使時鐘芯片繼續(xù)工作。DS1302管腳圖DS1302時鐘電路DS1302各引腳的功能為:8:Vcc1:備用電池端;1:Vcc2:5V電源。當Vcc2>Vcc1+0.2V時.由Vcc2向DS1302供電.當Vcc2<Vcc1時.由Vcc1向DS1302供電;7:SCLK:串行時鐘.輸入;6:I/O:數(shù)據(jù)輸入輸出口;5:CE/RST:復位腳;2、3:X1、X2是外接晶振腳〔32.768KHZ的晶振;4:地〔GND。DS1302有關(guān)日歷、時間的寄存器:DS1302有關(guān)日歷、時間的寄存器1、秒寄存器〔81h、80h的位7定義為時鐘暫停標志〔CH。當初始上電時該位置為1.時鐘振蕩器停止.DS1302處于低功耗狀態(tài);只有將秒寄器的該位置改寫為0時.時鐘才能開始運行。2、小時寄存器〔85h、84h的位7用于定義DS1302是運行于12小時模式還是24小時模式。當為高時.選擇12小時模式。在12小時模式時.位5是.當為1時.表示PM。在24小時模式時.位5是第二個10小時位3、控制寄存器〔8Fh、8Eh的位7是寫保護位〔WP.其它7位均置為0。在對任何的時鐘和RAM的寫操作之前.WP位必須為0。當WP位為1時.寫保護位防止對任一寄存器的寫操作。也就是說在電路上電的初始態(tài)WP是1.這時是不能改寫上面任何一個時間寄存器的.只有首先將WP改寫為0.才能進行其它寄存器的寫操作。DS1302讀寫時序DS1302是SPI總線驅(qū)動方式。它不僅要向寄存器寫入控制字.還需要讀取相應(yīng)寄存器的數(shù)據(jù)。DS1302的控制字如下圖:DS1302的控制字圖控制字的最高有效位〔位7必須是邏輯1.如果它為0.則不能把數(shù)據(jù)寫入到DS1302中。位6:如果為0.則表示存取日歷時鐘數(shù)據(jù).為1表示存取RAM數(shù)據(jù);位5至位1〔A4~A0:指示操作單元的地址;位0〔最低有效位:如為0.表示要進行寫操作.為1表示進行讀操作。讀數(shù)據(jù):讀數(shù)據(jù)時在緊跟8位的控制字指令后的下一個SCLK脈沖的下降沿.讀出DS1302的數(shù)據(jù).讀出的數(shù)據(jù)是從最低位到最高位。寫數(shù)據(jù):控制字總是從最低位開始輸出。在控制字指令輸入后的下一個SCLK時鐘的上升沿時.數(shù)據(jù)被寫入DS1302.數(shù)據(jù)輸入也是從最低位〔0位開始。5:溫度傳感器18B20通過18B20進行讀數(shù)據(jù).將讀出來的數(shù)據(jù)進行進制轉(zhuǎn)換.轉(zhuǎn)換后送到DS18B20是單總線的數(shù)字溫度傳感器。其與單片機的接口只需要一根數(shù)據(jù)線即可。當然連線簡單意味著軟件處理上可能要麻煩一點。下面來看看它的優(yōu)點看看它的靚照。外形和我們常用的三極管沒有什么兩樣哦。DS18B20的內(nèi)部存儲器分為以下幾部分ROM:存放該器件的編碼。前8位為單線系列的編碼<DS18B20的編碼是19H>后面48位為芯片的唯一序列號。在出場的時候就已經(jīng)設(shè)置好.用戶無法更改。最后8位是以上56位的CRC碼。DS18B20的溫度存放如上圖所示。其中S位符號位。當溫度值為負值時.S=1.反之則S=0。我們把得到的溫度數(shù)據(jù)乘上對應(yīng)的分辨率即可以得到轉(zhuǎn)換后的溫度值。DS18B20的通訊協(xié)議:在對DS18B20進行讀寫編程時.必須嚴格保證讀寫的時序。否則將無法讀取測溫結(jié)果。根據(jù)DS18B20的通訊協(xié)議.主機控制DS18B20完成溫度轉(zhuǎn)換必須經(jīng)過3個步驟:每一次讀寫之前都要對DS18B20進行復位.復位成功后發(fā)送一條ROM指令.最后發(fā)送RAM指令。這樣才能對DS18B20進行預(yù)定的操作。復位要求主機將數(shù)據(jù)線下拉500us.然后釋放.DS18B20收到信號后等待16~160us然后發(fā)出60~240us的存在低脈沖.主機收到此信號表示復位成功。上圖即DS18B20的復位時序圖。下面是讀操作的時序圖這是寫操作的時序圖6.按鍵電路按鍵電路由四個輕觸開關(guān)組成。按鍵用來調(diào)整時間.其一端直接接到單片機的端口.另一端接地.當按下按鍵時.相應(yīng)的端口變?yōu)榈碗娖?通過一個與門只要這四個按鍵有一個按下就會在P3.2檢測到一低電平就觸發(fā)外部中斷0進入按鍵調(diào)節(jié)程序中.通過與個各鍵相連的端口P3.4_P3.7可以判斷是哪個鍵按下.從而作相應(yīng)的操作。用軟件設(shè)計掃描程序。7.實現(xiàn)功能:K1按鍵進入設(shè)定狀態(tài)按K2,依次進入鬧鐘功能是否啟用.鬧鐘時,分秒,年,月,日及時間時,分,秒的設(shè)置,直到退出設(shè)置狀態(tài)按K3,調(diào)整是否起用鬧鐘和調(diào)節(jié)鬧鐘時,分,秒,年,月,日,時間的時,分,秒的數(shù)字LCD第二排中間顯示小喇叭.表示啟用鬧鐘功能.無則禁止鬧鐘功能〔可在調(diào)整狀態(tài)進行設(shè)置正常狀態(tài),LCD上排最前面顯示自定義字符,LCD下排最前面閃動"RICHMCU"設(shè)置狀態(tài),LCD上排最前面顯示"P",下排最前面在設(shè)置鬧鐘時間時顯示"alarm:",其它狀態(tài)顯示"time"8.程序流程圖:1主程序:首先初始化定時器、LCD1602及DS1302.然后就開始查詢按鍵.有鍵按下則開始調(diào)整時間和日期.若沒有按下.則執(zhí)行下面的時間、日期的顯示.最后依次循環(huán)這些相同的操作:18b20子程序:復位初始化向1820寫數(shù)據(jù),跳過rom,讀數(shù)據(jù)提取百、十、個、小數(shù)點后一位復位初始化向1820寫數(shù)據(jù),跳過rom,讀數(shù)據(jù)提取百、十、個、小數(shù)點后一位讀到的數(shù)轉(zhuǎn)換為整型Ds1302子程序:初始化Flag=1?Dnum=?1:小時加一2:分加一3:秒加一4:年加一5:月加一6:日加一7:星期加一1:初始化Flag=1?Dnum=?1:小時加一2:分加一3:秒加一4:年加一5:月加一6:日加一7:星期加一1:小時減一2:分減一3:秒減一4:年減一5:月減一6:日減一7:星期減一計算要顯示的數(shù)據(jù)送到1602顯示Dnum=?2、軟件設(shè)計軟件總設(shè)計:主程序首先對系統(tǒng)環(huán)境初始化.設(shè)置定時器T0工作模式為16位定時/計數(shù)器模式.置位總中斷允許位EA.并對鍵盤端口置位.再對LCD1602初始化.DS1302初始化。接著掃描鍵盤.在鍵盤程序里面是對時間、日期,鬧鐘的調(diào)整.溫度的選擇,最下面是時間的顯示。例如:閏年的計算bitleap_year<>{ bitleap; if<<year%4==0&&year%100!=0>||year%400==0>//閏年的條件 leap=1; else leap=0; returnleap;}仿真結(jié)果分析:電子萬年歷硬件電路圖及仿真如圖所示.系統(tǒng)由AT89C52單片機.按鍵掃描電路、顯示電路、時鐘電路、晶振電路、復位電路及電源指示電路。仿真正確顯示了時間.在LCD1602中正確顯示了當前日期、時間.按K1按鍵進入設(shè)定狀態(tài),按K2,依次進入鬧鐘功能是否啟用.鬧鐘時,分秒,年,月,日及時間時,分,秒的設(shè)置,直到退出設(shè)置狀態(tài),按K3,調(diào)整是否起用鬧鐘和調(diào)節(jié)鬧鐘時,分,秒,年,月,日,時間的時,分,秒的數(shù)字,按K4,選擇溫度的顯示.LCD第二排中間顯示小喇叭.表示啟用鬧鐘功能.無則禁止鬧鐘功能〔可在調(diào)整狀態(tài)進行設(shè)置,正常狀態(tài),LCD上排最前面顯示自定義字符,LCD下排最前面閃動"TIME",設(shè)置狀態(tài),LCD上排最前面顯示"P",下排最前面在設(shè)置鬧鐘時間時顯示"alarm:",其它狀態(tài)顯示"time"仿真正確顯示了時間和日期.符合設(shè)計的要求。增加溫度的顯示按下K4時出現(xiàn)溫度的顯示界面,上排顯示"wendumadebyFMZ",下排顯示溫度.仿真圖如下所示:參考文獻:單片機原理與接口技術(shù)<李曉林.第二版>RZ-51V20開發(fā)板論壇實物圖:鬧鐘設(shè)置時間顯示平閏年判斷,修改天數(shù)溫度顯示整體實物圖實驗源程序:#include<reg51.h>#include<intrins.h>#include<string.h>unsignedcharcodedigit[11]={"0123456789-"};//定義字符數(shù)組顯示數(shù)字unsignedcharcodeStr[]={"wendumadebyFMZ"};//說明顯示的是溫度unsignedcharcodeError[]={"DS18B20ERROR"};//說明沒有檢測到DS18B20unsignedcharcodeError1[]={"PLEASECHECK"};//說明沒有檢測到DS18B20unsignedcharcodeTemp[]={"wendumadebyFMZ:"};unsignedcharcodeCent[]={"Cent"};//溫度單位unsignedcharflag,tltemp;unsignedcharcodedis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};unsignedcharcodepara_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5}; //星期月參變數(shù)unsignedchardatadis_buf1[16]; //lcd上排顯示緩沖區(qū)unsignedchardatadis_buf2[16]; //lcd下排顯示緩沖區(qū)unsignedchardatayear,month,date,week;//年、月、日、星期unsignedchardataarmhour,armmin,armsec;//鬧鐘時、分、秒unsignedchardatahour,min,sec,sec100; //時、分、秒、百分之一秒unsignedchardataflag,vkey,skey;//設(shè)置狀態(tài)計數(shù)標志、按鍵先前值、按鍵當前值bit alarm; //標識是否啟用鬧鐘.1--啟用.0--關(guān)閉sbit rs=P2^0; //LCD數(shù)據(jù)/命令選擇端<H/L>sbit rw=P2^1; //LCD讀/寫選擇端<H/L>sbit ep=P2^2; //LCD使能控制sbit PRE=P3^3; //調(diào)整鍵<AN3>sbit SET=P3^4; //調(diào)整鍵<AN4>sbit SPK=P3^6;voiddelayms<unsignedcharms>; //延時程序bitlcd_busy<>; //測試LCD忙碌狀態(tài)程序voidlcd_wcmd<charcmd>; //寫入指令到LCD程序voidlcd_wdat<chardat>; //寫入數(shù)據(jù)到LCD程序voidlcd_pos<charpos>; //LCD數(shù)據(jù)指針位置程序voidlcd_init<>; //LCD初始化設(shè)定程序voidpro_timedate<>; //時間日期處理程序voidpro_display<>; //顯示處理程序voidpro_key<>; //按鍵處理程序voidtime_alarm<>; //定時報警功能<鬧鐘>unsignedcharscan_key<>; //按鍵掃描程序unsignedcharweek_proc<>; //星期自動計算與顯示函數(shù)bitleap_year<>; //判斷是否為閏年voidlcd_sef_chr<>; //LCD自定義字符程序voidupdate_disbuf<unsignedchart1,unsignedchart2[],unsignedchardis_h,unsignedchardis_m,unsignedchardis_s>;//延時程序voiddelay<unsignedcharms>{ while<ms--> { unsignedchari; for<i=0;i<250;i++> { _nop_<>; //執(zhí)行一條_nop_<>指令為一個機器周期 _nop_<>; _nop_<>; _nop_<>; } }}voiddelay1ms<>{unsignedchari,j; for<i=0;i<4;i++> for<j=0;j<33;j++>}//n毫秒voiddelaynms<unsignedcharn>{unsignedchari; for<i=0;i<n;i++> delay1ms<>;}//測試LCD忙碌狀態(tài)bitlcd_busy<>{ bitresult; rs=0; rw=1; ep=1; _nop_<>; _nop_<>; _nop_<>; _nop_<>; result=<bit><P0&0x80>; //LCD的D0--D7中,D7=1為忙碌,D7=0為空閑 ep=0; returnresult;}//寫入指令到LCDvoidlcd_wcmd<charcmd>{ while<lcd_busy<>>; //當lcd_busy為1時,再次檢測LCD忙碌狀態(tài),lcd-busy為0時,開始寫指令 rs=0; rw=0; ep=0; _nop_<>; _nop_<>; P0=cmd; _nop_<>; _nop_<>; _nop_<>; _nop_<>; ep=1; _nop_<>; _nop_<>; _nop_<>; _nop_<>; ep=0;}//寫入數(shù)據(jù)到LCDvoidlcd_wdat<chardat>{ while<lcd_busy<>>; rs=1; rw=0; ep=0; P0=dat; _nop_<>; _nop_<>; _nop_<>; _nop_<>; ep=1; _nop_<>; _nop_<>; _nop_<>; _nop_<>; ep=0;}//LCD數(shù)據(jù)指針位置程序voidlcd_pos<charpos>{ lcd_wcmd<pos|0x80>; //數(shù)據(jù)指針=80+地址碼<00H~27H,40H~67H>}voidlcd_sef_chr<>{ //第一個自定義字符 lcd_wcmd<0x40>; //"01000000"第1行地址<D7D6為地址設(shè)定命令形式D5D4D3為字符存放位置<0--7>.D2D1D0為字符行地址<0--7> lcd_wdat<0x1f>; //"XXX11111" 第1行數(shù)據(jù)〔D7D6D5為XXX.表示為任意數(shù)<一般用000.D4D3D2D1D0為字符行數(shù)據(jù)<1-點亮.0-熄滅 lcd_wcmd<0x41>; //"01000001" 第2行地址 lcd_wdat<0x11>; //"XXX10001" 第2行數(shù)據(jù) lcd_wcmd<0x42>; //"01000010" 第3行地址 lcd_wdat<0x15>; //"XXX10101" 第3行數(shù)據(jù) lcd_wcmd<0x43>; //"01000011" 第4行地址 lcd_wdat<0x11>; //"XXX10001" 第4行數(shù)據(jù) lcd_wcmd<0x44>; //"01000100" 第5行地址 lcd_wdat<0x1f>; //"XXX11111" 第5行數(shù)據(jù) lcd_wcmd<0x45>; //"01000101" 第6行地址 lcd_wdat<0x0a>; //"XXX01010" 第6行數(shù)據(jù) lcd_wcmd<0x46>; //"01000110" 第7行地址 lcd_wdat<0x1f>; //"XXX11111" 第7行數(shù)據(jù) lcd_wcmd<0x47>; //"01000111" 第8行地址 lcd_wdat<0x00>; //"XXX00000" 第8行數(shù)據(jù) //第二個自定義字符 lcd_wcmd<0x48>; //"01001000"第1行地址 lcd_wdat<0x01>; //"XXX00001" 第1行數(shù)據(jù) lcd_wcmd<0x49>; //"01001001" 第2行地址 lcd_wdat<0x1b>; //"XXX11011" 第2行數(shù)據(jù) lcd_wcmd<0x4a>; //"01001010" 第3行地址 lcd_wdat<0x1d>; //"XXX11101" 第3行數(shù)據(jù) lcd_wcmd<0x4b>; //"01001011" 第4行地址 lcd_wdat<0x19>; //"XXX11001" 第4行數(shù)據(jù) lcd_wcmd<0x4c>; //"01001100" 第5行地址 lcd_wdat<0x1d>; //"XXX11101" 第5行數(shù)據(jù) lcd_wcmd<0x4d>; //"01001101" 第6行地址 lcd_wdat<0x1b>; //"XXX11011" 第6行數(shù)據(jù) lcd_wcmd<0x4e>; //"01001110" 第7行地址 lcd_wdat<0x01>; //"XXX00001" 第7行數(shù)據(jù) lcd_wcmd<0x4f>; //"01001111" 第8行地址 lcd_wdat<0x00>; //"XXX00000" 第8行數(shù)據(jù)}//LCD初始化設(shè)定voidlcd_init<>{ lcd_wcmd<0x38>; //設(shè)置LCD為16X2顯示,5X7點陣,八位數(shù)據(jù)借口 delay<1>; lcd_wcmd<0x0c>; //LCD開顯示及光標設(shè)置<光標不閃爍,不顯示"-"> delay<1>; lcd_wcmd<0x06>; //LCD顯示光標移動設(shè)置<光標地址指針加1,整屏顯示不移動> delay<1>; lcd_wcmd<0x01>; //清除LCD的顯示內(nèi)容 delay<1>;}//閏年的計算bitleap_year<>{ bitleap; if<<year%4==0&&year%100!=0>||year%400==0>//閏年的條件 leap=1; else leap=0; returnleap;}//星期的自動運算和處理unsignedcharweek_proc<>{ unsignedcharnum_leap; unsignedcharc; num_leap=year/4-year/100+year/400;//自00年起到y(tǒng)ear所經(jīng)歷的閏年數(shù) if<leap_year<>&&month<=2> //既是閏年且是1月和2月 c=5; else c=6; week=<year+para_month[month]+date+num_leap+c>%7;//計算對應(yīng)的星期 returnweek;}//更新顯示緩沖區(qū)voidupdate_disbuf<unsignedchart1,unsignedchart2[],unsignedchardis_h,unsignedchardis_m,unsignedchardis_s>{ dis_buf1[0]=t1; // dis_buf1[1]=0x20; //空格 dis_buf1[2]=50; //'2' dis_buf1[3]=48;//'0' dis_buf1[4]=year/10+48; dis_buf1[5]=year%10+48; dis_buf1[6]=0x2d; dis_buf1[7]=month/10+48; dis_buf1[8]=month%10+48; dis_buf1[9]=0x2d; //'-' dis_buf1[10]=date/10+48; dis_buf1[11]=date%10+48; dis_buf1[12]=0x20; dis_buf1[13]=dis_week[4*week]; dis_buf1[14]=dis_week[4*week+1]; dis_buf1[15]=dis_week[4*week+2]; dis_buf2[0]=t2[0]; dis_buf2[1]=t2[1]; dis_buf2[2]=t2[2]; dis_buf2[3]=t2[3]; dis_buf2[4]=t2[4]; dis_buf2[5]=t2[5]; dis_buf2[6]=t2[6]; //空格 if<alarm> dis_buf2[7]=0x01; //alarm=1.顯示鬧鐘啟用標致〔第二個自定義字符 else dis_buf2[7]=0x20; //alarm=0.不顯示鬧鐘啟用標致 dis_buf2[8]=dis_h/10+48; dis_buf2[9]=dis_h%10+48; dis_buf2[10]=0x3a; //':' dis_buf2[11]=dis_m/10+48; dis_buf2[12]=dis_m%10+48; dis_buf2[13]=0x3a; dis_buf2[14]=dis_s/10+48; dis_buf2[15]=dis_s%10+48;}//時間和日期處理程序voidpro_timedate<>{ sec++; if<sec>59> {sec=0; min++; if<min>59> {min=0; hour++; if<hour>23> {hour=0; date++; if<month==1||month==3||month==5||month==7||month==8||month==10||month==12> if<date>31>{date=1;month++;} //大月31天 if<month==4||month==6||month==9||month==11> if<date>30>{date=1;month++;} //小月30天 if<month==2> {if<leap_year<>> {if<date>29>{date=1;month++;}}else {if<date>28>{date=1;month++;}} } if<month>12>{month=1;year++;} if<year>99>year=0; } } } week_proc<>; if<sec==armsec&&min==armmin&&hour==armhour> {if<alarm> TR1=1; //鬧鐘啟用時.報警時間到,啟動Timer1 }}//顯示處理程序voidpro_display<>{ unsignedchari; lcd_pos<0x00>; for<i=0;i<=15;i++> {lcd_wdat<dis_buf1[i]>;} lcd_pos<0x40>; for<i=0;i<=15;i++> {lcd_wdat<dis_buf2[i]>;}}//Timer0中斷處理程序,秒的產(chǎn)生voidtimer0<>interrupt1{ TH0=0xD8; TL0=0xF0; sec100++; if<sec100>=100> //1秒時間<100*10ms=1000ms=1s> {sec100=0; pro_timedate<>;//調(diào)用時間和日期處理程序 } if<sec&0x01> update_disbuf<0x00,"",hour,min,sec>; elseupdate_disbuf<0x00,"FMZTIME",hour,min,sec>;pro_display<>;//調(diào)用顯示處理函數(shù)}//按鍵掃描程序unsignedcharscan_key<>{ skey=0x00; //給變量vkey置初值 skey|=PRE; //讀取PRE鍵的狀態(tài) skey=skey<<1; //將PRE鍵的狀態(tài)存于skey的B1位 skey|=SET; //讀取SET鍵的狀態(tài),并存于skey的B0位 returnskey; //返回skey的鍵值<即PRE,SET的狀態(tài)>}//外部中斷INT0中斷處理程序voidint0<>interrupt0{ TR0=0; //禁止Timer0 IE=0; //禁止中斷 lcd_wcmd<0x0e>; //顯示光標"_",整個光標不閃爍 alarm=1; update_disbuf<0x50,"alarm:",armhour,armmin,armsec>; pro_display<>; //調(diào)用顯示處理程序 lcd_pos<0x47>; //使光標位于第一個調(diào)整項下 flag=0; vkey=0x03; while<flag^0x0a> {skey=scan_key<>; //掃描按鍵狀態(tài) if<skey^vkey> //若skey與vkey相同,跳出循環(huán),相異執(zhí)行循環(huán)體 { delay<10>; //去按鍵抖動 skey=scan_key<>; //轉(zhuǎn)回掃描按鍵狀態(tài) if<skey^vkey> //若skey與vkey相同,跳出循環(huán),相異執(zhí)行循環(huán)體 { vkey=skey; //將skey的值付給vkey if<skey==0x01> //PRE鍵按下 { flag++; //調(diào)整標志位加1 switch<flag> //將光標置于相應(yīng)調(diào)整位置 { case1:lcd_pos<0x49>;break; // case2: lcd_pos<0x4c>;break; case3: lcd_pos<0x4f>;break; case4: update_disbuf<0x50,"time:",hour,min,sec>; pro_display<>; lcd_pos<0x05>;break; case5: lcd_pos<0x08>;break; case6: lcd_pos<0x0b>;break; case7:lcd_pos<0x49>;break; // case8: lcd_pos<0x4c>;break; case9: lcd_pos<0x4f>;break; default:break; } } if<skey==0x02> //SET鍵按下 { pro_key<>; //轉(zhuǎn)設(shè)置按鍵處理程序 }if<skey==0x03>{ wendu<>} } } } lcd_wcmd<0x0c>; lcd_wcmd<0x01>; //清除LCD的顯示內(nèi)容 IE=0x8f; //CPU開中斷,INT0,INT1,開中斷 TR0=1; //Timer0啟動}//DS18B20的操作程序sbitDQ=P3^3;unsignedchartime;//設(shè)置全局變量.專門用于嚴格延時//函數(shù)功能:將DS18B20傳感器初始化.讀取應(yīng)答信號//出口參數(shù):flagbitInit_DS18B20<void>{bitflag;DQ=1;for<time=0;time<2;time++>;DQ=0;for<time=0;time<200;time++>;DQ=1;//釋放數(shù)據(jù)線〔將數(shù)據(jù)線拉高for<time=0;time<10;time++>;//延時約30us〔釋放總線后需等待15~60us讓DS18B20輸出存在脈沖flag=DQ;//讓單片機檢測是否輸出了存在脈沖〔DQ=0表示存在for<time=0;time<200;time++>//延時足夠長時間.等待存在脈沖輸出完畢;return<flag>;//返回檢測成功標志}////函數(shù)功能:從DS18B20讀取一個字節(jié)數(shù)據(jù)unsignedcharReadOneChar<void>{ unsignedchari=0; unsignedchardat;//儲存讀出的一個字節(jié)數(shù)據(jù) for<i=0;i<8;i++> { DQ=1;//先將數(shù)據(jù)線拉高 _nop_<>; //等待一個機器周期 DQ=0; _nop_<>;//等待一個機器周期 DQ=1;//將數(shù)據(jù)線"人為"拉高,為單片機檢測DS18B20的輸出電平作準備 for<time=0;time<2;time++>;//延時約6us.使主機在15us內(nèi)采樣 dat>>=1; if<DQ==1> dat|=0x80;//如果讀到的數(shù)據(jù)是1.則將1存入dat else dat|=0x00;//如果讀到的數(shù)據(jù)是0.則將0存入dat //將單片機檢測到的電平信號DQ存入r[i] for<time=0;time<8;time++> ;//延時3us,兩個讀時序之間必須有大于1us的恢復期 } return<dat>;//返回讀出的十六進制數(shù)據(jù)}//函數(shù)功能:向DS18B20寫入一個字節(jié)數(shù)據(jù)WriteOneChar<unsignedchardat>{ unsignedchari=0; for<i=0;i<8;i++> { DQ=1;//先將數(shù)據(jù)線拉高 _nop_<>; //等待一個機器周期 DQ=0;//將數(shù)據(jù)線從高拉低時即啟動寫時序 DQ=dat&0x01;//利用與運算取出要寫的某位二進制數(shù)據(jù),//并將其送到數(shù)據(jù)線上等待DS18B20采樣 for<time=0;time<10;time++> ;//延時約30us.DS18B20在拉低后的約15~60us期間從數(shù)據(jù)線上采樣 DQ=1;//釋放數(shù)據(jù)線 for<time=0;time<1;time++> ;//延時3us,兩個寫時序間至少需要1us的恢復期 dat>>=1;//將dat中的各二進制位數(shù)據(jù)右移1位 } for<time=0;time<4;time++> ;//稍作延時,給硬件一點反應(yīng)時間}//函數(shù)功能:做好讀溫度的準備voidReadyReadTemp<void>{Init_DS18B20<>;//將DS18B20初始化 WriteOneChar<0xCC>;//跳過讀序號列號的操作 WriteOneChar<0x44>;//啟動溫度轉(zhuǎn)換 delaynms<200>;//轉(zhuǎn)換一次需要延時一段時間 Init_DS18B20<>;//將DS18B20初始化 WriteOneChar<0xCC>;//跳過讀序號列號的操作 WriteOneChar<0xBE>;//讀取溫度寄存器,前兩個分別是溫度的低位和高位}//函數(shù)功能:讀溫度Read_Temperature<charxx,charyy>{unsignedchari,tl_temp;unsignedintx;unsignedcharct[8];union{bytec[2];intx;}temp;ow_reset<>;write_byte<0xCC>;//SkipROMwrite_byte<0x44>;//轉(zhuǎn)換溫度ow_reset<>;write_byte<0xCC>;//SkipROMwrite_byte<0xbe>;//讀取寄存器temp.c[1]=read_byte<>;//讀出溫度低8位temp.c[0]=read_byte<>;//讀出溫度高8位//零下溫度判斷sflag=0;//溫度零下標志0:零上.1:零下if<<temp.c[0]&0xf8>!=0x00>{sflag=1;//零下標志位置1temp.c[1]=~temp.c[1];//低8位取反temp.c[0]=~temp.c[0];//高8位取反tl_temp=temp.c[1]+1;//低8位加1temp.c[1]=tl_temp;//計算后重新存入數(shù)組if<tl_temp>255>temp.c[0]++;//如果低8位大于255.向高8位進1}x=<<temp.c[0]&0x07>*256+temp.c[1]>*.625;for<i=0;i<8;i++>{ct[i]=0;}i=0;while<x/10>{ct[i]=x%10;x=x/10;i++;}ct[i]=x;if<sflag==1>DisplayOneChar<xx-1,yy,0x2d>;elseDisplayOneChar<xx-1,yy,0x20>;DisplayOneChar<xx,yy,ct[2]+0x30>;//顯示溫度十位數(shù)DisplayOneChar<xx+1,yy,ct[1]+0x30>;//顯示溫度個位數(shù)DisplayOneChar<xx+2,yy,0x2e>;//顯示小數(shù)點DisplayOneChar<xx+3,yy,ct[0]+0x30>;//顯示溫度小數(shù)位DisplayOneChar<xx+4,yy,0x01>;//顯示自定義字符DisplayOneChar<xx+5,yy,0x43>;//顯示字符"C//主程序,初始化及初值設(shè)定voidmain<>{ lcd_init<>; //初始化LCD lcd_sef_chr<>; //寫入自定義字符號 hour=0;min=0;sec=0; //開機時的時,分,秒顯示 armhour=0;armmin=0;armsec=0; //開機時的時,分,秒報警初值 year=12;month=5;date=27; //開機時的年,月,日,星期顯示 week_proc<>; alarm=1; IE=0x8f; IP=0x04; //設(shè)置INT0為中斷最高優(yōu)先級 IT0=0;IT1=0; TMOD=0x11; TH0=0xdc;TL0=0x00; //Timer0置10ms定時初值 TH1=0xff;TL1=0x00; //Timer1置初值 TR0=1; //Timer0啟動 TR1=0; while<1>;}//設(shè)置按鍵處理程序voidpro_key<>{ switch<flag> { case0:alarm=!alarm; //啟用或關(guān)閉鬧鐘〔alarm=1:啟用,alarm=0:關(guān)閉> update_disbuf<0x50,"alarm:",armhour,armmin,armsec>;//更新顯示數(shù)據(jù) pro_display<>; //調(diào)用顯示處理 lcd_pos<0x47>;break; //光標回到原調(diào)整位置 case1:armho

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論