江科大51單片機筆記【9】DS1302時鐘可調時鐘(下)

在寫代碼前,記得把上一節的跳線帽給插回去,不然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;	
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/71724.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/71724.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/71724.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

電商行業門店管理軟件架構設計與數據可視化實踐

一、行業痛點與核心訴求 在電商多平臺運營成為主流的背景下,企業普遍面臨三大管理難題: ?數據碎片化:某頭部服飾品牌2023年運營報告顯示,其分布在8個平臺的162家門店,日均產生23萬條訂單數據,但財務部門需要5個工作日才能完成跨平臺利潤核算。?成本核算失真:行業調研…

創新算法!BKA-Transformer-BiLSTM黑翅鳶優化算法多變量時間序列預測

創新算法&#xff01;BKA-Transformer-BiLSTM黑翅鳶優化算法多變量時間序列預測 目錄 創新算法&#xff01;BKA-Transformer-BiLSTM黑翅鳶優化算法多變量時間序列預測預測效果基本介紹BKA-Transformer-BiLSTM黑翅鳶優化算法多變量時間序列預測一、引言1.1、研究背景和意義1.2、…

leetcode 95.不同的二叉搜索樹 Ⅱ

首先分析一下什么是二叉搜索樹。因為我本科學習數據結構的時候就是單純背了一下題庫&#xff0c;考試非常簡單。現在額外補充學一些之前自己沒有學過的內容。有序向量可以二分查找&#xff0c;列表可以快速插入和刪除。二叉搜索樹可以實現按照關鍵碼訪問。call by key .數據表現…

數據安全防線:備份文件的重要性與自動化實踐

在數字化時代&#xff0c;信息已成為企業運營和個人生活的核心資源。無論是企業的核心數據、客戶的敏感信息&#xff0c;還是個人的珍貴照片、重要文檔&#xff0c;這些數據一旦丟失或受損&#xff0c;都可能帶來不可估量的損失。因此&#xff0c;備份文件的重要性不言而喻&…

碰一碰發視頻系統之寫卡功能開發了,支持OEM

一、引言 在碰一碰發視頻系統中&#xff0c;NFC&#xff08;Near Field Communication&#xff0c;近場通信&#xff09;技術扮演著關鍵角色。其中&#xff0c;寫卡功能是實現用戶與系統便捷交互的重要環節&#xff0c;通過將特定的視頻相關信息寫入 NFC 標簽&#xff0c;用戶…

【數據結構初階第十八節】八大排序系列(上篇)—[詳細動態圖解+代碼解析]

看似不起眼的日復一日&#xff0c;總會在某一天讓你看到堅持的意義。??????云邊有個稻草人-CSDN博客 hello&#xff0c;好久不見&#xff01; 目錄 一. 排序的概念及運用 1. 概念 2. 運用 3. 常見排序算法 二. 實現常見排序算法 1. 插入排序 &#xff08;1&…

python爬蟲系列課程8:js瀏覽器window對象屬性

python爬蟲系列課程8:js瀏覽器window對象屬性 一、JavaScript的組成二、document常見屬性對象三、navigator對象一、JavaScript的組成 JavaScript可以分為三個部分:ECMAScript標準、DOM、BOM。 ECMAScript標準:即JS的基本語法,JavaScript的核心,描述了語言的基本語法和數…

快速使用PPASR V3版不能語音識別框架

前言 本文章主要介紹如何快速使用PPASR語音識別框架訓練和推理&#xff0c;本文將致力于最簡單的方式去介紹使用&#xff0c;如果使用更進階功能&#xff0c;還需要從源碼去看文檔。僅需三行代碼即可實現訓練和推理。 源碼地址&#xff1a;https://github.com/yeyupiaoling/P…

cannon g3810打印機設置

現在AI這么厲害&#xff0c;是不是很少人來這里搜索資料了。 不過我還是寫一下。 買了一臺cannon g3810打印機。一直都用USB打印&#xff0c;今天突然想用手機打印。于是又折騰了兩個小時&#xff0c;終于折騰完了。 步驟如下&#xff1a; [1]打開官網&#xff0c;下載佳能…

使用 Arduino 和 ThingSpeak 通過 Internet 進行心跳監測

使用 Arduino 和 ThingSpeak 通過 Internet 進行心跳監測 在這個項目中,我們將使用 Arduino 制作一個心跳檢測和監測系統,該系統將使用脈搏傳感器檢測心跳,并在與其連接的 LCD 上顯示 BPM(每分鐘心跳次數)讀數。它還將使用 Wi-Fi 模塊ESP8266將讀數發送到 ThingSpeak 服務…

vulnhub靶場之【digitalworld.local系列】的snakeoil靶機

前言 靶機&#xff1a;digitalworld.local-snakeoil&#xff0c;IP地址為192.168.10.11 攻擊&#xff1a;kali&#xff0c;IP地址為192.168.10.6 kali采用VMware虛擬機&#xff0c;靶機選擇使用VMware打開文件&#xff0c;都選擇橋接網絡 這里官方給的有兩種方式&#xff0…

自行車的主要品牌

一、國際知名品牌&#xff08;專注運動與高端市場&#xff09; 捷安特&#xff08;GIANT&#xff09; 臺灣品牌&#xff0c;全球最大自行車制造商之一&#xff0c;覆蓋山地車、公路車、通勤車等多品類。 美利達&#xff08;MERIDA&#xff09; 臺灣品牌&#xff0c;以山地車…

C語言(隊列)

1、隊列的原理和作用 1、1 隊列的原理 隊列的原理其實就像一個管道&#xff0c;如果我們不斷的往管道里塞乒乓球&#xff0c;每個乒乓球在管道里就會排列一條隊列&#xff0c;先進去的乒乓球會先出來&#xff0c;這個就是隊列先進先出的規則 球從左邊進去的動作叫入列&#xf…

【C++算法】AVL樹的平衡之美:從理論到C++高效實現

AVL樹是一種自平衡二叉搜索樹,解決了普通二叉搜索樹在數據傾斜時的性能退化問題。本文深入探討了AVL樹的理論基礎,包括平衡因子的定義、旋轉操作的數學推導,并通過LaTeX公式分析其時間復雜度。接著,我們用C++實現了一個完整的AVL樹,包括插入、刪除和平衡調整的詳細代碼,附…

黑金風格人像靜物戶外旅拍Lr調色教程,手機濾鏡PS+Lightroom預設下載!

調色教程 針對人像、靜物以及戶外旅拍照片&#xff0c;運用 Lightroom 軟件進行風格化調色工作。旨在通過軟件中的多種工具&#xff0c;如基本參數調整、HSL&#xff08;色相、飽和度、明亮度&#xff09;調整、曲線工具等改變照片原本的色彩、明度、對比度等屬性&#xff0c;將…

ESP8266 NodeMCU 與 Atmega16 微控制器連接以發送電子郵件

NodeMCU ESP8266 AVR 微控制器 ATmega16 的接口 Atmega16 是一款低成本的 8 位微控制器,比以前版本的微控制器具有更多的 GPIO。它具有所有常用的通信協議,如 UART、USART、SPI 和 I2C。由于其廣泛的社區支持和簡單性,它在機器人、汽車和自動化行業有廣泛的應用。 Atmega1…

【Hadoop】詳解HDFS

Hadoop 分布式文件系統(HDFS)被設計成適合運行在通用硬件上的分布式文件系統&#xff0c;它是一個高度容錯性的系統&#xff0c;適合部署在廉價的機器上&#xff0c;能夠提供高吞吐量的數據訪問&#xff0c;非常適合大規模數據集上的應用。為了做到可靠性&#xff0c;HDFS創建了…

2025 批量下載市場高標解讀/配置喵/wangdizhe 雪球帖子/文章導出excel和pdf

之前分享過文章2025 批量下載雪球和東方財富文章導出excel和pdf &#xff0c;今天整理分享下我下載過的一些雪球文章。 第1個號市場高標解讀 抓取下載的所有帖子excel數據包含文章日期&#xff0c;文章標題&#xff0c;文章鏈接&#xff0c;文章簡介&#xff0c;點贊數&#…

2022年《申論》第二題(河北A卷)

材料&#xff1a; “社區很大&#xff0c;共有安置房148棟&#xff0c;安置人口2.9萬人。人員眾多&#xff0c;而且原來都來自農村&#xff0c;群眾生活環境變化大&#xff0c;不適應。”春林易地搬遷安置點建成使用后&#xff0c;老單便來這里擔任春林街道辦主任。如何有效治…

Qt中實現多個QMainWindow同時顯示

在Qt中實現多個QMainWindow同時顯示&#xff0c;可通過以下方法實現&#xff1a; 一、直接顯示多個實例 必須使用new創建堆對象&#xff0c;避免棧對象因作用域結束被銷毀?。 int main(int argc, char *argv[]) {QApplication a(argc, argv);// 創建兩個獨立的主窗口QMainW…