国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

RTC實(shí)時(shí)時(shí)鐘源碼分析

這篇具有很好參考價(jià)值的文章主要介紹了RTC實(shí)時(shí)時(shí)鐘源碼分析。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

1.先來(lái)看一下RTC的配置過(guò)程

RTC實(shí)時(shí)時(shí)鐘源碼分析

?2.RTC源碼講解

我們的工程中加入了 rtc.c 源文件和 rtc.h頭文件,同時(shí),引入了 stm32f10x_rtc.c 和 stm32f10x_bkp.c 庫(kù)文件。

說(shuō)明,首先是 RTC_Init,其代碼如下:

//實(shí)時(shí)時(shí)鐘配置
//初始化 RTC 時(shí)鐘,同時(shí)檢測(cè)時(shí)鐘是否工作正常
//BKP->DR1 用于保存是否第一次配置的設(shè)置
//返回 0:正常
//其他:錯(cuò)誤代碼
u8 RTC_Init(void)
{
u8 temp=0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR |
RCC_APB1Periph_BKP, ENABLE); //使能 PWR 和 BKP 外設(shè)時(shí)鐘。這個(gè)使能了時(shí)鐘和后備區(qū)域寄存器
PWR_BackupAccessCmd(ENABLE); //使能后備寄存器訪問(wèn)
//檢查是不是第一次配置RTC,如果不是的話就要進(jìn)行復(fù)位等操作
if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //從指定的后備寄存器中
//讀出數(shù)據(jù):讀出了與寫入的指定數(shù)據(jù)不相等
{ 
BKP_DeInit(); //③復(fù)位備份區(qū)域
RCC_LSEConfig(RCC_LSE_ON);  //設(shè)置外部低速晶振(LSE)
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //檢查指定的
//RCC 標(biāo)志位設(shè)置與否,等待低速晶振就緒
{       //在這里的這個(gè)for循環(huán)主要是為了防止LSE外部時(shí)鐘沒(méi)有配置成功,得多次進(jìn)行檢測(cè)才行
temp++;
delay_ms(10);
}
if(temp>=250)return 1;//初始化時(shí)鐘失敗,晶振有問(wèn)題 
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //設(shè)置 RTC 時(shí)鐘
//(RTCCLK),選擇 LSE 作為 RTC 時(shí)鐘
RCC_RTCCLKCmd(ENABLE); //使能 RTC 時(shí)鐘
RTC_WaitForLastTask();  //等待最近一次對(duì) RTC 寄存器的寫操作完成
RTC_WaitForSynchro(); //等待 RTC 寄存器同步
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中斷
RTC_WaitForLastTask();  //等待最近一次對(duì) RTC 寄存器的寫操作完成
RTC_EnterConfigMode(); // 允許配置,只有執(zhí)行了這個(gè)函數(shù)才能對(duì)RTC里面的寄存器進(jìn)行操作
RTC_SetPrescaler(32767); //設(shè)置 RTC 預(yù)分頻的值
RTC_WaitForLastTask();  //等待最近一次對(duì) RTC 寄存器的寫操作完成
RTC_Set(2009,12,2,10,0,55); //設(shè)置時(shí)間
RTC_ExitConfigMode(); //退出配置模式
BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后備寄存器中
//寫入用戶程序數(shù)據(jù) 0x5050,相當(dāng)于恢復(fù)了原始的狀態(tài)
}
else//系統(tǒng)繼續(xù)計(jì)時(shí)
{
RTC_WaitForSynchro(); //等待最近一次對(duì) RTC 寄存器的寫操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中斷
RTC_WaitForLastTask();  //等待最近一次對(duì) RTC 寄存器的寫操作完成
}
RTC_NVIC_Config(); //RCT 中斷分組設(shè)置 
RTC_Get(); //更新時(shí)間 
return 0; //ok
}

該函數(shù)用來(lái)初始化 RTC 時(shí)鐘,但是只在第一次的時(shí)候設(shè)置時(shí)間,以后如果重新上電/復(fù)位都不會(huì)再進(jìn)行時(shí)間設(shè)置了(前提是備份電池有電),在第一次配置的時(shí)候,我們是按照上面介紹的 RTC 初始化步驟來(lái)做的,這里就不在多說(shuō)了,這里我們?cè)O(shè)置時(shí)間是通過(guò)時(shí)間設(shè)置函數(shù)RTC_Set(2014,3,8,22,10,55);來(lái)實(shí)現(xiàn)的,這里我們默認(rèn)將時(shí)間設(shè)置為 2014 年 3 月 8 日 22 點(diǎn) 10 分55 秒。在設(shè)置好時(shí)間之后,我們通過(guò)語(yǔ)句 BKP_WriteBackupRegister(BKP_DR1, 0X5050);向
BKP->DR1 寫入標(biāo)志字 0X5050,用于標(biāo)記時(shí)間已經(jīng)被設(shè)置了。這樣,再次發(fā)生復(fù)位的時(shí)候,該函數(shù)通過(guò)語(yǔ)句 if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)判斷 BKP->DR1 的值,來(lái)決定是不是需要重新設(shè)置時(shí)間,如果不需要設(shè)置,則跳過(guò)時(shí)間設(shè)置,僅僅使能秒鐘中斷一下,就進(jìn)行中斷分組,然后返回了。這樣不會(huì)重復(fù)設(shè)置時(shí)間,使得我們?cè)O(shè)置的時(shí)間不會(huì)因復(fù)位或者斷電而丟失。
該函數(shù)還有返回值,返回值代表此次操作的成功與否,如果返回 0,則代表初始化 RTC 成功,如果返回值非零則代表錯(cuò)誤代碼了。

//設(shè)置時(shí)鐘
//把輸入的時(shí)鐘轉(zhuǎn)換為秒鐘
//以 1970 年 1 月 1 日為基準(zhǔn)
//1970~2099 年為合法年份
//返回值:0,成功;其他:錯(cuò)誤代碼.
//平年的月份日期表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
//syear,smon,sday,hour,min,sec:年月日時(shí)分秒
//返回值:設(shè)置結(jié)果。0,成功;1,失敗。
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
u16 t;
u32 seccount=0;
if(syear<1970||syear>2099)return 1; 
for(t=1970;t<syear;t++) //把所有年份的秒鐘相加
{
if(Is_Leap_Year(t))seccount+=31622400;//閏年的秒鐘數(shù)
else seccount+=31536000;  //平年的秒鐘數(shù)
}
smon-=1;
for(t=0;t<smon;t++)  //把前面月份的秒鐘數(shù)相加
{
seccount+=(u32)mon_table[t]*86400;//月份秒鐘數(shù)相加
if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//閏年 2 月份增加一天的秒鐘數(shù)
}
seccount+=(u32)(sday-1)*86400; //把前面日期的秒鐘數(shù)相加
seccount+=(u32)hour*3600; //小時(shí)秒鐘數(shù)
seccount+=(u32)min*60;  //分鐘秒鐘數(shù)
seccount+=sec;  //最后的秒鐘加上去 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR |
RCC_APB1Periph_BKP, ENABLE); //使能 PWR 和 BKP 外設(shè)時(shí)鐘
PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后備寄存器訪問(wèn)
RTC_SetCounter(seccount); //設(shè)置 RTC 計(jì)數(shù)器的值
RTC_WaitForLastTask();  //等待最近一次對(duì) RTC 寄存器的寫操作完成
return 0;
}

該函數(shù)用于設(shè)置時(shí)間,把我們輸入的時(shí)間,轉(zhuǎn)換為以 1970 年 1 月 1 日 0 時(shí) 0 分 0 秒當(dāng)做起始時(shí)間的秒鐘信號(hào),后續(xù)的計(jì)算都以這個(gè)時(shí)間為基準(zhǔn)的,由于 STM32 的秒鐘計(jì)數(shù)器可以保存136 年的秒鐘數(shù)據(jù),這樣我們可以計(jì)時(shí)到 2106 年。
接著,我們介紹一下 RTC_Get 函數(shù),該函數(shù)用于獲取時(shí)間和日期等數(shù)據(jù),其代碼如上:
?

//得到當(dāng)前的時(shí)間,結(jié)果保存在 calendar 結(jié)構(gòu)體里面
//返回值:0,成功;其他:錯(cuò)誤代碼.
u8 RTC_Get(void)
{
static u16 daycnt=0;
u32 timecount=0; u32 temp=0; u16 temp1=0; 
timecount=RTC_GetCounter(); 
temp=timecount/86400; //得到天數(shù)(秒鐘數(shù)對(duì)應(yīng)的)
if(daycnt!=temp)//超過(guò)一天了
{ 
daycnt=temp;
temp1=1970; //從 1970 年開始
while(temp>=365)
{ 
if(Is_Leap_Year(temp1))//是閏年
{
if(temp>=366)temp-=366;//閏年的秒鐘數(shù)
else break;
}
else temp-=365;  //平年
temp1++;
}
calendar.w_year=temp1;//得到年份
temp1=0;
while(temp>=28)//超過(guò)了一個(gè)月
{
if(Is_Leap_Year(calendar.w_year)&&temp1==1)//當(dāng)年是不是閏年/2 月份
{
if(temp>=29)temp-=29;//閏年的秒鐘數(shù)
else break;
}
else
{
if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
else break;
}
temp1++;
}
calendar.w_month=temp1+1; //得到月份
calendar.w_date=temp+1; //得到日期
}
temp=timecount%86400; //得到秒鐘數(shù)
calendar.hour=temp/3600; //小時(shí)
calendar.min=(temp%3600)/60; //分鐘 
calendar.sec=(temp%3600)%60; //秒鐘
calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);
return 0;
}

函數(shù)其實(shí)就是將存儲(chǔ)在秒鐘寄存器 RTC->CNTH 和 RTC->CNTL 中的秒鐘數(shù)據(jù)轉(zhuǎn)換為真正的時(shí)間和日期。該代碼還用到了一個(gè) calendar 的結(jié)構(gòu)體,calendar 是我們?cè)?rtc.h 里面將要定義的一個(gè)時(shí)間結(jié)構(gòu)體,用來(lái)存放時(shí)鐘的年月日時(shí)分秒等信息。因?yàn)?STM32 的 RTC 只有秒鐘計(jì)數(shù)器,而年月日,時(shí)分秒這些需要我們自己軟件計(jì)算。我們把計(jì)算好的值保存在 calendar 里面,方便其他程序調(diào)用。

最后介紹一下秒鐘中斷服務(wù)函數(shù),該函數(shù)代碼如下:
?

//RTC 時(shí)鐘中斷
//每秒觸發(fā)一次
void RTC_IRQHandler(void)
{ 
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒鐘中斷
{ 
RTC_Get();//更新時(shí)間
}
if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//鬧鐘中斷
{
RTC_ClearITPendingBit(RTC_IT_ALR);  //清鬧鐘中斷
}
RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);  //清鬧鐘中斷
RTC_WaitForLastTask(); 
}

此部分代碼比較簡(jiǎn)單,我們通過(guò) RTC_GetITStatus 函數(shù)來(lái)判斷發(fā)生的是何種中斷,如果是秒鐘中斷,則執(zhí)行一次時(shí)間的計(jì)算,獲得最新時(shí)間。從而,我們可以在 calendar 里面讀到時(shí)間、日期等信息。

接下來(lái)看看 rtc.h 內(nèi)容如下:

#ifndef __RTC_H
#define __RTC_H
//時(shí)間結(jié)構(gòu)體
typedef struct
{
vu8 hour;
vu8 min;
vu8 sec;
//公歷日月年周
vu16 w_year;
vu8 w_month;
vu8 w_date;
vu8 week; 
}_calendar_obj; 
extern _calendar_obj calendar;  //日歷結(jié)構(gòu)體
void Disp_Time(u8 x,u8 y,u8 size);  //在制定位置開始顯示時(shí)間
void Disp_Week(u8 x,u8 y,u8 size,u8 lang); //在指定位置顯示星期
u8 RTC_Init(void); //初始化 RTC,返回 0,失敗;1,成功;
u8 Is_Leap_Year(u16 year); //平年,閏年判斷
u8 RTC_Get(void); //更新時(shí)間
u8 RTC_Get_Week(u16 year,u8 month,u8 day);
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//設(shè)置時(shí)間 
#endif

從上面代碼可以看到_calendar_obj 結(jié)構(gòu)體所包含的東西,是一個(gè)完整的公歷信息,包括年、月、日、周、時(shí)、分、秒等 7 個(gè)元素。我們以后要知道當(dāng)前時(shí)間,只需要通過(guò) RTC_Get 函數(shù),執(zhí)行時(shí)鐘轉(zhuǎn)換,然后就可以從 calendar 里面讀出當(dāng)前的公歷時(shí)間了。

最后來(lái)看看主函數(shù)代碼:
?

int main(void)
{ 
u8 t;
delay_init(); //延時(shí)函數(shù)初始化 
uart_init(9600);  //串口初始化為 9600
LED_Init();  //初始化與 LED 連接的硬件接口
LCD_Init();  //初始化 LCD
usmart_dev.init(72);  //初始化 USMART
POINT_COLOR=RED;//設(shè)置字體為紅色
LCD_ShowString(60,50,200,16,16,"Mini STM32");
LCD_ShowString(60,70,200,16,16,"RTC TEST"); 
LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(60,110,200,16,16,"2014/3/8");
while(RTC_Init()) //RTC 初始化 ,一定要初始化成功
{
LCD_ShowString(60,130,200,16,16,"RTC ERROR! "); delay_ms(800);
LCD_ShowString(60,130,200,16,16,"RTC Trying...");
} 
//顯示時(shí)間
POINT_COLOR=BLUE;//設(shè)置字體為藍(lán)色
LCD_ShowString(60,130,200,16,16," - - "); 
LCD_ShowString(60,162,200,16,16," : : ");
while(1)
{ 
if(t!=calendar.sec)
{
t=calendar.sec;
LCD_ShowNum(60,130,calendar.w_year,4,16);
LCD_ShowNum(100,130,calendar.w_month,2,16); 
LCD_ShowNum(124,130,calendar.w_date,2,16);
switch(calendar.week)
{
case 0: LCD_ShowString(60,148,200,16,16,"Sunday "); break; 
case 1: LCD_ShowString(60,148,200,16,16,"Monday "); break; 
case 2: LCD_ShowString(60,148,200,16,16,"Tuesday "); break; 
case 3: LCD_ShowString(60,148,200,16,16,"Wednesday");break;
case 4: LCD_ShowString(60,148,200,16,16,"Thursday ");break;
case 5: LCD_ShowString(60,148,200,16,16,"Friday ");break;
case 6: LCD_ShowString(60,148,200,16,16,"Saturday ");break;
}
LCD_ShowNum(60,162,calendar.hour,2,16); 
LCD_ShowNum(84,162,calendar.min,2,16);
LCD_ShowNum(108,162,calendar.sec,2,16);
LED0=!LED0;
} 
delay_ms(10);
};
}

這部分代碼就不再需要詳細(xì)解釋了,在包含了 rtc.h 之后,通過(guò)判斷 calendar.sec 是否改變來(lái)決定要不要更新時(shí)間顯示。同時(shí)我們?cè)O(shè)置 LED0 每 2 秒鐘閃爍一次,用來(lái)提示程序已經(jīng)開始跑了。
為了方便設(shè)置時(shí)間,我們?cè)?usmart_config.c 里面,修改 usmart_nametab 如下:
?

struct _m_usmart_nametab usmart_nametab[]=
{
#if USMART_USE_WRFUNS==1 //如果使能了讀寫操作
(void*)read_addr,"u32 read_addr(u32 addr)",
(void*)write_addr,"void write_addr(u32 addr,u32 val)", 
#endif 
(void*)delay_ms,"void delay_ms(u16 nms)",
(void*)delay_us,"void delay_us(u32 nus)",
(void*)RTC_Set,"u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)",
};

將 RTC_Set 加入了 usmart,同時(shí)去掉了上一章的一些函數(shù)(減少代碼量),這樣通過(guò)串口就可以直接設(shè)置 RTC 時(shí)間了。
至此,RTC 實(shí)時(shí)時(shí)鐘的軟件設(shè)計(jì)就完成了,接下來(lái)就讓我們來(lái)檢驗(yàn)一下,我們的程序是否正確了。

整體函數(shù)代碼:文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-453017.html

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "rtc.h" 		    
// 精英 STM32開發(fā)板
//RTC實(shí)時(shí)時(shí)鐘 驅(qū)動(dòng)代碼			 
//正點(diǎn)原子@ALIENTEK
//2010/6/6
	   
_calendar_obj calendar;//時(shí)鐘結(jié)構(gòu)體 
 
static void RTC_NVIC_Config(void)
{	
  NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;		//RTC全局中斷
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//先占優(yōu)先級(jí)1位,從優(yōu)先級(jí)3位
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	//先占優(yōu)先級(jí)0位,從優(yōu)先級(jí)4位
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		//使能該通道中斷
	NVIC_Init(&NVIC_InitStructure);		//根據(jù)NVIC_InitStruct中指定的參數(shù)初始化外設(shè)NVIC寄存器
}

//實(shí)時(shí)時(shí)鐘配置
//初始化RTC時(shí)鐘,同時(shí)檢測(cè)時(shí)鐘是否工作正常
//BKP->DR1用于保存是否第一次配置的設(shè)置
//返回0:正常
//其他:錯(cuò)誤代碼

u8 RTC_Init(void)
{
	//檢查是不是第一次配置時(shí)鐘
	u8 temp=0;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外設(shè)時(shí)鐘   
	PWR_BackupAccessCmd(ENABLE);	//使能后備寄存器訪問(wèn)  
	if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)		//從指定的后備寄存器中讀出數(shù)據(jù):讀出了與寫入的指定數(shù)據(jù)不相同
		{	 			 
		BKP_DeInit();	//復(fù)位備份區(qū)域 	
		RCC_LSEConfig(RCC_LSE_ON);	//設(shè)置外部低速晶振(LSE),使用外設(shè)低速晶振
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)	//檢查指定的RCC標(biāo)志位設(shè)置與否,等待低速晶振就緒
			{
			temp++;
			delay_ms(10);
			}
		if(temp>=250)return 1;//初始化時(shí)鐘失敗,晶振有問(wèn)題	    
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//設(shè)置RTC時(shí)鐘(RTCCLK),選擇LSE作為RTC時(shí)鐘    
		RCC_RTCCLKCmd(ENABLE);	//使能RTC時(shí)鐘  
		RTC_WaitForLastTask();	//等待最近一次對(duì)RTC寄存器的寫操作完成
		RTC_WaitForSynchro();		//等待RTC寄存器同步  
		RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中斷
		RTC_WaitForLastTask();	//等待最近一次對(duì)RTC寄存器的寫操作完成
		RTC_EnterConfigMode();/// 允許配置	
		RTC_SetPrescaler(32767); //設(shè)置RTC預(yù)分頻的值
		RTC_WaitForLastTask();	//等待最近一次對(duì)RTC寄存器的寫操作完成
		RTC_Set(2015,1,14,17,42,55);  //設(shè)置時(shí)間	
		RTC_ExitConfigMode(); //退出配置模式  
		BKP_WriteBackupRegister(BKP_DR1, 0X5050);	//向指定的后備寄存器中寫入用戶程序數(shù)據(jù)
		}
	else//系統(tǒng)繼續(xù)計(jì)時(shí)
		{

		RTC_WaitForSynchro();	//等待最近一次對(duì)RTC寄存器的寫操作完成
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能RTC秒中斷
		RTC_WaitForLastTask();	//等待最近一次對(duì)RTC寄存器的寫操作完成
		}
	RTC_NVIC_Config();//RCT中斷分組設(shè)置		    				     
	RTC_Get();//更新時(shí)間	
	return 0; //ok

}		 				    
//RTC時(shí)鐘中斷
//每秒觸發(fā)一次  
//extern u16 tcnt; 
void RTC_IRQHandler(void)
{		 
	if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//一秒鐘中斷
	{							
		RTC_Get();//更新時(shí)間   
 	}
	if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//鬧鐘中斷
	{
		RTC_ClearITPendingBit(RTC_IT_ALR);		//清鬧鐘中斷	  	
	  RTC_Get();				//更新時(shí)間   
  	printf("Alarm Time:%d-%d-%d %d:%d:%d\n",calendar.w_year,calendar.w_month,calendar.w_date,calendar.hour,calendar.min,calendar.sec);//輸出鬧鈴時(shí)間	
		
  	} 				  								 
	RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);		//清鬧鐘中斷
	RTC_WaitForLastTask();	  	    						 	   	 
}
//判斷是否是閏年函數(shù)
//月份   1  2  3  4  5  6  7  8  9  10 11 12
//閏年   31 29 31 30 31 30 31 31 30 31 30 31
//非閏年 31 28 31 30 31 30 31 31 30 31 30 31
//輸入:年份
//輸出:該年份是不是閏年.1,是.0,不是
u8 Is_Leap_Year(u16 year)
{			  
	if(year%4==0) //必須能被4整除
	{ 
		if(year%100==0) 
		{ 
			if(year%400==0)return 1;//如果以00結(jié)尾,還要能被400整除 	   
			else return 0;   
		}else return 1;   
	}else return 0;	
}	 			   
//設(shè)置時(shí)鐘
//把輸入的時(shí)鐘轉(zhuǎn)換為秒鐘
//以1970年1月1日為基準(zhǔn)
//1970~2099年為合法年份
//返回值:0,成功;其他:錯(cuò)誤代碼.
//月份數(shù)據(jù)表											 
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正數(shù)據(jù)表	  
//平年的月份日期表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
	u16 t;
	u32 seccount=0;
	if(syear<1970||syear>2099)return 1;	   
	for(t=1970;t<syear;t++)	//把所有年份的秒鐘相加
	{
		if(Is_Leap_Year(t))seccount+=31622400;//閏年的秒鐘數(shù)
		else seccount+=31536000;			  //平年的秒鐘數(shù)
	}
	smon-=1;
	for(t=0;t<smon;t++)	   //把前面月份的秒鐘數(shù)相加
	{
		seccount+=(u32)mon_table[t]*86400;//月份秒鐘數(shù)相加
		if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//閏年2月份增加一天的秒鐘數(shù)	   
	}
	seccount+=(u32)(sday-1)*86400;//把前面日期的秒鐘數(shù)相加 
	seccount+=(u32)hour*3600;//小時(shí)秒鐘數(shù)
    seccount+=(u32)min*60;	 //分鐘秒鐘數(shù)
	seccount+=sec;//最后的秒鐘加上去

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外設(shè)時(shí)鐘  
	PWR_BackupAccessCmd(ENABLE);	//使能RTC和后備寄存器訪問(wèn) 
	RTC_SetCounter(seccount);	//設(shè)置RTC計(jì)數(shù)器的值

	RTC_WaitForLastTask();	//等待最近一次對(duì)RTC寄存器的寫操作完成  	
	return 0;	    
}

//初始化鬧鐘		  
//以1970年1月1日為基準(zhǔn)
//1970~2099年為合法年份
//syear,smon,sday,hour,min,sec:鬧鐘的年月日時(shí)分秒   
//返回值:0,成功;其他:錯(cuò)誤代碼.
u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
{
	u16 t;
	u32 seccount=0;
	if(syear<1970||syear>2099)return 1;	   
	for(t=1970;t<syear;t++)	//把所有年份的秒鐘相加
	{
		if(Is_Leap_Year(t))seccount+=31622400;//閏年的秒鐘數(shù)
		else seccount+=31536000;			  //平年的秒鐘數(shù)
	}
	smon-=1;
	for(t=0;t<smon;t++)	   //把前面月份的秒鐘數(shù)相加
	{
		seccount+=(u32)mon_table[t]*86400;//月份秒鐘數(shù)相加
		if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//閏年2月份增加一天的秒鐘數(shù)	   
	}
	seccount+=(u32)(sday-1)*86400;//把前面日期的秒鐘數(shù)相加 
	seccount+=(u32)hour*3600;//小時(shí)秒鐘數(shù)
    seccount+=(u32)min*60;	 //分鐘秒鐘數(shù)
	seccount+=sec;//最后的秒鐘加上去 			    
	//設(shè)置時(shí)鐘
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外設(shè)時(shí)鐘   
	PWR_BackupAccessCmd(ENABLE);	//使能后備寄存器訪問(wèn)  
	//上面三步是必須的!
	
	RTC_SetAlarm(seccount);
 
	RTC_WaitForLastTask();	//等待最近一次對(duì)RTC寄存器的寫操作完成  	
	
	return 0;	    
}


//得到當(dāng)前的時(shí)間
//返回值:0,成功;其他:錯(cuò)誤代碼.
u8 RTC_Get(void)
{
	static u16 daycnt=0;
	u32 timecount=0; 
	u32 temp=0;
	u16 temp1=0;	  
    timecount=RTC_GetCounter();	 
 	temp=timecount/86400;   //得到天數(shù)(秒鐘數(shù)對(duì)應(yīng)的)
	if(daycnt!=temp)//超過(guò)一天了
	{	  
		daycnt=temp;
		temp1=1970;	//從1970年開始
		while(temp>=365)
		{				 
			if(Is_Leap_Year(temp1))//是閏年
			{
				if(temp>=366)temp-=366;//閏年的秒鐘數(shù)
				else {temp1++;break;}  
			}
			else temp-=365;	  //平年 
			temp1++;  
		}   
		calendar.w_year=temp1;//得到年份
		temp1=0;
		while(temp>=28)//超過(guò)了一個(gè)月
		{
			if(Is_Leap_Year(calendar.w_year)&&temp1==1)//當(dāng)年是不是閏年/2月份
			{
				if(temp>=29)temp-=29;//閏年的秒鐘數(shù)
				else break; 
			}
			else 
			{
				if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
				else break;
			}
			temp1++;  
		}
		calendar.w_month=temp1+1;	//得到月份
		calendar.w_date=temp+1;  	//得到日期 
	}
	temp=timecount%86400;     		//得到秒鐘數(shù)   	   
	calendar.hour=temp/3600;     	//小時(shí)
	calendar.min=(temp%3600)/60; 	//分鐘	
	calendar.sec=(temp%3600)%60; 	//秒鐘
	calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//獲取星期   
	return 0;
}	 
//獲得現(xiàn)在是星期幾
//功能描述:輸入公歷日期得到星期(只允許1901-2099年)
//輸入?yún)?shù):公歷年月日 
//返回值:星期號(hào)																						 
u8 RTC_Get_Week(u16 year,u8 month,u8 day)
{	
	u16 temp2;
	u8 yearH,yearL;
	
	yearH=year/100;	yearL=year%100; 
	// 如果為21世紀(jì),年份數(shù)加100  
	if (yearH>19)yearL+=100;
	// 所過(guò)閏年數(shù)只算1900年之后的  
	temp2=yearL+yearL/4;
	temp2=temp2%7; 
	temp2=temp2+day+table_week[month-1];
	if (yearL%4==0&&month<3)temp2--;
	return(temp2%7);
}			  
















到了這里,關(guān)于RTC實(shí)時(shí)時(shí)鐘源碼分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【STM32】RTC(實(shí)時(shí)時(shí)鐘)

    【STM32】RTC(實(shí)時(shí)時(shí)鐘)

    本質(zhì):計(jì)數(shù)器 RTC中斷是外部中斷(EXTI) 當(dāng)VDD掉電的時(shí)候,Vbat可以通過(guò)電源---實(shí)時(shí)計(jì)時(shí) STM32的RTC外設(shè)(Real Time Clock),實(shí)質(zhì)是一個(gè) ? 掉電 ? 后還繼續(xù)運(yùn)行的定時(shí)器。從定時(shí)器的角度來(lái)說(shuō),相對(duì)于通用定時(shí)器TIM外設(shè),它十分簡(jiǎn)單, 只有很純粹的計(jì)時(shí)和觸發(fā)中斷的功能 ;但從

    2024年02月03日
    瀏覽(27)
  • STM32——RTC實(shí)時(shí)時(shí)鐘

    STM32——RTC實(shí)時(shí)時(shí)鐘

    Unix 時(shí)間戳(Unix Timestamp)定義為從UTC/GMT的1970年1月1日0時(shí)0分0秒開始所經(jīng)過(guò)的秒數(shù),不考慮閏秒 時(shí)間戳存儲(chǔ)在一個(gè)秒計(jì)數(shù)器中,秒計(jì)數(shù)器為32位/64位的整型變量 世界上所有時(shí)區(qū)的秒計(jì)數(shù)器相同,不同時(shí)區(qū)通過(guò)添加偏移來(lái)得到當(dāng)?shù)貢r(shí)間 底層使用秒計(jì)數(shù)器可以節(jié)省硬件設(shè)計(jì)電路,

    2024年01月23日
    瀏覽(24)
  • 嵌入式——實(shí)時(shí)時(shí)鐘(RTC)

    嵌入式——實(shí)時(shí)時(shí)鐘(RTC)

    目錄 一、初識(shí)RTC 1.簡(jiǎn)介 2.特性 3.后備寄存器和RTC寄存器特性 二、RTC組成 1.相關(guān)寄存器 (1)控制寄存器高位(RTC_CRH) (2)控制寄存器低位(RTC_CRL) (3)預(yù)分頻裝載寄存器高位(RTC_PRLH) (4)預(yù)分頻裝載寄存器低位(RTC_PRLL) (5)計(jì)數(shù)器寄存器高位(RTC_CNTH) (6)計(jì)數(shù)器

    2024年02月19日
    瀏覽(19)
  • STM32--RTC實(shí)時(shí)時(shí)鐘

    STM32--RTC實(shí)時(shí)時(shí)鐘

    Unix 時(shí)間戳是從1970年1月1日(UTC/GMT的午夜)開始所經(jīng)過(guò)的秒數(shù),不考慮閏秒 。 時(shí)間戳存儲(chǔ)在一個(gè)秒計(jì)數(shù)器中,秒計(jì)數(shù)器為32位/64位的整型變量。 世界上所有時(shí)區(qū)的秒計(jì)數(shù)器相同,不同時(shí)區(qū)通過(guò)添加偏移來(lái)得到當(dāng)?shù)貢r(shí)間。 GMT : GMT(Greenwich Mean Time), 格林威治平時(shí)(也稱格林

    2024年02月10日
    瀏覽(20)
  • STM32-RTC實(shí)時(shí)時(shí)鐘

    STM32-RTC實(shí)時(shí)時(shí)鐘

    目錄 RTC實(shí)時(shí)時(shí)鐘 功能框圖 UNIX時(shí)間戳 初始化結(jié)構(gòu)體 RTC時(shí)間結(jié)構(gòu)體 RTC日期結(jié)構(gòu)體 RTC鬧鐘結(jié)構(gòu)體 進(jìn)入和退出配置函數(shù) 實(shí)驗(yàn)環(huán)節(jié)1:顯示日歷 常規(guī)配置 RTC配置 測(cè)試環(huán)節(jié) 實(shí)驗(yàn)現(xiàn)象 實(shí)驗(yàn)環(huán)節(jié)2:鬧鐘 常規(guī)配置 RTC配置 測(cè)試環(huán)節(jié) 實(shí)驗(yàn)現(xiàn)象 STM32的RTC外設(shè),實(shí)質(zhì)上是一個(gè) 掉電后還繼續(xù)運(yùn)

    2024年02月06日
    瀏覽(26)
  • STM32-實(shí)時(shí)時(shí)鐘RTC-2

    STM32-實(shí)時(shí)時(shí)鐘RTC-2

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    2024年01月20日
    瀏覽(26)
  • STM32-RTC實(shí)時(shí)時(shí)鐘詳解

    STM32-RTC實(shí)時(shí)時(shí)鐘詳解

    RTC的本質(zhì)很簡(jiǎn)單,就是一個(gè)時(shí)鐘經(jīng)過(guò)精確分頻最后得到的一個(gè)1Hz的時(shí)鐘,也可以說(shuō)是計(jì)數(shù)器,其他大部分功能都是基于這個(gè)計(jì)數(shù)器設(shè)計(jì)的數(shù)字邏輯。 本文講的RTC是基于STM32F030來(lái)講的,相比與F1系列的RTC來(lái)說(shuō),M0的將很多原本需要軟件實(shí)現(xiàn)的功能硬件化了,使用起來(lái)更加便利。

    2024年02月04日
    瀏覽(36)
  • 【STM32學(xué)習(xí)】實(shí)時(shí)時(shí)鐘 —— RTC

    【STM32學(xué)習(xí)】實(shí)時(shí)時(shí)鐘 —— RTC

    STM32RTC實(shí)時(shí)時(shí)鐘實(shí)驗(yàn)講解,從入門到放棄 【STM32】RTC休眠喚醒(停機(jī)模式)、獨(dú)立看門狗開啟狀態(tài)下 關(guān)于STM32使用RTC喚醒停止模式的設(shè)置 RTC(Real Time Clock):實(shí)時(shí)時(shí)鐘,是指可以像時(shí)鐘一樣輸出實(shí)際時(shí)間的電子設(shè)備,一般會(huì)是集成電路,因此也稱為時(shí)鐘芯片??傊琑TC只是個(gè)能靠電

    2024年02月01日
    瀏覽(22)
  • STM32基礎(chǔ)10--實(shí)時(shí)時(shí)鐘(RTC)

    STM32基礎(chǔ)10--實(shí)時(shí)時(shí)鐘(RTC)

    ?目錄 前言 RTC框圖 STM32實(shí)時(shí)時(shí)鐘電路 功能需要 STM32CubeMx配置RTC 配置RCC 配置RTC 配置時(shí)間,鬧鐘,喚醒 開啟中斷 設(shè)置中斷優(yōu)先級(jí) 功能代碼實(shí)現(xiàn) STM32Cude生成RTC初始化 自定義觸發(fā)鬧鐘次數(shù)變量? 重寫周期喚醒回調(diào)函數(shù) 重寫鬧鐘中斷函數(shù) ????????在做51單片機(jī)項(xiàng)目時(shí),如果需

    2023年04月11日
    瀏覽(19)
  • STM32學(xué)習(xí)筆記(十二)丨RTC實(shí)時(shí)時(shí)鐘

    STM32學(xué)習(xí)筆記(十二)丨RTC實(shí)時(shí)時(shí)鐘

    ???本次課程采用單片機(jī)型號(hào)為STM32F103C8T6。 ???課程鏈接:江協(xié)科技 STM32入門教程 ??往期筆記鏈接: ??STM32學(xué)習(xí)筆記(一)丨建立工程丨GPIO 通用輸入輸出 ??STM32學(xué)習(xí)筆記(二)丨STM32程序調(diào)試丨OLED的使用 ??STM32學(xué)習(xí)筆記(三)丨中斷系統(tǒng)丨EXTI外部中斷 ??

    2024年02月16日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包