日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

stm32f103 rtc 获取 日历 时钟

發(fā)布時(shí)間:2025/3/21 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 stm32f103 rtc 获取 日历 时钟 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
STM32的RTC實(shí)現(xiàn)日歷功能程序發(fā)布時(shí)間:2011-09-30 14:53:05 ?

STM32的RTC只有一個(gè)32位的計(jì)數(shù)器用來計(jì)時(shí),沒有寄存器來存年月日時(shí)分秒等。通過設(shè)置可以讓這個(gè)計(jì)數(shù)器1秒加1,從0-0XFFFFFFFF大概可以計(jì)時(shí)136年。程序要設(shè)置一個(gè)時(shí)間起點(diǎn)表示0,一般設(shè)置起始時(shí)間為1970-01-01 0:0:0。這是UNIX時(shí)間戳。如果要設(shè)置RTC時(shí)間,如2011-9-30 12:00FAMILY: 宋體">到1970-01-01 0:0:0有多少秒,把這個(gè)值寫到RTC計(jì)數(shù)器就可以了。如果要讀當(dāng)前的年月日時(shí)分秒,先讀出32位RTC計(jì)數(shù)器值,然后以1970-01-01 0:0:0為時(shí)間基點(diǎn),算出當(dāng)前時(shí)間。

為什么要設(shè)置起始時(shí)間為1970-01-01 0:0:0,因?yàn)橛幸粋€(gè)TIME.H文件,里面有寫好的設(shè)置時(shí)間函數(shù),讀時(shí)間函數(shù),使用的參數(shù)就是32位計(jì)數(shù)器。不過我沒有找到這個(gè)文件。不使用這個(gè)文件的函數(shù)的話,起始時(shí)間可以設(shè)為任意值。

直接使用32位計(jì)數(shù)器來計(jì)算時(shí)間的優(yōu)點(diǎn):

1、可以不使用RTC的秒中斷,因?yàn)樵赟TM32掉電時(shí),只有電池供電,這時(shí)RTC在計(jì)數(shù),但是STM32的內(nèi)核中斷應(yīng)該是不能使用的。

2、不用在備份區(qū)保存年月日等參數(shù)。

下面是網(wǎng)上找的程序,我實(shí)際測試過,是正確的。

//時(shí)間結(jié)構(gòu)體

typedef struct

{

?????? u8 hour;

?????? u8 min;

?????? u8 sec;?????????????????

?????? //公歷日月年周

?????? u16 w_year;

?????? u8? w_month;

?????? u8? w_date;

?????? u8? week;????????????

}tm;

tm timer;

/*

?*

?*

?*/

void RTC_Config(void)

{

???? u16 u16_WaitForOscSource;

???? //我們在BKP的后備寄存器1中,存了一個(gè)特殊字符0xA5A5

??? //第一次上電或后備電源掉電后,該寄存器數(shù)據(jù)丟失,

??? //表明RTC數(shù)據(jù)丟失,需要重新配置

??? if (BKP_ReadBackupRegister(BKP_DR1) != 0x5A5A)

??? {

??????? //重新配置RTC

??????? /* Enable PWR and BKP clocks */

? ??? RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

?

? ??? /* Allow access to BKP Domain */

? ??? PWR_BackupAccessCmd(ENABLE);

?

? ??? /* Reset Backup Domain */

????? ?BKP_DeInit();

?

? ??? /* Enable LSE */

? ??? RCC_LSEConfig(RCC_LSE_ON);

?????? for(u16_WaitForOscSource=0;u16_WaitForOscSource<5000;u16_WaitForOscSource++)

??? ?????? {

??? ?????? }

? ??? /* Wait till LSE is ready */

? ??? while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);

?

? ??? /* Select LSE as RTC Clock Source */

? ??? RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

?

? ??? /* Enable RTC Clock */

? ??? RCC_RTCCLKCmd(ENABLE);

?

? ??? /* Wait for RTC registers synchronization */

? ??? RTC_WaitForSynchro();

?

? ??? /* Wait until last write operation on RTC registers has finished */

? ??? RTC_WaitForLastTask();

?

? ??? /* Enable the RTC Second */

? ??? RTC_ITConfig(RTC_IT_SEC, ENABLE);

?

? ??? /* Wait until last write operation on RTC registers has finished */

????? ?RTC_WaitForLastTask();

?

? ??? /* Set RTC prescaler: set RTC period to 1sec */

? ??? RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

?

? ??? /* Wait until last write operation on RTC registers has finished */

? ??? RTC_WaitForLastTask();

??????? //配置完成后,向后備寄存器中寫特殊字符0xA5A5

??????? BKP_WriteBackupRegister(BKP_DR1, 0x5A5A);

?????? ?RTC_Set(2011,01,01,0,0,0);//默認(rèn)時(shí)間

??? }

??? else

??? {

??????? //若后備寄存器沒有掉電,則無需重新配置RTC

??????? //這里我們可以利用RCC_GetFlagStatus()函數(shù)查看本次復(fù)位類型

??????? RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

??? ?????? ?for(u16_WaitForOscSource=0;u16_WaitForOscSource<5000;u16_WaitForOscSource++);

??????? if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)

??????? {

??????????? //這是上電復(fù)位

??????? }

??????? else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)

??????? {

??????????? //這是外部RST管腳復(fù)位

??????? }

??????? //清除RCC中復(fù)位標(biāo)志

??????? RCC_ClearFlag();

?

??????? //雖然RTC模塊不需要重新配置,且掉電后依靠后備電池依然運(yùn)行

??????? //但是每次上電后,還是要使能RTCCLK???????

??????? //RCC_RTCCLKCmd(ENABLE);

??????? //等待RTC時(shí)鐘與APB1時(shí)鐘同步

??????? //RTC_WaitForSynchro();

?

??????? //使能秒中斷

??????? RTC_ITConfig(RTC_IT_SEC, ENABLE);

??????? //等待操作完成

??????? RTC_WaitForLastTask();

??? }

?

?

?

??? return;

}

//判斷是否是閏年函數(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<2000||syear>2099)return 1;//syear范圍1970-2099,此處設(shè)置范圍為2000-2099???? ??

?????? 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->APB1ENR|=1<<28;//使能電源時(shí)鐘

??? RCC->APB1ENR|=1<<27;//使能備份時(shí)鐘

?????? PWR->CR|=1<<8;? ??//取消備份區(qū)寫保護(hù)

?????? //上面三步是必須的!*/

?????? PWR_BackupAccessCmd(ENABLE);

?????? RTC_WaitForLastTask();

?????? RTC_SetCounter(seccount);

?????? RTC_WaitForLastTask();

?????? 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();

?????? ??

?????? /*timecount=RTC->CNTH;//得到計(jì)數(shù)器中的值(秒鐘數(shù))

?????? timecount<<=16;

?????? timecount+=RTC->CNTL;??? */??????????

?

?????? temp=timecount/86400;?? //得到天數(shù)(秒鐘數(shù)對應(yīng)的)

?????? if(daycnt!=temp)//超過一天了

?????? {???? ?

????????????? 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++;?

????????????? }??

????????????? timer.w_year=temp1;//得到年份

????????????? temp1=0;

????????????? while(temp>=28)//超過了一個(gè)月

????????????? {

???????????????????? if(Is_Leap_Year(timer.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++;?

????????????? }

????????????? timer.w_month=temp1+1;//得到月份

????????????? timer.w_date=temp+1;? //得到日期

?????? }

?????? temp=timecount%86400;???? //得到秒鐘數(shù)?? ???

?????? timer.hour=temp/3600;???? //小時(shí)

?????? timer.min=(temp%3600)/60; //分鐘?????

?????? timer.sec=(temp%3600)%60; //秒鐘

?????? timer.week=RTC_Get_Week(timer.w_year,timer.w_month,timer.w_date);//獲取星期??

?????? return 0;

}????

//獲得現(xiàn)在是星期幾

//功能描述:輸入公歷日期得到星期(只允許1901-2099年)

//輸入?yún)?shù):公歷年月日

//返回值:星期號????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

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;

?????? // 所過閏年數(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);

}

總結(jié)

以上是生活随笔為你收集整理的stm32f103 rtc 获取 日历 时钟的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。