#include "drv_rtc.h" #include "drv_clk.h" #include "bsp_task.h" #include "kit_time.h" #include "kit_data.h" #include "kit_debug.h" #define LSE_NOT_READY 0 #define RCC_BDCR_RTCEN_POS KIT_CREAT_BIT(15) #define RCC_BDCR_LSEDY_POS ((uint32_t)0x00000002) #define RCC_BDCR_LSEON_POS KIT_CREAT_BIT(0) #define RCC_RTCCLKSource_LSE KIT_CREAT_BIT(8) #define RTC_FLAG_RTOFF ((uint16_t)0x0020) /*!< RTC Operation OFF flag */ /****************************************************************************************** 1.写RTC寄存器前必须使能PWR_CR中的DBP,且必须等待操作完成才能清0 DBP 2.stm32f10x RTC 进行写操作前必须判断上一次操作是否完成(RTOFF) 3.写RTC_CNT、RTC_ALR或RTC_PRL寄存器时必须先置位CNF,写完后必须清0才会执行写操作 4.读RTC_CNT、RTC_ALR或RTC_PRL寄存器时前必须清0RSF,等其被硬件置位时表示同步完成,可以读取 5.低速时钟起振时间1-5s ******************************************************************************************/ #define RTC_INIT_MASK ((uint32_t)0xFFFFFFFF) bool drv_rtc_enable_init_mode(void) { uint32_t dly = 0; // //对RTC寄存器操作前先要使能备份区 // PWR->CR |= PWR_CR_DBP; //关闭RTC寄存器写保护 RTC->WPR = 0xCA; RTC->WPR = 0x53; //进入RTC初始化模式 if((RTC->ISR &= RTC_ISR_INITF) == 0) { RTC->ISR = RTC_INIT_MASK; //等待进入RTC初始化模式成功 while(((RTC->ISR & RTC_ISR_INITF) == 0x00) && (dly++ < 100)) { bsp_task_delay_ms(1); } } return (dly < 100); } void drv_rtc_disable_init_mode(void) { RTC->ISR &= ~RTC_ISR_INIT; //退出RTC初始化模式 RTC->WPR = 0xFF; //使能RTC寄存器写保护 } //由于低速时钟起振较慢,其他任务初始化后再初始化RTC bool drv_rtc_init(void) { bool res = false; uint32_t dly = 0; //if((RCC->BDCR & RCC_BDCR_RTCEN_POS) != RCC_BDCR_RTCEN_POS) { KIT_DEBUG_PRINTF("rtc init\r\n"); RCC->APB1ENR |= RCC_APB1Periph_PWR; //使能允许写入RTC和后备寄存器 PWR->CR |= PWR_CR_DBP; //开启LSE RCC->BDCR |= RCC_BDCR_LSEON_POS; while((RCC->BDCR & RCC_BDCR_LSEDY_POS) == LSE_NOT_READY) { bsp_task_delay_ms(10); if(dly++ > 500) { KIT_DEBUG_PRINTF("rtc fail \r\n"); return res; } } KIT_DEBUG_PRINTF("rtc dly %d\r\n", dly); RCC->BDCR |= (RCC_RTCCLKSource_LSE | RCC_BDCR_RTCEN_POS); //RTC配置使用默认配置 //设置同步分频系数和异步分频系数,默认为1Hz = 32768/(同步分频 + 1)/(异步分频 + 1) res = drv_rtc_enable_init_mode(); if(res == true) { RTC->PRER = 0x001F03FF; } drv_rtc_disable_init_mode(); //PWR->CR &= ~PWR_CR_DBP_POS; } return res; } //ampm:AM/PM,0=AM/24H,1=PM. bool drv_rtc_set_time(uint8_t hour, uint8_t min, uint8_t sec) { bool res; //关闭RTC寄存器写保护 res = drv_rtc_enable_init_mode(); if(res == true) { RTC->TR = ((uint32_t)kit_dec_to_bcd(hour) << 16) | ((uint32_t)kit_dec_to_bcd(min) << 8) | (kit_dec_to_bcd(sec)); } drv_rtc_disable_init_mode(); return res; } //year 20xx, month 1-12, day 1-31 bool drv_rtc_set_date(uint16_t year, uint8_t month, uint8_t day) { bool res; //关闭RTC寄存器写保护 res = drv_rtc_enable_init_mode(); if((res == true) && (year >= 2000)) { RTC->DR = ((uint32_t)kit_dec_to_bcd(year - 2000) << 16) | ((uint32_t)kit_dec_to_bcd(month) << 8) | (kit_dec_to_bcd(day)); } drv_rtc_disable_init_mode(); return res; } bool drv_rtc_wait_sync(void) { bool res = true; int32_t retry = 0; //关闭RTC寄存器写保护 RTC->WPR = 0xCA; RTC->WPR = 0x53; RTC->ISR &= ~(1 << 5); //清除RSF位 while((retry++ < 0XFFFFF) && ((RTC->ISR & (1 << 5)) == 0x00)) //等待影子寄存器同步 {} if(retry >= 0XFFFFF) { res = false; } RTC->WPR = 0xFF; //使能RTC寄存器写保护 return res; } bool drv_rtc_get_time(int32_t *hour, int32_t *min, int32_t *sec) { uint32_t temp = 0; if(drv_rtc_wait_sync() == true) { temp = RTC->TR; *hour = kit_dcb_to_dec((temp >> 16) & 0x3F); *min = kit_dcb_to_dec((temp >> 8) & 0x7F); *sec = kit_dcb_to_dec(temp & 0x7F); return true; } else { *hour = *min = *sec = 0; return false; } } //year 20xx, month 1-12, day 1-31 bool drv_rtc_get_date(int32_t *year, int32_t *month, int32_t *day) { uint32_t temp = 0; if(drv_rtc_wait_sync() == true) { temp = RTC->DR; *year = kit_dcb_to_dec((temp >> 16) & 0xFF) + 2000; *month = kit_dcb_to_dec((temp >> 8) & 0x1F); *day = kit_dcb_to_dec(temp & 0x3F); return true; } else { *year = 2000; *month = *day = 1; return false; } } uint32_t drv_rtc_get_tick(void) { struct tm tmp; uint32_t res = 0; tmp.tm_year = 0; if((drv_rtc_get_time(&tmp.tm_hour, &tmp.tm_min, &tmp.tm_sec) == true) && (drv_rtc_get_date(&tmp.tm_year, &tmp.tm_mon, &tmp.tm_mday) == true)) { tmp.tm_mon--; tmp.tm_year = (tmp.tm_year > 2018) ? (tmp.tm_year - 1900) : 119; res = kit_time_get_stamp(2019, &tmp); } return res; } bool drv_rtc_set_tick(uint32_t tick) { struct tm *tmp; bool res = false; if(drv_rtc_get_tick() != tick) { tmp = kit_time_get_date(2019, tick); //标准库月0-11 ST月为1-12,ST年从2000开始只保留十位和各位 if((tmp->tm_year >= 119) && (drv_rtc_set_time(tmp->tm_hour, tmp->tm_min, tmp->tm_sec) == true) && (drv_rtc_set_date((tmp->tm_year + 1900), tmp->tm_mon + 1, tmp->tm_mday) == true)) { res = true; } } else { res = true; } return res; } uint16_t drv_rtc_get_ms(void) { uint32_t tmp = 0; /* Get sub seconds values from the correspondent registers*/ tmp = (uint32_t)(RTC->SSR); /* Read DR register to unfroze calendar registers */ (void)(RTC->DR); tmp = (0x03FF - tmp) * 1000 / (0x03FF + 1); return tmp; } bool drv_rtc_set_ms(uint16_t ms) { bool res = false; uint32_t cur_ms, cnt = 0; /* Disable the write protection for RTC registers */ RTC->WPR = 0xCA; RTC->WPR = 0x53; cur_ms = drv_rtc_get_ms(); if(ms != cur_ms) { RTC->WPR = 0xCA; RTC->WPR = 0x53; /* Check if a Shift is pending*/ while(((RTC->ISR & RTC_ISR_SHPF) != RESET) && (cnt++ < 1000)); /* Check if the Shift pending is completed or if there is no Shift operation at all*/ if((RTC->ISR & RTC_ISR_SHPF) == RESET) { /* check if the reference clock detection is disabled */ if((RTC->CR & RTC_CR_REFCKON) == RESET) { if(cur_ms > ms) { cur_ms = (cur_ms - ms) * (0x3FF + 1) / 1000; } else { cur_ms = (1000 - ms + cur_ms) * (0x3FF + 1) / 1000; } RTC->SHIFTR = cur_ms; res = drv_rtc_wait_sync(); } } /* Enable the write protection for RTC registers */ RTC->WPR = 0xFF; } return res; } #include "stdio.h" char rtc_time_str[20]; char *drv_rtc_get_time_string(void) { struct tm tmp; drv_rtc_get_time(&tmp.tm_hour, &tmp.tm_min, &tmp.tm_sec); sprintf(rtc_time_str, "%2d:%2d:%2d", tmp.tm_hour, tmp.tm_min, tmp.tm_sec); return rtc_time_str; }