| #include "rtc.h" |
| #include "time.h" |
| #include "data_tools.h" |
| #include "string.h" |
| #include "timer.h" |
| |
| uint32_t CrystalStartErrFlag; |
| |
| static uint8_t rtc_wait_flag(uint32_t* reg, uint32_t mask, uint32_t flag, uint32_t timeout) |
| { |
| uint32_t t = timeout/100; |
| |
| while(((*reg)&mask) != flag) |
| { |
| delay_ms(100); |
| t --; |
| if(t == 0) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| uint32_t rtc_get_counter(void) |
| { |
| return (uint32_t)((RTC->CNTH << 16) | RTC->CNTL); |
| } |
| |
| static uint8_t rtc_set_counter(uint32_t cnt) |
| { |
| PWR->CR |= PWR_CR_DBP; // ʹÄÜ·ÃÎÊRTC, BDC ¼Ä´æÆ÷ |
| RTC->CRL |=RTC_CRL_CNF; // ÉèÖÃRTCÅäÖñê¼Ç,ÔÊÐíÅäÖà |
| RTC->CNTH = (cnt>>16)&0xffff; |
| RTC->CNTL = cnt&0xffff ; |
| RTC->CRL &= ~RTC_CRL_CNF; // ÉèÖÃRTCÅäÖñê¼Ç,²»ÔÊÐíÅäÖà |
| if(rtc_wait_flag((uint32_t*)&RTC->CRL, RTC_FLAG_RTOFF, RTC_FLAG_RTOFF, 4000ul)) //µÈ´ýÅäÖÃÍê³É |
| { |
| PWR->CR &= ~PWR_CR_DBP; // ²»ÔÊÐíÅäÖÃRTC¡¢BDC¼Ä´æÆ÷ |
| return 1; |
| } |
| PWR->CR &= ~PWR_CR_DBP; // ²»ÔÊÐíÅäÖÃRTC¡¢BDC¼Ä´æÆ÷ |
| return 0; |
| } |
| |
| void rtc_init(void) |
| { |
| CrystalStartErrFlag = 0; |
| RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); |
| |
| //RTCÊ×´ÎÉϵç»òʱÖÓ¶ªÊ§ |
| if(BKP_ReadBackupRegister(BKP_DR1) != 0x5A5A) |
| { |
| RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); |
| PWR_BackupAccessCmd(ENABLE); |
| BKP_DeInit(); |
| RCC_LSEConfig(RCC_LSE_ON); |
| |
| //²ÎÕÕstm32f10x datasheet£¬LES startup time |
| //tsu(lse) = 3S (Typ) |
| //´Ë´¦µÈ´ýLSEÆðÕñÑÓʱԼ4S |
| if(rtc_wait_flag((uint32_t*)&RCC->BDCR, 0x02, 0x02, 4000ul)) |
| CrystalStartErrFlag = 1; |
| |
| if(!CrystalStartErrFlag) |
| { |
| RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); |
| RCC_RTCCLKCmd(ENABLE); |
| /* Clear RSF flag */ |
| RTC->CRL &= (u16)~RTC_FLAG_RSF; |
| /* Loop until RSF flag is set */ |
| if(rtc_wait_flag((uint32_t*)&RTC->CRL, RTC_FLAG_RSF, RTC_FLAG_RSF, 4000ul)) |
| CrystalStartErrFlag = 1; |
| |
| //rtc wait for last task |
| if(rtc_wait_flag((uint32_t*)&RTC->CRL, RTC_FLAG_RTOFF, RTC_FLAG_RTOFF, 4000ul)) |
| CrystalStartErrFlag = 1; |
| |
| RTC_SetPrescaler(32767); |
| //rtc wait for last task |
| if(rtc_wait_flag((uint32_t*)&RTC->CRL, RTC_FLAG_RTOFF, RTC_FLAG_RTOFF, 4000ul)) |
| CrystalStartErrFlag = 1; |
| |
| BKP_WriteBackupRegister(BKP_DR1, 0x5A5A); |
| } |
| PWR_BackupAccessCmd(DISABLE); |
| RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, DISABLE); |
| } |
| else |
| { |
| /* Clear RSF flag */ |
| RTC->CRL &= (u16)~RTC_FLAG_RSF; |
| /* Loop until RSF flag is set */ |
| if(rtc_wait_flag((uint32_t*)&RTC->CRL, RTC_FLAG_RSF, RTC_FLAG_RSF, 4000ul)) |
| CrystalStartErrFlag = 1; |
| else |
| { |
| //0x386D4380ul 2000Äê1ÔÂ1ÈÕÃëÊý |
| if(rtc_get_counter()<0x386D4380ul) |
| { |
| rtc_set_counter(0x386D4380ul); |
| } |
| |
| // rtc_get_time(&SystemTime); |
| } |
| } |
| } |
| |
| uint32_t rtc_mk_time(_SystemTime* t) |
| { |
| struct tm temp_time; |
| _SystemTime temp_time_hex; |
| |
| memcpy(&temp_time_hex, t, sizeof(_SystemTime)); |
| bcd2hex(&temp_time_hex, sizeof(temp_time_hex)); |
| temp_time.tm_year = temp_time_hex.year+100; //´Ó1900Ä꿪ʼ |
| temp_time.tm_mon = temp_time_hex.month-1; |
| temp_time.tm_mday = temp_time_hex.day; |
| temp_time.tm_wday = temp_time_hex.week; |
| temp_time.tm_hour = temp_time_hex.hour; |
| temp_time.tm_min = temp_time_hex.minute; |
| temp_time.tm_sec = temp_time_hex.second; |
| |
| return mktime(&temp_time); |
| } |
| |
| uint8_t rtc_set_time(_SystemTime* t) |
| { |
| uint8_t ret = 0; |
| time_t seconds = rtc_mk_time(t); |
| |
| ret = rtc_set_counter(seconds); |
| |
| return ret; |
| } |
| |
| uint8_t rtc_get_time(_SystemTime* t) |
| { |
| struct tm* temp_time; |
| _SystemTime temp_time_bcd; |
| time_t seconds = rtc_get_counter(); |
| |
| temp_time = localtime(&seconds); |
| if(temp_time->tm_year<100) |
| temp_time_bcd.year = 0; |
| else |
| temp_time_bcd.year = temp_time->tm_year - 100; |
| |
| temp_time_bcd.month = temp_time->tm_mon+1; |
| temp_time_bcd.day = temp_time->tm_mday; |
| temp_time_bcd.week = temp_time->tm_wday; |
| temp_time_bcd.hour = temp_time->tm_hour; |
| temp_time_bcd.minute = temp_time->tm_min; |
| temp_time_bcd.second = temp_time->tm_sec; |
| hex2bcd(&temp_time_bcd, sizeof(temp_time_bcd)); |
| memcpy(t, &temp_time_bcd, sizeof(temp_time_bcd)); |
| return 0; |
| } |
| |
| uint32_t rtc_time_diff(void* t1, void* t2) |
| { |
| uint32_t t1_sec = rtc_mk_time((_SystemTime*)t1); |
| uint32_t t2_sec = rtc_mk_time((_SystemTime*)t2); |
| |
| return (t1_sec-t2_sec); |
| } |