第48節(jié):利用DS1302做一個(gè)實(shí)時(shí)時(shí)鐘
DS1302有兩路獨(dú)立電源輸入,我們只要在其中一路電源上掛一個(gè)紐扣電池就可以實(shí)現(xiàn)掉電時(shí)鐘繼續(xù)跑的功能,紐扣電池作為備用電源必須比主電源的電壓低一點(diǎn)。DS1302還給我們預(yù)留了一片RAM區(qū),我們可以把一些數(shù)據(jù)存入到DS1302,只要DS1302的電池有電,那么它就相當(dāng)于一個(gè)EEPROM。這個(gè)RAM區(qū)有什么用呢?因?yàn)镽AM區(qū)的數(shù)據(jù)只要一掉電,所有的數(shù)據(jù)都會(huì)變成0x00或者0xff,也就是數(shù)據(jù)掉電會(huì)丟失,我們可以利用這個(gè)特點(diǎn),可以在里面存入標(biāo)志位數(shù)據(jù),一旦發(fā)現(xiàn)這個(gè)數(shù)據(jù)改變了,就知道時(shí)鐘的數(shù)據(jù)需要重新設(shè)置過(guò),或者說(shuō)明電池沒(méi)電了。
在移植DS1302驅(qū)動(dòng)程序中,有一個(gè)地方最容易出錯(cuò),就是DS1302芯片的數(shù)據(jù)線DIO。我們編程時(shí)要特別留意這個(gè)IO口什么時(shí)候作為數(shù)據(jù)輸入,什么時(shí)候作為數(shù)據(jù)輸出,以便及時(shí)更改方向寄存器。對(duì)于51單片機(jī),IO口在讀取數(shù)據(jù)之前,要先置1。
這一節(jié)要教會(huì)大家六個(gè)知識(shí)點(diǎn):
第一個(gè):DS1302做實(shí)時(shí)時(shí)鐘時(shí),修改時(shí)間和讀取時(shí)間的常見(jiàn)程序框架。
第二個(gè):如何編寫監(jiān)控備用電池電量耗盡的監(jiān)控程序。
第三個(gè):在往DS1302寫入數(shù)據(jù)修改時(shí)間之前,必須注意調(diào)整一下“日”的變量,因?yàn)槊總€(gè)月的最大天數(shù)是不一樣的,有的一個(gè)月28天,有的一個(gè)月29天,有的一個(gè)月30天,有的一個(gè)月31天。
第四個(gè):本程序第一次出現(xiàn)了電平按鍵,跟之前講的下降沿按鍵不一樣,請(qǐng)留意我是何如用軟件濾波的,以及它具體的實(shí)現(xiàn)代碼。
第五個(gè):本程序第一次出現(xiàn)了一個(gè)按鍵按下去后,如果不松手就會(huì)觸發(fā)兩次事件,第一次是短按,第二次是長(zhǎng)按3秒。請(qǐng)留意我是如何在之前的按鍵上略做修改就實(shí)現(xiàn)此功能的具體代碼。
第六個(gè):繼續(xù)加深了解按鍵與顯示是如何緊密關(guān)聯(lián)起來(lái)的程序框架。
具體內(nèi)容,請(qǐng)看源代碼講解。
(1) 硬件平臺(tái).
基于朱兆祺51單片機(jī)學(xué)習(xí)板。
舊版的朱兆祺51學(xué)習(xí)板在硬件上有一個(gè)bug,DS1302芯片附近的R43,R42兩個(gè)電阻應(yīng)該去掉,并且把R41的電阻換成0歐姆的電阻,或者直接短接起來(lái)。新版的朱兆祺51學(xué)習(xí)板已經(jīng)改過(guò)來(lái)了。
(2)實(shí)現(xiàn)功能:
本程序有2兩個(gè)窗口。
第1個(gè)窗口顯示日期。顯示格式“年-月-日”。注意中間有“-”分開(kāi)。
第2個(gè)窗口顯示時(shí)間。顯示格式“時(shí) 分 秒”。注意中間沒(méi)“-”,只有空格分開(kāi)。
系統(tǒng)上電后,默認(rèn)顯示第2個(gè)窗口,實(shí)時(shí)顯示動(dòng)態(tài)的“時(shí) 分 秒”時(shí)間。此時(shí)按下S13按鍵不松手就會(huì)切換到顯示日期的第1個(gè)窗口。松手后自動(dòng)切換回第2個(gè)顯示動(dòng)態(tài)時(shí)間的窗口。
需要更改時(shí)間的時(shí)候,長(zhǎng)按S9按鍵不松手超過(guò)3秒后,系統(tǒng)將進(jìn)入修改時(shí)間的狀態(tài),切換到第1個(gè)日期窗口,并且顯示“年”的兩位數(shù)碼管會(huì)閃爍,此時(shí)可以按S1或者S5加減按鍵修改年的參數(shù),修改完年后,繼續(xù)短按S9按鍵,會(huì)切換到“月”的參數(shù)閃爍狀態(tài),只要依次不斷按下S9按鍵,就會(huì)依次切換年,月,日,時(shí),分,秒的參數(shù)閃爍狀態(tài),最后修改完秒的參數(shù)后,系統(tǒng)會(huì)自動(dòng)把我們修改設(shè)置的日期時(shí)間一次性寫入DS1302芯片內(nèi)部,達(dá)到修改日期時(shí)間的目的。
S13是電平變化按鍵,用來(lái)切換窗口的,專門用來(lái)查看當(dāng)前日期。按下S13按鍵時(shí)顯示日期窗口,松手后返回到顯示實(shí)時(shí)時(shí)間的窗口。
本程序在使用過(guò)程中的注意事項(xiàng):
(a)第一次上電時(shí),蜂鳴器會(huì)報(bào)警,只要DS1302芯片的備用電池電量充足,這個(gè)時(shí)候斷電再重啟一次,就不會(huì)報(bào)警了。
(b)第一次上電時(shí),時(shí)間沒(méi)有走動(dòng),需要重新設(shè)置一下日期時(shí)間才可以。長(zhǎng)按S9按鍵可以進(jìn)入修改日期時(shí)間的狀態(tài)。
(3)源代碼講解如下:
- #include "REG52.H"
- #define const_dpy_time_half200//數(shù)碼管閃爍時(shí)間的半值
- #define const_dpy_time_all 400//數(shù)碼管閃爍時(shí)間的全值 一定要比const_dpy_time_half 大
- #define const_voice_short40 //蜂鳴器短叫的持續(xù)時(shí)間
- #define const_key_time120 //按鍵去抖動(dòng)延時(shí)的時(shí)間
- #define const_key_time220 //按鍵去抖動(dòng)延時(shí)的時(shí)間
- #define const_key_time320 //按鍵去抖動(dòng)延時(shí)的時(shí)間
- #define const_key_time420 //按鍵去抖動(dòng)延時(shí)的時(shí)間
- #define const_key_time171200//長(zhǎng)按超過(guò)3秒的時(shí)間
- #define const_ds1302_0_5s200 //大概0.5秒的時(shí)間
- #define const_ds1302_sampling_time 360 //累計(jì)主循環(huán)次數(shù)的時(shí)間,每次刷新采樣時(shí)鐘芯片的時(shí)間
- #define WRITE_SECOND 0x80 //DS1302內(nèi)部的相關(guān)地址
- #define WRITE_MINUTE 0x82
- #define WRITE_HOUR 0x84
- #define WRITE_DATE 0x86
- #define WRITE_MONTH 0x88
- #define WRITE_YEAR 0x8C
- #define WRITE_CHECK 0xC2//用來(lái)檢查芯片的備用電池是否用完了的地址
- #define READ_CHECK 0xC3//用來(lái)檢查芯片的備用電池是否用完了的地址
- #define READ_SECOND 0x81
- #define READ_MINUTE 0x83
- #define READ_HOUR 0x85
- #define READ_DATE 0x87
- #define READ_MONTH 0x89
- #define READ_YEAR 0x8D
- #define WRITE_PROTECT 0x8E
- void initial_myself(void);
- void initial_peripheral(void);
- void delay_short(unsigned int uiDelayShort);
- void delay_long(unsigned int uiDelaylong);
- //驅(qū)動(dòng)數(shù)碼管的74HC595
- void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01);
- void display_drive(void); //顯示數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
- void display_service(void); //顯示的窗口菜單服務(wù)程序
- //驅(qū)動(dòng)LED的74HC595
- void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01);
- void T0_time(void);//定時(shí)中斷函數(shù)
- void key_service(void); //按鍵服務(wù)的應(yīng)用程序
- void key_scan(void);//按鍵掃描函數(shù) 放在定時(shí)中斷里
- void ds1302_alarm_service(void); //ds1302出錯(cuò)報(bào)警
- void ds1302_sampling(void); //ds1302采樣程序,內(nèi)部每秒鐘采集更新一次
- void Write1302 ( unsigned char addr, unsigned char dat );//修改時(shí)間的驅(qū)動(dòng)
- unsigned char Read1302 ( unsigned char addr );//讀取時(shí)間的驅(qū)動(dòng)
- unsigned char bcd_to_number(unsigned char ucBcdTemp);//BCD轉(zhuǎn)原始數(shù)值
- unsigned char number_to_bcd(unsigned char ucNumberTemp); //原始數(shù)值轉(zhuǎn)BCD
- //日調(diào)整 每個(gè)月份的日最大取值不同,有的最大28日,有的最大29日,有的最大30,有的最大31
- unsigned char date_adjust(unsigned char ucYearTemp,unsigned char ucMonthTemp,unsigned char ucDateTemp); //日調(diào)整
- sbit SCLK_dr =P1^3;
- sbit DIO_dr_sr =P1^4;
- sbit DS1302_CE_dr =P1^5;
- sbit key_sr1=P0^0; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
- sbit key_sr2=P0^1; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
- sbit key_sr3=P0^2; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
- sbit key_sr4=P0^3; //對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
- sbit key_gnd_dr=P0^4; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
- sbit beep_dr=P2^7; //蜂鳴器的驅(qū)動(dòng)IO口
- sbit eeprom_scl_dr=P3^7; //時(shí)鐘線
- sbit eeprom_sda_dr_sr=P3^6; //數(shù)據(jù)的輸出線和輸入線
- sbit dig_hc595_sh_dr=P2^0; //數(shù)碼管的74HC595程序
- sbit dig_hc595_st_dr=P2^1;
- sbit dig_hc595_ds_dr=P2^2;
- sbit hc595_sh_dr=P2^3; //LED燈的74HC595程序
- sbit hc595_st_dr=P2^4;
- sbit hc595_ds_dr=P2^5;
- unsigned int uiSampingCnt=0; //采集Ds1302的計(jì)時(shí)器,每秒鐘更新采集一次
- unsigned char ucKeySec=0; //被觸發(fā)的按鍵編號(hào)
- unsigned intuiKeyTimeCnt1=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
- unsigned char ucKeyLock1=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
- unsigned intuiKeyTimeCnt2=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
- unsigned char ucKeyLock2=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
- unsigned intuiKeyTimeCnt3=0; //按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器
- unsigned char ucKeyLock3=0; //按鍵觸發(fā)后自鎖的變量標(biāo)志
- unsigned int uiKey4Cnt1=0;//在軟件濾波中,用到的變量
- unsigned int uiKey4Cnt2=0;
- unsigned char ucKey4Sr=1;//實(shí)時(shí)反映按鍵的電平狀態(tài)
- unsigned char ucKey4SrRecord=0; //記錄上一次按鍵的電平狀態(tài)
- unsigned intuiVoiceCnt=0;//蜂鳴器鳴叫的持續(xù)時(shí)間計(jì)數(shù)器
- unsigned charucVoiceLock=0;//蜂鳴器鳴叫的原子鎖
- unsigned char ucDigShow8;//第8位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigShow7;//第7位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigShow6;//第6位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigShow5;//第5位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigShow4;//第4位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigShow3;//第3位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigShow2;//第2位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigShow1;//第1位數(shù)碼管要顯示的內(nèi)容
- unsigned char ucDigDot8;//數(shù)碼管8的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigDot7;//數(shù)碼管7的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigDot6;//數(shù)碼管6的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigDot5;//數(shù)碼管5的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigDot4;//數(shù)碼管4的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigDot3;//數(shù)碼管3的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigDot2;//數(shù)碼管2的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigDot1;//數(shù)碼管1的小數(shù)點(diǎn)是否顯示的標(biāo)志
- unsigned char ucDigShowTemp=0; //臨時(shí)中間變量
- unsigned char ucDisplayDriveStep=1;//動(dòng)態(tài)掃描數(shù)碼管的步驟變量
- unsigned char ucWd=2;//本程序的核心變量,窗口顯示變量。類似于一級(jí)菜單的變量。代表顯示不同的窗口。
- unsigned char ucPart=0;//本程序的核心變量,局部顯示變量。類似于二級(jí)菜單的變量。代表顯示不同的局部。
- unsigned char ucWd1Update=0; //窗口1更新顯示標(biāo)志
- unsigned char ucWd2Update=1; //窗口2更新顯示標(biāo)志
- unsigned char ucWd1Part1Update=0;//在窗口1中,局部1的更新顯示標(biāo)志
- unsigned char ucWd1Part2Update=0; //在窗口1中,局部2的更新顯示標(biāo)志
- unsigned char ucWd1Part3Update=0; //在窗口1中,局部3的更新顯示標(biāo)志
- unsigned char ucWd2Part1Update=0;//在窗口2中,局部1的更新顯示標(biāo)志
- unsigned char ucWd2Part2Update=0; //在窗口2中,局部2的更新顯示標(biāo)志
- unsigned char ucWd2Part3Update=0; //在窗口2中,局部3的更新顯示標(biāo)志
- unsigned charucYear=0; //原始數(shù)據(jù)
- unsigned charucMonth=0;
- unsigned charucDate=0;
- unsigned charucHour=0;
- unsigned charucMinute=0;
- unsigned charucSecond=0;
- unsigned charucYearBCD=0; //BCD碼的數(shù)據(jù)
- unsigned charucMonthBCD=0;
- unsigned charucDateBCD=0;
- unsigned charucHourBCD=0;
- unsigned charucMinuteBCD=0;
- unsigned charucSecondBCD=0;
- unsigned char ucTemp1=0;//中間過(guò)渡變量
- unsigned char ucTemp2=0;//中間過(guò)渡變量
- unsigned char ucTemp4=0;//中間過(guò)渡變量
- unsigned char ucTemp5=0;//中間過(guò)渡變量
- unsigned char ucTemp7=0;//中間過(guò)渡變量
- unsigned char ucTemp8=0;//中間過(guò)渡變量
- unsigned char ucDelayTimerLock=0; //原子鎖
- unsigned intuiDelayTimer=0;
- unsigned char ucCheckDs1302=0;//檢查Ds1302芯片是否正常
- unsigned char ucDs1302Error=0; //Ds1302芯片的備用電池是否用完了的報(bào)警標(biāo)志
- unsigned char ucDs1302Lock=0;//原子鎖
- unsigned intuiDs1302Cnt=0; //間歇性蜂鳴器報(bào)警的計(jì)時(shí)器
- unsigned char ucDpyTimeLock=0; //原子鎖
- unsigned intuiDpyTimeCnt=0;//數(shù)碼管的閃爍計(jì)時(shí)器,放在定時(shí)中斷里不斷累加
- //根據(jù)原理圖得出的共陰數(shù)碼管字模表
- code unsigned char dig_table[]=
- {
- 0x3f,//0 序號(hào)0
- 0x06,//1 序號(hào)1
- 0x5b,//2 序號(hào)2
- 0x4f,//3 序號(hào)3
- 0x66,//4 序號(hào)4
- 0x6d,//5 序號(hào)5
- 0x7d,//6 序號(hào)6
- 0x07,//7 序號(hào)7
- 0x7f,//8 序號(hào)8
- 0x6f,//9 序號(hào)9
- 0x00,//無(wú) 序號(hào)10
- 0x40,//- 序號(hào)11
- 0x73,//P 序號(hào)12
- };
- void main()
- {
- initial_myself();
- delay_long(100);
- initial_peripheral();
- while(1)
- {
- key_service(); //按鍵服務(wù)的應(yīng)用程序
- ds1302_sampling(); //ds1302采樣程序,內(nèi)部每秒鐘采集更新一次
- display_service(); //顯示的窗口菜單服務(wù)程序
- ds1302_alarm_service(); //ds1302出錯(cuò)報(bào)警
- }
- }
- /* 注釋一:
- * 系統(tǒng)不用時(shí)時(shí)刻刻采集ds1302的內(nèi)部數(shù)據(jù),每隔一段時(shí)間更新采集一次就可以了。
- * 這個(gè)間隔時(shí)間應(yīng)該小于或者等于1秒鐘的時(shí)間,否則在數(shù)碼管上看不到每秒鐘的時(shí)間變化。
- */
- void ds1302_sampling(void) //ds1302采樣程序,內(nèi)部每秒鐘采集更新一次
- {
- if(ucPart==0)//當(dāng)系統(tǒng)不是處于設(shè)置日期和時(shí)間的情況下
- {
- ++uiSampingCnt;//累計(jì)主循環(huán)次數(shù)的時(shí)間
- if(uiSampingCnt>const_ds1302_sampling_time)//每隔一段時(shí)間就更新采集一次Ds1302數(shù)據(jù)
- {
- uiSampingCnt=0;
- ucYearBCD=Read1302(READ_YEAR); //讀取年
- ucMonthBCD=Read1302(READ_MONTH); //讀取月
- ucDateBCD=Read1302(READ_DATE); //讀取日
- ucHourBCD=Read1302(READ_HOUR); //讀取時(shí)
- ucMinuteBCD=Read1302(READ_MINUTE); //讀取分
- ucSecondBCD=Read1302(READ_SECOND); //讀取秒
- ucYear=bcd_to_number(ucYearBCD);//BCD轉(zhuǎn)原始數(shù)值
- ucMonth=bcd_to_number(ucMonthBCD);//BCD轉(zhuǎn)原始數(shù)值
- ucDate=bcd_to_number(ucDateBCD);//BCD轉(zhuǎn)原始數(shù)值
- ucHour=bcd_to_number(ucHourBCD);//BCD轉(zhuǎn)原始數(shù)值
- ucMinute=bcd_to_number(ucMinuteBCD);//BCD轉(zhuǎn)原始數(shù)值
- ucSecond=bcd_to_number(ucSecondBCD);//BCD轉(zhuǎn)原始數(shù)值
- ucWd2Update=1; //窗口2更新顯示時(shí)間
- }
- }
- }
- //修改ds1302時(shí)間的驅(qū)動(dòng) ,注意,此處寫入的是BCD碼,
- void Write1302 ( unsigned char addr, unsigned char dat )
- {
- unsigned char i,temp; //單片機(jī)驅(qū)動(dòng)DS1302屬于SPI通訊方式,根據(jù)我的經(jīng)驗(yàn),不用關(guān)閉中斷
- DS1302_CE_dr=0; //CE引腳為低,數(shù)據(jù)傳送中止
- delay_short(1);
- SCLK_dr=0; //清零時(shí)鐘總線
- delay_short(1);
- DS1302_CE_dr = 1; //CE引腳為高,邏輯控制有效
- delay_short(1);
- //發(fā)送地址
- for ( i=0; i<8; i++ ) //循環(huán)8次移位
- {
- DIO_dr_sr = 0;
- temp = addr;
- if(temp&0x01)
- {
- DIO_dr_sr =1;
- }
- else
- {
- DIO_dr_sr =0;
- }
- delay_short(1);
- addr >>= 1; //右移一位
- SCLK_dr = 1;
- delay_short(1);
- SCLK_dr = 0;
- delay_short(1);
- }
- //發(fā)送數(shù)據(jù)
- for ( i=0; i<8; i++ ) //循環(huán)8次移位
- {
- DIO_dr_sr = 0;
- temp = dat;
- if(temp&0x01)
- {
- DIO_dr_sr =1;
- }
- else
- {
- DIO_dr_sr =0;
- }
- delay_short(1);
- dat >>= 1; //右移一位
- SCLK_dr = 1;
- delay_short(1);
- SCLK_dr = 0;
- delay_short(1);
- }
- DS1302_CE_dr = 0;
- delay_short(1);
- }
- //讀取Ds1302時(shí)間的驅(qū)動(dòng) ,注意,此處讀取的是BCD碼,
- unsigned char Read1302 ( unsigned char addr )
- {
- unsigned char i,temp,dat1;
- DS1302_CE_dr=0; //單片機(jī)驅(qū)動(dòng)DS1302屬于SPI通訊方式,根據(jù)我的經(jīng)驗(yàn),不用關(guān)閉中斷
- delay_short(1);
- SCLK_dr=0;
- delay_short(1);
- DS1302_CE_dr = 1;
- delay_short(1);
- //發(fā)送地址
- for ( i=0; i<8; i++ ) //循環(huán)8次移位
- {
- DIO_dr_sr = 0;
- temp = addr;
- if(temp&0x01)
- {
- DIO_dr_sr =1;
- }
- else
- {
- DIO_dr_sr =0;
- }
- delay_short(1);
- addr >>= 1; //右移一位
- SCLK_dr = 1;
- delay_short(1);
- SCLK_dr = 0;
- delay_short(1);
- }
- /* 注釋二:
- * 51單片機(jī)IO口的特點(diǎn),在讀取數(shù)據(jù)之前必須先輸出高電平,
- * 如果是PIC,AVR等單片機(jī),這里應(yīng)該把IO方向寄存器設(shè)置為輸入
- */
- DIO_dr_sr =1; //51單片機(jī)IO口的特點(diǎn),在讀取數(shù)據(jù)之前必須先輸出高電平,
- temp=0;
- for ( i=0; i<8; i++ )
- {
- temp>>=1;
- if(DIO_dr_sr==1)
- {
- temp=temp+0x80;
- }
- DIO_dr_sr =1;//51單片機(jī)IO口的特點(diǎn),在讀取數(shù)據(jù)之前必須先輸出高電平
- delay_short(1);
- SCLK_dr = 1;
- delay_short(1);
- SCLK_dr = 0;
- delay_short(1);
- }
- DS1302_CE_dr=0;
- delay_short(1);
- dat1=temp;
- return (dat1);
- }
- unsigned char bcd_to_number(unsigned char ucBcdTemp)//BCD轉(zhuǎn)原始數(shù)值
- {
- unsigned char ucNumberResult=0;
- unsigned char ucBcdTemp10;
- unsigned char ucBcdTemp1;
- ucBcdTemp10=ucBcdTemp;
- ucBcdTemp10=ucBcdTemp10>>4;
- ucBcdTemp1=ucBcdTemp;
- ucBcdTemp1=ucBcdTemp1&0x0f;
- ucNumberResult=ucBcdTemp10*10+ucBcdTemp1;
- return ucNumberResult;
- }
- unsigned char number_to_bcd(unsigned char ucNumberTemp) //原始數(shù)值轉(zhuǎn)BCD
- {
- unsigned char ucBcdResult=0;
- unsigned char ucNumberTemp10;
- unsigned char ucNumberTemp1;
- ucNumberTemp10=ucNumberTemp;
- ucNumberTemp10=ucNumberTemp10/10;
- ucNumberTemp10=ucNumberTemp10<<4;
- ucNumberTemp10=ucNumberTemp10&0xf0;
- ucNumberTemp1=ucNumberTemp;
- ucNumberTemp1=ucNumberTemp1%10;
- ucBcdResult=ucNumberTemp10|ucNumberTemp1;
- return ucBcdResult;
- }
- //日調(diào)整 每個(gè)月份的日最大取值不同,有的最大28日,有的最大29日,有的最大30,有的最大31
- unsigned char date_adjust(unsigned char ucYearTemp,unsigned char ucMonthTemp,unsigned char ucDateTemp) //日調(diào)整
- {
- unsigned char ucDayResult;
- unsigned int uiYearTemp;
- unsigned int uiYearYu;
- ucDayResult=ucDateTemp;
- switch(ucMonthTemp)//根據(jù)不同的月份來(lái)修正不同的日最大值
- {
- case 2://二月份要計(jì)算是否是閏年
- uiYearTemp=2000+ucYearTemp;
- uiYearYu=uiYearTemp%4;
- if(uiYearYu==0) //閏年
- {
- if(ucDayResult>29)
- {
- ucDayResult=29;
- }
- }
- else
- {
- if(ucDayResult>28)
- {
- ucDayResult=28;
- }
- }
- break;
- case 4:
- case 6:
- case 9:
- case 11:
- if(ucDayResult>30)
- {
- ucDayResult=30;
- }
- break;
- }
- return ucDayResult;
- }
- void ds1302_alarm_service(void) //ds1302出錯(cuò)報(bào)警
- {
- if(ucDs1302Error==1)//備用電池的電量用完了報(bào)警提示
- {
- if(uiDs1302Cnt>const_ds1302_0_5s)//大概0.5秒鐘蜂鳴器響一次
- {
- ucDs1302Lock=1;//原子鎖加鎖
- uiDs1302Cnt=0; //計(jì)時(shí)器清零
- ucDs1302Lock=0;//原子鎖解鎖
- ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- uiVoiceCnt=const_voice_short; //蜂鳴器聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- }
- }
- }
- void display_service(void) //顯示的窗口菜單服務(wù)程序
- {
- switch(ucWd)//本程序的核心變量,窗口顯示變量。類似于一級(jí)菜單的變量。代表顯示不同的窗口。
- {
- case 1: //顯示日期窗口的數(shù)據(jù)數(shù)據(jù)格式 NN-YY-RR 年-月-日
- if(ucWd1Update==1)//窗口1要全部更新顯示
- {
- ucWd1Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來(lái)掃描
- ucDigShow6=11;//顯示一杠"-"
- ucDigShow3=11;//顯示一杠"-"
- ucWd1Part1Update=1;//局部年更新顯示
- ucWd1Part2Update=1;//局部月更新顯示
- ucWd1Part3Update=1;//局部日更新顯示
- }
- if(ucWd1Part1Update==1)//局部年更新顯示
- {
- ucWd1Part1Update=0;
- ucTemp8=ucYear/10;//年
- ucTemp7=ucYear%10;
- ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow7=ucTemp7;
- }
- if(ucWd1Part2Update==1)//局部月更新顯示
- {
- ucWd1Part2Update=0;
- ucTemp5=ucMonth/10;//月
- ucTemp4=ucMonth%10;
- ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow4=ucTemp4;
- }
- if(ucWd1Part3Update==1) //局部日更新顯示
- {
- ucWd1Part3Update=0;
- ucTemp2=ucDate/10;//日
- ucTemp1=ucDate%10;
- ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow1=ucTemp1;
- }
- //數(shù)碼管閃爍
- switch(ucPart)//相當(dāng)于二級(jí)菜單,根據(jù)局部變量的值,使對(duì)應(yīng)的參數(shù)產(chǎn)生閃爍的動(dòng)態(tài)效果。
- {
- case 0://都不閃爍
- break;
- case 1://年參數(shù)閃爍
- if(uiDpyTimeCnt==const_dpy_time_half)
- {
- ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow7=ucTemp7;
- }
- else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
- {
- ucDpyTimeLock=1; //原子鎖加鎖
- uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
- ucDpyTimeLock=0;//原子鎖解鎖
- ucDigShow8=10; //數(shù)碼管顯示空,什么都不顯示
- ucDigShow7=10;
- }
- break;
- case 2: //月參數(shù)閃爍
- if(uiDpyTimeCnt==const_dpy_time_half)
- {
- ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow4=ucTemp4;
- }
- else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
- {
- ucDpyTimeLock=1; //原子鎖加鎖
- uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
- ucDpyTimeLock=0;//原子鎖解鎖
- ucDigShow5=10; //數(shù)碼管顯示空,什么都不顯示
- ucDigShow4=10;
- }
- break;
- case 3: //日參數(shù)閃爍
- if(uiDpyTimeCnt==const_dpy_time_half)
- {
- ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow1=ucTemp1;
- }
- else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
- {
- ucDpyTimeLock=1; //原子鎖加鎖
- uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
- ucDpyTimeLock=0;//原子鎖解鎖
- ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
- ucDigShow1=10;
- }
- break;
- }
- break;
- case 2: //顯示時(shí)間窗口的數(shù)據(jù)數(shù)據(jù)格式 SS FF MM 時(shí) 分 秒
- if(ucWd2Update==1)//窗口2要全部更新顯示
- {
- ucWd2Update=0;//及時(shí)清零標(biāo)志,避免一直進(jìn)來(lái)掃描
- ucDigShow6=10;//顯示空
- ucDigShow3=10;//顯示空
- ucWd2Part3Update=1;//局部時(shí)更新顯示
- ucWd2Part2Update=1;//局部分更新顯示
- ucWd2Part1Update=1;//局部秒更新顯示
- }
- if(ucWd2Part1Update==1)//局部時(shí)更新顯示
- {
- ucWd2Part1Update=0;
- ucTemp8=ucHour/10;//時(shí)
- ucTemp7=ucHour%10;
- ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow7=ucTemp7;
- }
- if(ucWd2Part2Update==1)//局部分更新顯示
- {
- ucWd2Part2Update=0;
- ucTemp5=ucMinute/10;//分
- ucTemp4=ucMinute%10;
- ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow4=ucTemp4;
- }
- if(ucWd2Part3Update==1) //局部秒更新顯示
- {
- ucWd2Part3Update=0;
- ucTemp2=ucSecond/10;//秒
- ucTemp1=ucSecond%10;
- ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow1=ucTemp1;
- }
- //數(shù)碼管閃爍
- switch(ucPart)//相當(dāng)于二級(jí)菜單,根據(jù)局部變量的值,使對(duì)應(yīng)的參數(shù)產(chǎn)生閃爍的動(dòng)態(tài)效果。
- {
- case 0://都不閃爍
- break;
- case 1://時(shí)參數(shù)閃爍
- if(uiDpyTimeCnt==const_dpy_time_half)
- {
- ucDigShow8=ucTemp8; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow7=ucTemp7;
- }
- else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
- {
- ucDpyTimeLock=1; //原子鎖加鎖
- uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
- ucDpyTimeLock=0;//原子鎖解鎖
- ucDigShow8=10; //數(shù)碼管顯示空,什么都不顯示
- ucDigShow7=10;
- }
- break;
- case 2: //分參數(shù)閃爍
- if(uiDpyTimeCnt==const_dpy_time_half)
- {
- ucDigShow5=ucTemp5; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow4=ucTemp4;
- }
- else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
- {
- ucDpyTimeLock=1; //原子鎖加鎖
- uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
- ucDpyTimeLock=0;//原子鎖解鎖
- ucDigShow5=10; //數(shù)碼管顯示空,什么都不顯示
- ucDigShow4=10;
- }
- break;
- case 3: //秒?yún)?shù)閃爍
- if(uiDpyTimeCnt==const_dpy_time_half)
- {
- ucDigShow2=ucTemp2; //數(shù)碼管顯示實(shí)際內(nèi)容
- ucDigShow1=ucTemp1;
- }
- else if(uiDpyTimeCnt>const_dpy_time_all) //const_dpy_time_all一定要比const_dpy_time_half 大
- {
- ucDpyTimeLock=1; //原子鎖加鎖
- uiDpyTimeCnt=0; //及時(shí)把閃爍記時(shí)器清零
- ucDpyTimeLock=0;//原子鎖解鎖
- ucDigShow2=10; //數(shù)碼管顯示空,什么都不顯示
- ucDigShow1=10;
- }
- break;
- }
- break;
- }
- }
- void key_scan(void)//按鍵掃描函數(shù) 放在定時(shí)中斷里
- {
- if(key_sr1==1)//IO是高電平,說(shuō)明按鍵沒(méi)有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
- {
- ucKeyLock1=0; //按鍵自鎖標(biāo)志清零
- uiKeyTimeCnt1=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來(lái)的。
- }
- else if(ucKeyLock1==0)//有按鍵按下,且是第一次被按下
- {
- uiKeyTimeCnt1++; //累加定時(shí)中斷次數(shù)
- if(uiKeyTimeCnt1>const_key_time1)
- {
- uiKeyTimeCnt1=0;
- ucKeyLock1=1;//自鎖按鍵置位,避免一直觸發(fā)
- ucKeySec=1; //觸發(fā)1號(hào)鍵
- }
- }
- if(key_sr2==1)//IO是高電平,說(shuō)明按鍵沒(méi)有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
- {
- ucKeyLock2=0; //按鍵自鎖標(biāo)志清零
- uiKeyTimeCnt2=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來(lái)的。
- }
- else if(ucKeyLock2==0)//有按鍵按下,且是第一次被按下
- {
- uiKeyTimeCnt2++; //累加定時(shí)中斷次數(shù)
- if(uiKeyTimeCnt2>const_key_time2)
- {
- uiKeyTimeCnt2=0;
- ucKeyLock2=1;//自鎖按鍵置位,避免一直觸發(fā)
- ucKeySec=2; //觸發(fā)2號(hào)鍵
- }
- }
- /* 注釋三:
- * 注意,此處把一個(gè)按鍵的短按和長(zhǎng)按的功能都實(shí)現(xiàn)了。
- */
- if(key_sr3==1)//IO是高電平,說(shuō)明按鍵沒(méi)有被按下,這時(shí)要及時(shí)清零一些標(biāo)志位
- {
- ucKeyLock3=0; //按鍵自鎖標(biāo)志清零
- uiKeyTimeCnt3=0;//按鍵去抖動(dòng)延時(shí)計(jì)數(shù)器清零,此行非常巧妙,是我實(shí)戰(zhàn)中摸索出來(lái)的。
- }
- else if(ucKeyLock3==0)//有按鍵按下,且是第一次被按下
- {
- uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
- if(uiKeyTimeCnt3>const_key_time3)
- {
- uiKeyTimeCnt3=0;
- ucKeyLock3=1;//自鎖按鍵置位,避免一直觸發(fā)
- ucKeySec=3; //短按觸發(fā)3號(hào)鍵
- }
- }
- else if(uiKeyTimeCnt3
- {
- uiKeyTimeCnt3++; //累加定時(shí)中斷次數(shù)
- if(uiKeyTimeCnt3==const_key_time17)//等于3秒鐘,觸發(fā)17號(hào)長(zhǎng)按按鍵
- {
- ucKeySec=17; //長(zhǎng)按3秒觸發(fā)17號(hào)鍵
- }
- }
- /* 注釋四:
- * 注意,此處是電平按鍵的濾波抗干擾處理
- */
- if(key_sr4==1)//對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S13鍵
- {
- uiKey4Cnt1=0; //在軟件濾波中,非常關(guān)鍵的語(yǔ)句?。?!類似按鍵去抖動(dòng)程序的及時(shí)清零
- uiKey4Cnt2++; //類似獨(dú)立按鍵去抖動(dòng)的軟件抗干擾處理
- if(uiKey4Cnt2>const_key_time4)
- {
- uiKey4Cnt2=0;
- ucKey4Sr=1;//實(shí)時(shí)反映按鍵松手時(shí)的電平狀態(tài)
- }
- }
- else
- {
- uiKey4Cnt2=0; //在軟件濾波中,非常關(guān)鍵的語(yǔ)句?。?!類似按鍵去抖動(dòng)程序的及時(shí)清零
- uiKey4Cnt1++;
- if(uiKey4Cnt1>const_key_time4)
- {
- uiKey4Cnt1=0;
- ucKey4Sr=0;//實(shí)時(shí)反映按鍵按下時(shí)的電平狀態(tài)
- }
- }
- }
- void key_service(void) //按鍵服務(wù)的應(yīng)用程序
- {
- switch(ucKeySec) //按鍵服務(wù)狀態(tài)切換
- {
- case 1:// 加按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S1鍵
- switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
- {
- case 1:
- switch(ucPart) //在不同的局部變量下,相當(dāng)于二級(jí)菜單
- {
- case 1://年
- ucYear++;
- if(ucYear>99)
- {
- ucYear=99;
- }
- ucWd1Part1Update=1;//更新顯示
- break;
- case 2: //月
- ucMonth++;
- if(ucMonth>12)
- {
- ucMonth=12;
- }
- ucWd1Part2Update=1;//更新顯示
- break;
- case 3: //日
- ucDate++;
- if(ucDate>31)
- {
- ucDate=31;
- }
- ucWd1Part3Update=1;//更新顯示
- break;
- }
- break;
- case 2:
- switch(ucPart) //在不同的局部變量下,相當(dāng)于二級(jí)菜單
- {
- case 1://時(shí)
- ucHour++;
- if(ucHour>23)
- {
- ucHour=23;
- }
- ucWd2Part1Update=1;//更新顯示
- break;
- case 2: //分
- ucMinute++;
- if(ucMinute>59)
- {
- ucMinute=59;
- }
- ucWd2Part2Update=1;//更新顯示
- break;
- case 3: //秒
- ucSecond++;
- if(ucSecond>59)
- {
- ucSecond=59;
- }
- ucWd2Part3Update=1;//更新顯示
- break;
- }
- break;
- }
- ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
- break;
- case 2:// 減按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S5鍵
- switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
- {
- case 1:
- switch(ucPart) //在不同的局部變量下,相當(dāng)于二級(jí)菜單
- {
- case 1://年
- ucYear--;
- if(ucYear>99)
- {
- ucYear=0;
- }
- ucWd1Part1Update=1;//更新顯示
- break;
- case 2: //月
- ucMonth--;
- if(ucMonth<1)
- {
- ucMonth=1;
- }
- ucWd1Part2Update=1;//更新顯示
- break;
- case 3: //日
- ucDate--;
- if(ucDate<1)
- {
- ucDate=1;
- }
- ucWd1Part3Update=1;//更新顯示
- break;
- }
- break;
- case 2:
- switch(ucPart) //在不同的局部變量下,相當(dāng)于二級(jí)菜單
- {
- case 1://時(shí)
- ucHour--;
- if(ucHour>23)
- {
- ucHour=0;
- }
- ucWd2Part1Update=1;//更新顯示
- break;
- case 2: //分
- ucMinute--;
- if(ucMinute>59)
- {
- ucMinute=0;
- }
- ucWd2Part2Update=1;//更新顯示
- break;
- case 3: //秒
- ucSecond--;
- if(ucSecond>59)
- {
- ucSecond=0;
- }
- ucWd2Part3Update=1;//更新顯示
- break;
- }
- break;
- }
- ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
- break;
- case 3://短按設(shè)置按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
- switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
- {
- case 1:
- ucPart++;
- if(ucPart>3)
- {
- ucPart=1;
- ucWd=2; //切換到第二個(gè)窗口,設(shè)置時(shí)分秒
- ucWd2Update=1;//窗口2更新顯示
- }
- ucWd1Update=1;//窗口1更新顯示
- break;
- case 2:
- if(ucPart>0) //在窗口2的時(shí)候,要第一次激活設(shè)置時(shí)間,必須是長(zhǎng)按3秒才可以,這里短按激活不了第一次
- {
- ucPart++;
- if(ucPart>3)//設(shè)置時(shí)間結(jié)束
- {
- ucPart=0;
- /* 注釋五:
- * 每個(gè)月份的天數(shù)最大值是不一樣的,在寫入ds1302時(shí)鐘芯片內(nèi)部數(shù)據(jù)前,應(yīng)該做一次調(diào)整。
- * 有的月份最大28天,有的月份最大29天,有的月份最大30天,有的月份最大31天,
- */
- ucDate=date_adjust(ucYear,ucMonth,ucDate); //日調(diào)整 避免日的數(shù)值在某個(gè)月份超范圍
- ucYearBCD=number_to_bcd(ucYear);//原始數(shù)值轉(zhuǎn)BCD
- ucMonthBCD=number_to_bcd(ucMonth); //原始數(shù)值轉(zhuǎn)BCD
- ucDateBCD=number_to_bcd(ucDate);//原始數(shù)值轉(zhuǎn)BCD
- ucHourBCD=number_to_bcd(ucHour);//原始數(shù)值轉(zhuǎn)BCD
- ucMinuteBCD=number_to_bcd(ucMinute);//原始數(shù)值轉(zhuǎn)BCD
- ucSecondBCD=number_to_bcd(ucSecond);//原始數(shù)值轉(zhuǎn)BCD
- Write1302 (WRITE_PROTECT,0X00); //禁止寫保護(hù)
- Write1302 (WRITE_YEAR,ucYearBCD); //年修改
- Write1302 (WRITE_MONTH,ucMonthBCD); //月修改
- Write1302 (WRITE_DATE,ucDateBCD); //日修改
- Write1302 (WRITE_HOUR,ucHourBCD); //小時(shí)修改
- Write1302 (WRITE_MINUTE,ucMinuteBCD); //分鐘修改
- Write1302 (WRITE_SECOND,ucSecondBCD); //秒位修改
- Write1302 (WRITE_PROTECT,0x80); //允許寫保護(hù)
- }
- ucWd2Update=1;//窗口2更新顯示
- }
- break;
- }
- ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
- break;
- case 17://長(zhǎng)按3秒設(shè)置按鍵 對(duì)應(yīng)朱兆祺學(xué)習(xí)板的S9鍵
- switch(ucWd)//在不同的窗口下,設(shè)置不同的參數(shù)
- {
- case 2:
- if(ucPart==0) //處于非設(shè)置時(shí)間的狀態(tài)下,要第一次激活設(shè)置時(shí)間,必須是長(zhǎng)按3秒才可以
- {
- ucWd=1;
- ucPart=1;//進(jìn)入到設(shè)置日期的狀態(tài)下
- ucWd1Update=1;//窗口1更新顯示
- }
- break;
- }
- ucVoiceLock=1;//原子鎖加鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- uiVoiceCnt=const_voice_short; //按鍵聲音觸發(fā),滴一聲就停。
- ucVoiceLock=0;//原子鎖解鎖,保護(hù)主函數(shù)與中斷函數(shù)的共享變量uiVoiceCnt
- ucKeySec=0;//響應(yīng)按鍵服務(wù)處理程序后,按鍵編號(hào)清零,避免一致觸發(fā)
- break;
- }
- /* 注釋六:
- * 注意,此處就是第一次出現(xiàn)的電平按鍵程序,跟以往的下降沿按鍵不一樣。
- * ucKey4Sr是經(jīng)過(guò)軟件濾波處理后,直接反應(yīng)IO口電平狀態(tài)的變量.當(dāng)電平發(fā)生
- * 變化時(shí),就會(huì)切換到不同的顯示界面,這里多用了一個(gè)ucKey4SrRecord變量
- * 記錄上一次的電平狀態(tài),是為了避免一直刷新顯示。
- */
- if(ucKey4Sr!=ucKey4SrRecord)//說(shuō)明S13的切換按鍵電平狀態(tài)發(fā)生變化
- {
- ucKey4SrRecord=ucKey4Sr;//及時(shí)記錄當(dāng)前最新的按鍵電平狀態(tài)避免一直進(jìn)來(lái)觸發(fā)
- if(ucKey4Sr==1) //松手后切換到顯示時(shí)間的窗口
- {
- ucWd=2; //顯示時(shí)分秒的窗口
- ucPart=0;//進(jìn)入到非設(shè)置時(shí)間的狀態(tài)下
- ucWd2Update=1;//窗口2更新顯示
- }
- else//按下去切換到顯示日期的窗口
- {
- ucWd=1; //顯示年月日的窗口
- ucPart=0;//進(jìn)入到非設(shè)置時(shí)間的狀態(tài)下
- ucWd1Update=1;//窗口1更新顯示
- }
- }
- }
- void display_drive(void)
- {
- //以下程序,如果加一些數(shù)組和移位的元素,還可以壓縮容量。但是鴻哥追求的不是容量,而是清晰的講解思路
- switch(ucDisplayDriveStep)
- {
- case 1://顯示第1位
- ucDigShowTemp=dig_table[ucDigShow1];
- if(ucDigDot1==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0xfe);
- break;
- case 2://顯示第2位
- ucDigShowTemp=dig_table[ucDigShow2];
- if(ucDigDot2==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0xfd);
- break;
- case 3://顯示第3位
- ucDigShowTemp=dig_table[ucDigShow3];
- if(ucDigDot3==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0xfb);
- break;
- case 4://顯示第4位
- ucDigShowTemp=dig_table[ucDigShow4];
- if(ucDigDot4==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0xf7);
- break;
- case 5://顯示第5位
- ucDigShowTemp=dig_table[ucDigShow5];
- if(ucDigDot5==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0xef);
- break;
- case 6://顯示第6位
- ucDigShowTemp=dig_table[ucDigShow6];
- if(ucDigDot6==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0xdf);
- break;
- case 7://顯示第7位
- ucDigShowTemp=dig_table[ucDigShow7];
- if(ucDigDot7==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0xbf);
- break;
- case 8://顯示第8位
- ucDigShowTemp=dig_table[ucDigShow8];
- if(ucDigDot8==1)
- {
- ucDigShowTemp=ucDigShowTemp|0x80;//顯示小數(shù)點(diǎn)
- }
- dig_hc595_drive(ucDigShowTemp,0x7f);
- break;
- }
- ucDisplayDriveStep++;
- if(ucDisplayDriveStep>8)//掃描完8個(gè)數(shù)碼管后,重新從第一個(gè)開(kāi)始掃描
- {
- ucDisplayDriveStep=1;
- }
- }
- //數(shù)碼管的74HC595驅(qū)動(dòng)函數(shù)
- void dig_hc595_drive(unsigned char ucDigStatusTemp16_09,unsigned char ucDigStatusTemp08_01)
- {
- unsigned char i;
- unsigned char ucTempData;
- dig_hc595_sh_dr=0;
- dig_hc595_st_dr=0;
- ucTempData=ucDigStatusTemp16_09;//先送高8位
- for(i=0;i<8;i++)
- {
- if(ucTempData>=0x80)dig_hc595_ds_dr=1;
- else dig_hc595_ds_dr=0;
- dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
- delay_short(1);
- dig_hc595_sh_dr=1;
- delay_short(1);
- ucTempData=ucTempData<<1;
- }
- ucTempData=ucDigStatusTemp08_01;//再先送低8位
- for(i=0;i<8;i++)
- {
- if(ucTempData>=0x80)dig_hc595_ds_dr=1;
- else dig_hc595_ds_dr=0;
- dig_hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
- delay_short(1);
- dig_hc595_sh_dr=1;
- delay_short(1);
- ucTempData=ucTempData<<1;
- }
- dig_hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來(lái)
- delay_short(1);
- dig_hc595_st_dr=1;
- delay_short(1);
- dig_hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
- dig_hc595_st_dr=0;
- dig_hc595_ds_dr=0;
- }
- //LED燈的74HC595驅(qū)動(dòng)函數(shù)
- void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01)
- {
- unsigned char i;
- unsigned char ucTempData;
- hc595_sh_dr=0;
- hc595_st_dr=0;
- ucTempData=ucLedStatusTemp16_09;//先送高8位
- for(i=0;i<8;i++)
- {
- if(ucTempData>=0x80)hc595_ds_dr=1;
- else hc595_ds_dr=0;
- hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
- delay_short(1);
- hc595_sh_dr=1;
- delay_short(1);
- ucTempData=ucTempData<<1;
- }
- ucTempData=ucLedStatusTemp08_01;//再先送低8位
- for(i=0;i<8;i++)
- {
- if(ucTempData>=0x80)hc595_ds_dr=1;
- else hc595_ds_dr=0;
- hc595_sh_dr=0; //SH引腳的上升沿把數(shù)據(jù)送入寄存器
- delay_short(1);
- hc595_sh_dr=1;
- delay_short(1);
- ucTempData=ucTempData<<1;
- }
- hc595_st_dr=0;//ST引腳把兩個(gè)寄存器的數(shù)據(jù)更新輸出到74HC595的輸出引腳上并且鎖存起來(lái)
- delay_short(1);
- hc595_st_dr=1;
- delay_short(1);
- hc595_sh_dr=0; //拉低,抗干擾就增強(qiáng)
- hc595_st_dr=0;
- hc595_ds_dr=0;
- }
- void T0_time(void) interrupt 1 //定時(shí)中斷
- {
- TF0=0;//清除中斷標(biāo)志
- TR0=0; //關(guān)中斷
- if(ucVoiceLock==0) //原子鎖判斷
- {
- if(uiVoiceCnt!=0)
- {
- uiVoiceCnt--; //每次進(jìn)入定時(shí)中斷都自減1,直到等于零為止。才停止鳴叫
- beep_dr=0;//蜂鳴器是PNP三極管控制,低電平就開(kāi)始鳴叫。
- }
- else
- {
- ; //此處多加一個(gè)空指令,想維持跟if括號(hào)語(yǔ)句的數(shù)量對(duì)稱,都是兩條指令。不加也可以。
- beep_dr=1;//蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
- }
- }
- if(ucDs1302Error>0) //EEPROM出錯(cuò)
- {
- if(ucDs1302Lock==0)//原子鎖判斷
- {
- uiDs1302Cnt++;//間歇性蜂鳴器報(bào)警的計(jì)時(shí)器
- }
- }
- if(ucDpyTimeLock==0) //原子鎖判斷
- {
- uiDpyTimeCnt++;//數(shù)碼管的閃爍計(jì)時(shí)器
- }
- key_scan(); //按鍵掃描函數(shù)
- display_drive();//數(shù)碼管字模的驅(qū)動(dòng)函數(shù)
- TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
- TL0=0x0b;
- TR0=1;//開(kāi)中斷
- }
- void delay_short(unsigned int uiDelayShort)
- {
- unsigned int i;
- for(i=0;i
- {
- ; //一個(gè)分號(hào)相當(dāng)于執(zhí)行一條空語(yǔ)句
- }
- }
- void delay_long(unsigned int uiDelayLong)
- {
- unsigned int i;
- unsigned int j;
- for(i=0;i
- {
- for(j=0;j<500;j++)//內(nèi)嵌循環(huán)的空指令數(shù)量
- {
- ; //一個(gè)分號(hào)相當(dāng)于執(zhí)行一條空語(yǔ)句
- }
- }
- }
- void initial_myself(void)//第一區(qū) 初始化單片機(jī)
- {
- key_gnd_dr=0; //模擬獨(dú)立按鍵的地GND,因此必須一直輸出低電平
- beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時(shí)不叫。
- hc595_drive(0x00,0x00);//關(guān)閉所有經(jīng)過(guò)另外兩個(gè)74HC595驅(qū)動(dòng)的LED燈
- TMOD=0x01;//設(shè)置定時(shí)器0為工作方式1
- TH0=0xfe; //重裝初始值(65535-500)=65035=0xfe0b
- TL0=0x0b;
- }
- void initial_peripheral(void) //第二區(qū) 初始化外圍
- {
- ucDigDot8=0; //小數(shù)點(diǎn)全部不顯示
- ucDigDot7=0;
- ucDigDot6=0;
- ucDigDot5=0;
- ucDigDot4=0;
- ucDigDot3=0;
- ucDigDot2=0;
- ucDigDot1=0;
- EA=1; //開(kāi)總中斷
- ET0=1; //允許定時(shí)中斷
- TR0=1; //啟動(dòng)定時(shí)中斷
- /* 注釋七:
- * 檢查ds1302芯片的備用電池電量是否用完了。
- * 在上電的時(shí)候,在一個(gè)特定的地址里把數(shù)據(jù)讀出來(lái),如果發(fā)現(xiàn)不等于0x5a,
- * 則是因?yàn)閭溆秒姵仉娏坑猛炅耍瑢?dǎo)致保存在ds1302內(nèi)部RAM數(shù)據(jù)區(qū)的數(shù)據(jù)被更改,
- * 與此同時(shí),應(yīng)該重新寫入一次0x5a,為下一次通電判斷做準(zhǔn)備
- */
- ucCheckDs1302=Read1302(READ_CHECK); //判斷ds1302內(nèi)部的數(shù)據(jù)是否被更改
- if(ucCheckDs1302!=0x5a)
- {
- Write1302 (WRITE_PROTECT,0X00); //禁止寫保護(hù)
- Write1302 (WRITE_CHECK,0x5a); //重新寫入標(biāo)志數(shù)據(jù),方便下一次更換新電池后的判斷
- Write1302 (WRITE_PROTECT,0x80); //允許寫保護(hù)
- ucDs1302Error=1;//表示ds1302備用電池沒(méi)電了,報(bào)警提示更換新電池
- }
- }
總結(jié)陳詞:
下一節(jié)開(kāi)始講單片機(jī)驅(qū)動(dòng)溫度傳感器芯片的內(nèi)容,欲知詳情,請(qǐng)聽(tīng)下回分解-----利用DS18B20做一個(gè)溫控器。
評(píng)論