声明:以下仅为本人的理解,不一定完全正确(勿喷),有不对的请指正,可以共同交流学习进步
众所周知,STM32HAL库的RTC有这个断电重新上电后时间正常但是丢失日期的bug, 这主要是因为HAL库处理时间是最终还是将时间转换为秒然后处理,而日期的处理主要是通过RTC_DateTypeDef结构体DateToUpdate变量进行处理。下面我们来分析下HAL_RTC_Init初始化函数
可以看到在RTC初始化函数中,简单粗暴的将这个日期数据处理的结构体复位了,而没有去读取时间戳将其转换成日期。
接下来分析HAL_RTC_SetDate日期设置和HAL_RTC_GetDate日期获取函数
可以看到无论是HAL库的设置日期和获取日期函数都是经过这个DateToUpdate变量的处理,那么一旦我们断电重新上电,那么HAL_RTC_Init函数获就将DateToUpdate变量复位,所以我们调用HAL_RTC_GetDate获取到的就不是你所设置的日期了。
所以我们可以将年月日时分秒格式数据转换成时间戳直接写入RTC_CNT寄存器,然后读取时也是直接读取寄存器值,再转换为年月日时分秒格式。这里可以使用<time.h>中的库函数解决, 以下是时间设置函数以及时间获取函数
void myRTC_setTime(uint16_t* time_data)
{
uint32_t set_tim_stamp;
struct tm set_tim_data;
set_tim_data.tm_year = time_data[0] - 1900;
set_tim_data.tm_mon = time_data[1] - 1;
set_tim_data.tm_mday = time_data[2];
set_tim_data.tm_hour = time_data[3];
set_tim_data.tm_min = time_data[4];
set_tim_data.tm_sec = time_data[5];
set_tim_stamp = mktime(&set_tim_data);
// 等待上一次写操作完成
while(!(hrtc.Instance->CRL & RTC_CRL_RTOFF));
// 失能写保护
__HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);
// 将时间戳写入RTC_CNT寄存器
WRITE_REG(hrtc.Instance->CNTH, (set_tim_stamp >> 16U));
WRITE_REG(hrtc.Instance->CNTL, (set_tim_stamp & RTC_CNTL_RTC_CNT));
// 写入完毕开启写保护
__HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);
// 等待写操作完成
while(!(hrtc.Instance->CRL & RTC_CRL_RTOFF));
}
void myRTC_getTime(uint16_t* get_time_datas)
{
uint32_t get_tim_stamp;
struct tm get_tim_data = {0};
// 从RTC_CNT寄存器获取RTC时间戳
get_tim_stamp = RTC->CNTH; // 获取高16位
get_tim_stamp <<= 16U;
get_tim_stamp |= RTC->CNTL; // 获取低16位
get_tim_data = *localtime(&get_tim_stamp);
get_time_datas[0] = get_tim_data.tm_year + 1900;
get_time_datas[1] = get_tim_data.tm_mon + 1;
get_time_datas[2] = get_tim_data.tm_mday;
get_time_datas[3] = get_tim_data.tm_hour;
get_time_datas[4] =