在寫代碼前,記得把上一節的跳線帽給插回去,不然LCD無法顯示
一.DS1302時鐘
1.編寫DS1302.c文件
(1)重新對端口定義名字
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
(2)初始化
因為單片機上電默認是1,所以要初始化為0
void DS1302_Init(void)
{DS1302_CE=0;DS1302_SCLK=0;
}
(3)寫入函數
在給SCLK賦值的時候
? ? DS1302_SCLK=1; ?
?? ?DS1302_SCLK=0;
在這中間置1后馬上置0需要有一個最小的延時,但實際操作后發現不用加延時可以運行,因為我們的單片機運行沒有這么快
這里相當于我們已經寫入了第0位
//Command是命令字
void DS1302_WriteByte(unsigned char Command,Data)
{DS1302_CE=1;DS1302_IO=Command&0x01; //取第0位DS1302_SCLK=1; DS1302_SCLK=0;}
同理第1位即?? ?DS1302_IO=Command&0x02;?
? ? ? ?第2位即?? ?DS1302_IO=Command&0x04; .......
所以我們可以用一個for循環來實現取8位
//Command是命令字
void DS1302_WriteByte(unsigned char Command,Data)
{unsigned char iDS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0;}}
此時我們已經完成寫入操作的一半,又發現后面的寫入數據和前面的寫入指令是一樣的,所以我們可以復制for循環的代碼思路
//Command是命令字
void DS1302_WriteByte(unsigned char Command,Data)
{unsigned char iDS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0;}for(i=0;i<8;i++){DS1302_IO=Data&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0;}DS1302_CE=0;
}
記得在最后把CE置0
到這我們就完成時序的寫入函數,我們就可以對任何的寄存器進行寫入操作
(4)讀取函數
雖然該部分的時序跟上面的寫入類似,但不能直接照搬,因為在SCLK這條線上只有15個脈沖(寫入是16個)因為在最中間的脈沖同時進行上升沿和下降沿的操作
所以我們把SCLK賦值的順序顛倒一下,先給0再給1,這樣當for循環8次后,剛好全是上升沿
這里根據代碼理解在圖上比劃一下就很好理解,第一個for循環里先給0再給1,在循環結束后SCLK依舊是1,但是在第二個for循環里還是要先給1再給0,目的就是為了跳過一個周期適配15個脈沖
unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i,Data=0x00;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i); DS1302_SCLK=0; DS1302_SCLK=1;}for(i=0;i<8;i++){DS1302_SCLK=1; DS1302_SCLK=0;if(DS1302_IO){Data |= (0X01<<i);} }DS1302_CE=0;return Data;
}
一般來說,與操作是為了清零,或操作是為了置1
最后不用忘了return 返回值,因為這是有返回值的函數
(5)測試
寫完上面3個函數,我們就已經對時序模擬出來了、
接下來進行測試
先寫好聲明文件
//DS1302.h#ifndef __DS1302_H_
#define __DS1302_H_void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);#endif
這里提醒一下,DS1302初始化有寫保護,只能讀不能寫,在DS1302初始化之后加一句DS1302_WriteByte(0x8e,0x00);0x8E為寫保護寄存器,需要先關閉寫保護,
//main文件#include <REGX52.H>
#include " LCD1602.h"
#include " DS1302.h"unsigned char Second;void main()
{DS1302_Init();DS1302_WriteByte(0x8E,0x00);LCD_Init();LCD_ShowString(1,1,"RTC");DS1302_WriteByte(0x80,0x03);Second=DS1302_ReadByte(0x81);LCD_ShowNum(2,1,Second,3);while(1){}}
現象
(6)擴展知識點
BCD碼(Binary Coded Decimal):用4位二進制數來表示1位十進制
內部的寄存器不是以二進制來存儲的,而是以BCD碼來存儲
例:0001 0011表示13,1000 0101表示85,0001 1010不合法
在十六進制中的體現:0x13表示13,0x85表示85,0x1A不合法
BCD碼轉十進制:DEC=BCD/16*10+BCD%16;(2位BCD)
十進制轉BCD碼:BCD=DEC/10*16+DEC%16;(2位BCD)
#include <REGX52.H>
#include " LCD1602.h"
#include " DS1302.h"
#include " Delay.h"unsigned char Second;void main()
{DS1302_Init();DS1302_WriteByte(0x8E,0x00);LCD_Init();LCD_ShowString(1,1,"RTC");DS1302_WriteByte(0x80,0x03);while(1){Second=DS1302_ReadByte(0x81);LCD_ShowHexNum(2,1,Second,3);}}
所以我們在這里想讓Second自加顯示在LCD上,就得使用下面這個函數,而不是ShowNum,否則他會從9突變到16,這是因為ShowNum是以十進制來顯示,而時鐘寄存器的自加是上面所說的BCD碼,而下面這個函數是以十六進制顯示的? ? ? ? ? ? LCD_ShowHexNum(2,1,Second,3);? 十六進制和BCD碼有部分兼容
下面解釋寄存器里的BCD碼
CH是時鐘靜止,給1靜止給0運行,高3位顯示10秒,低4位顯示秒,分、時、日、月、年都是同理
小時的最高位是選擇12/24制,第6位選擇AM還是PM
根據前面BCD碼轉十進制,我們就可以寫出
LCD_ShowNum(2,1,Second/16*10+Second%16,3);
這樣就可以在LCD上正常顯示了
(7)定義數組函數存儲讀寫年月日等
先定義地址
因為寫入和讀取的地址前7位都是一樣的,只有最低位是01之分,這里我們只定義寫入的地址,只需要在讀的函數里給Command即命令字的最低位置1,這樣就不用再重新定義讀取的地址了
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8Eunsigned char DS1302_ReadByte(unsigned char Command)
{Command |=0x01;
下面是完整代碼
記得要在.h文件里說明
這里再說一電,聲明外部變量時前面必須加extern,數組和函數可以不加因為前面會自帶
#include <REGX52.H>//重新對端口定義名字
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8Eunsigned char DS1320_Time[]={25,03,04,12,59,55,2}void DS1302_Init(void)
{DS1302_CE=0;DS1302_SCLK=0;
}//Command是命令字
void DS1302_WriteByte(unsigned char Command,Data)
{unsigned char i;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0;}for(i=0;i<8;i++){DS1302_IO=Data&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0;}DS1302_CE=0;
}unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i,Data=0x00;Command |=0x01;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i); DS1302_SCLK=0; DS1302_SCLK=1;}for(i=0;i<8;i++){DS1302_SCLK=1; DS1302_SCLK=0;if(DS1302_IO){Data |= (0X01<<i);} }DS1302_CE=0;DS1302_IO=0;return Data;
}//寫入時間是十進制轉BCD碼
void DS1302_SetTime(void)
{DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP,0x80);
}
//讀取時間是BCD碼轉十進制
void DS1302_ReadTime(void)
{unsigned char Temp;Temp=DS1302_ReadByte(DS1302_YEAR);DS1302_Time[0]=Temp/16*10+Temp%16Temp=DS1302_ReadByte(DS1302_MONTH);DS1302_Time[1]=Temp/16*10+Temp%16Temp=DS1302_ReadByte(DS1302_DATE);DS1302_Time[2]=Temp/16*10+Temp%16Temp=DS1302_ReadByte(DS1302_HOUR);DS1302_Time[3]=Temp/16*10+Temp%16Temp=DS1302_ReadByte(DS1302_MINUTE);DS1302_Time[4]=Temp/16*10+Temp%16Temp=DS1302_ReadByte(DS1302_SECOND);DS1302_Time[5]=Temp/16*10+Temp%16Temp=DS1302_ReadByte(DS1302_DAY);DS1302_Time[6]=Temp/16*10+Temp%16}
有了這些代碼我們就不用在main函數里定義時分秒了,我們只需要調用函數即可
(8)主函數
到這里我們就做好第一個功能了
#include <REGX52.H>
#include " LCD1602.h"
#include " DS1302.h"
#include " Delay.h"void main()
{DS1302_Init();LCD_Init();LCD_ShowString(1,1," - - ");LCD_ShowString(2,1," : : ");DS1302_SetTime();while(1){DS1302_ReadTime();LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2);}}
下面再對模塊化參數進行注釋?
#include <REGX52.H>//引腳定義
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;//寄存器寫入地址/指令定義
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8Eunsigned char DS1302_Time[]={25,03,04,12,59,55,2};/*** @brief DS1302初始化* @param 無* @retval 無*/void DS1302_Init(void)
{DS1302_CE=0;DS1302_SCLK=0;
}/*** @brief DS1302寫一個字節* @param Command命令字/地址* @param Data要寫入的數據* @retval 無*/
void DS1302_WriteByte(unsigned char Command,Data)
{unsigned char i;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0;}for(i=0;i<8;i++){DS1302_IO=Data&(0x01<<i); DS1302_SCLK=1; DS1302_SCLK=0;}DS1302_CE=0;
}/*** @brief DS1302讀一個字節* @param Command命令字/地址* @retval 讀出的數據*/unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i,Data=0x00;Command |=0x01;DS1302_CE=1;for(i=0;i<8;i++){DS1302_IO=Command&(0x01<<i); DS1302_SCLK=0; DS1302_SCLK=1;}for(i=0;i<8;i++){DS1302_SCLK=1; DS1302_SCLK=0;if(DS1302_IO){Data |= (0X01<<i);} }DS1302_CE=0;DS1302_IO=0;return Data;
}/*** @brief DS1302設置時間,調用之后,DS1302_Time數組的數字會被設置到DS1302中* @param 無* @retval 無*/
void DS1302_SetTime(void)
{DS1302_WriteByte(DS1302_WP,0x00);DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//鍗佽繘鍒惰漿BCD鐮佸悗鍐欏叆DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP,0x80);
}/*** @brief DS1302讀取時間,調用之后,DS1302中的數據會被讀取到DS1302_Time數組中* @param 無* @retval 無*/
void DS1302_ReadTime(void)
{unsigned char Temp;Temp=DS1302_ReadByte(DS1302_YEAR);DS1302_Time[0]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_MONTH);DS1302_Time[1]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DATE);DS1302_Time[2]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_HOUR);DS1302_Time[3]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_MINUTE);DS1302_Time[4]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_SECOND);DS1302_Time[5]=Temp/16*10+Temp%16;Temp=DS1302_ReadByte(DS1302_DAY);DS1302_Time[6]=Temp/16*10+Temp%16;}
二.DS1302可調時鐘
這個部分是上一個代碼的升級版,這一塊會比較難
下面為了節約空間,我沒有把定義的變量標出來,都是unsigned char類型
1.按鍵1切換
定義按鍵1,切換我們的模式,模式0是時間顯示,模式1是時間設置
void main()
{DS1302_Init();LCD_Init();LCD_ShowString(1,1," - - ");LCD_ShowString(2,1," : : ");DS1302_SetTime();while(1){KeyNum=Key();if(KeyNum==1){if(MODE==0){MODE=1;}else if(MODE==1){MODE=0;}}switch(MODE){case 0:TimeShow();break;case 1:TimeSet();break;}}}
2.時間顯示函數
void TimeShow(void)
{DS1302_ReadTime();LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2);
}
3.時間設置函數
按鍵2讓時間設置選擇++并且取值范圍在0~5
void TimeSet(void)
{if(KeyNum==2){TimeSetSelect++;TimeSetSelect%=6; //大于5越界取余0的進階寫法}if(KeyNum==3){DS1302_Time[TimeSetSelect]++;}if(KeyNum==4){DS1302_Time[TimeSetSelect]--;}LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2);LCD_ShowNum(2,10,TimeSetSelect,2);
}
這樣就已經實現對時鐘的六個位進行選擇和加減,但是我們并沒有設置越界判斷,也就是說月份會一直加到13,14月,所以下面我們對這個函數進行越界判斷的優化
這段最麻煩是對日的判斷,因為有30和31的區分,而2月又有28和29的區分,所以非常麻煩
void TimeSet(void)
{if(KeyNum==2){TimeSetSelect++;TimeSetSelect%=6; //大于5越界取余0的進階寫法}
if(KeyNum==3){DS1302_Time[TimeSetSelect]++;if(DS1302_Time[0]>99){DS1302_Time[0]=0;}if(DS1302_Time[1]>12){DS1302_Time[1]=1;}if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 || DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12){if(DS1302_Time[2]>31){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11){if(DS1302_Time[2]>30){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]>29){DS1302_Time[2]=1;}}else{if(DS1302_Time[2]>28){DS1302_Time[2]=1;}}}if(DS1302_Time[3]>23){DS1302_Time[3]=0;}if(DS1302_Time[4]>59){DS1302_Time[4]=0;}if(DS1302_Time[5]>59){DS1302_Time[5]=0;}}if(KeyNum==4){DS1302_Time[TimeSetSelect]--;if(DS1302_Time[0]<0){DS1302_Time[0]=99;}if(DS1302_Time[1]<1){DS1302_Time[1]=12;}if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 || DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12){if(DS1302_Time[2]<1){DS1302_Time[2]=31;}if(DS1302_Time[2]>31){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11){if(DS1302_Time[2]<1){DS1302_Time[2]=30;}if(DS1302_Time[2]>30){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]<1){DS1302_Time[2]=29;}if(DS1302_Time[2]>29){DS1302_Time[2]=1;}}else{if(DS1302_Time[2]<1){DS1302_Time[2]=28;}if(DS1302_Time[2]>28){DS1302_Time[2]=1;}}}if(DS1302_Time[3]<0){DS1302_Time[3]=23;}if(DS1302_Time[4]<0){DS1302_Time[4]=59;}if(DS1302_Time[5]<0){DS1302_Time[5]=59;}}LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2);LCD_ShowNum(2,10,TimeSetSelect,2);
}
4.選擇對應位閃爍
感嘆號是邏輯取反,波浪號是按位取反
比如0邏輯取反1,1邏輯取反0;0按位取反0xFE,1按位取反0xFF
我們設置一個變量,讓他10101010的變化,然后當選擇某個位時,讓這個位為1時亮,為0時滅,在這里我們只需要一個標識位,所以用邏輯取反就好
這里要用到之前的定時器中斷的函數
if(TimeSetSelect==0&&TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}else {LCD_ShowNum(1,1,DS1302_Time[0],2);}if(TimeSetSelect==1&&TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}else {LCD_ShowNum(1,4,DS1302_Time[1],2);}if(TimeSetSelect==2&&TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}else {LCD_ShowNum(1,7,DS1302_Time[2],2);}if(TimeSetSelect==3&&TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}else {LCD_ShowNum(2,1,DS1302_Time[3],2);}if(TimeSetSelect==4&&TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}else {LCD_ShowNum(2,4,DS1302_Time[4],2);}if(TimeSetSelect==5&&TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}else {LCD_ShowNum(2,7,DS1302_Time[5],2);}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18; //設置定時初值TH0 = 0xFC; //設置定時初值T0Count++;if(T0Count>=500){T0Count=0;TimeSetFlashFlag=!TimeSetFlashFlag;}}
#include <REGX52.H>
#include " LCD1602.h"
#include " DS1302.h"
#include " Delay.h"
#include " Key.h"
#include " Timer0.h"unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;void TimeShow(void)
{DS1302_ReadTime();LCD_ShowNum(1,1,DS1302_Time[0],2);LCD_ShowNum(1,4,DS1302_Time[1],2);LCD_ShowNum(1,7,DS1302_Time[2],2);LCD_ShowNum(2,1,DS1302_Time[3],2);LCD_ShowNum(2,4,DS1302_Time[4],2);LCD_ShowNum(2,7,DS1302_Time[5],2);
}void TimeSet(void)
{if(KeyNum==2){TimeSetSelect++;TimeSetSelect%=6; //大于5越界取余0的進階寫法}
if(KeyNum==3){DS1302_Time[TimeSetSelect]++;if(DS1302_Time[0]>99){DS1302_Time[0]=0;}if(DS1302_Time[1]>12){DS1302_Time[1]=1;}if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 || DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12){if(DS1302_Time[2]>31){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11){if(DS1302_Time[2]>30){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]>29){DS1302_Time[2]=1;}}else{if(DS1302_Time[2]>28){DS1302_Time[2]=1;}}}if(DS1302_Time[3]>23){DS1302_Time[3]=0;}if(DS1302_Time[4]>59){DS1302_Time[4]=0;}if(DS1302_Time[5]>59){DS1302_Time[5]=0;}}if(KeyNum==4){DS1302_Time[TimeSetSelect]--;if(DS1302_Time[0]<0){DS1302_Time[0]=99;}if(DS1302_Time[1]<1){DS1302_Time[1]=12;}if( DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7 || DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12){if(DS1302_Time[2]<1){DS1302_Time[2]=31;}if(DS1302_Time[2]>31){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11){if(DS1302_Time[2]<1){DS1302_Time[2]=30;}if(DS1302_Time[2]>30){DS1302_Time[2]=1;}}else if(DS1302_Time[1]==2){if(DS1302_Time[0]%4==0){if(DS1302_Time[2]<1){DS1302_Time[2]=29;}if(DS1302_Time[2]>29){DS1302_Time[2]=1;}}else{if(DS1302_Time[2]<1){DS1302_Time[2]=28;}if(DS1302_Time[2]>28){DS1302_Time[2]=1;}}}if(DS1302_Time[3]<0){DS1302_Time[3]=23;}if(DS1302_Time[4]<0){DS1302_Time[4]=59;}if(DS1302_Time[5]<0){DS1302_Time[5]=59;}}if(TimeSetSelect==0&&TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}else {LCD_ShowNum(1,1,DS1302_Time[0],2);}if(TimeSetSelect==1&&TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}else {LCD_ShowNum(1,4,DS1302_Time[1],2);}if(TimeSetSelect==2&&TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}else {LCD_ShowNum(1,7,DS1302_Time[2],2);}if(TimeSetSelect==3&&TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}else {LCD_ShowNum(2,1,DS1302_Time[3],2);}if(TimeSetSelect==4&&TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}else {LCD_ShowNum(2,4,DS1302_Time[4],2);}if(TimeSetSelect==5&&TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}else {LCD_ShowNum(2,7,DS1302_Time[5],2);}}void main()
{DS1302_Init();LCD_Init();Timer0Init();LCD_ShowString(1,1," - - ");LCD_ShowString(2,1," : : ");DS1302_SetTime();while(1){KeyNum=Key();if(KeyNum==1){if(MODE==0){MODE=1;TimeSetSelect=0;}else if(MODE==1){MODE=0;DS1302_SetTime();}}switch(MODE){case 0:TimeShow();break;case 1:TimeSet();break;}}}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x18; //設置定時初值TH0 = 0xFC; //設置定時初值T0Count++;if(T0Count>=500){T0Count=0;TimeSetFlashFlag=!TimeSetFlashFlag;}}
這代碼還有一個缺陷就是按下按鍵的時候會停止時間
就是我們在寫Key()函數時,用到了while死循環,但是為了簡單應用只能這樣
unsigned int Key()
{unsigned char KeyNumber=0;if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}return KeyNumber;
}