stm32 每次复位或者开关电源,RTC时间都会变慢

        正点原子的hal库的RTC例程也有这个问题。

        具体问题现象是:多次连续按复位,或者多次连续开关电源,出现RTC时间慢于实际时间。

        在网上寻找无果:stm32 每次复位启动RTC时间都会变慢_stm32停机唤醒缓慢-优快云博客 这一片文章应该是年代久了,而且也不知道在说啥。

        怀疑是HAL_RTC_Init(&hrtc)的问题,将该函数直接放在main函数中,rtc直接不动。

        我的解决方法是:在MX_RTC_Init()函数中的HAL_RTC_Init(&hrtc)函数找到RTC_EnterInitMode(hrtc)函数,然后将这个函数内的__HAL_RTC_WRITEPROTECTION_DISABLE(hrtc)函数注释掉,图片如下。原因可能是在于该函数使得RTC几个寄存器的写保护消失,使得HAL_RTC_Init(&hrtc)重复对RTC的一些寄存器进行初始化。

        试验后问题解决。

 /*2025-3-17    21:22

=======================================================================*/

        今天深挖了一下原理,导致stm32 每次复位或者开关电源,RTC时间都会变慢的原因是因为,在原版的HAL_RTC_Init(&hrtc)中有个向预分频装载计数器PRL重新写值的函数如下图:

        我们将这两行代码注释掉就可以更精准的解决这个问题了。

        STM32F1手册313页如是说:

        因为一旦RTC_PRL寄存器被重写,RTC_DIV寄存器也会被硬件重新装载。而RTC_DIV寄存器是受RTC_CLK(该值一般为为LSE,晶振频率为32.768kHz)影响计数,进而产生我们需要的1Hz信号,给RTC_CNT寄存器计数的。一般来说RTC_DIV只会受到RTC_CNT加1而重新装载RTC_PRL的值,但是一旦我们复位,RTC_DIV寄存器被重新装载,就导致了时间变慢,我们从RTC_CNT中读取秒数也会变慢。

        粘贴主要代码如下:

        main函数中的MX_RTC_Init函数、我的RTC秒中断函数:

RTC_TimeTypeDef RTC_Time;
RTC_DateTypeDef RTC_Date;
uint8_t aShowTime[50] = {0};
uint8_t aShowDate[50] = {0};

void MX_RTC_Init(void)
{
    RTC_TimeTypeDef sTime        = {0};
    RTC_DateTypeDef DateToUpdate = {0};

    hrtc.Instance          = RTC;
    hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
    hrtc.Init.OutPut       = RTC_OUTPUTSOURCE_ALARM;
    if (HAL_RTC_Init(&hrtc) != HAL_OK) {
        Error_Handler();
    }

    /* USER CODE BEGIN Check_RTC_BKUP */
    HAL_RTCEx_SetSecond_IT(&hrtc);  
    if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) == 0x32F6) { // 如果已经初始化过,则直接返回,否则读取备份寄存器中的年月星期日期
        hrtc.DateToUpdate.Year = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);
        hrtc.DateToUpdate.Month = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3);
        hrtc.DateToUpdate.WeekDay = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR4);
        hrtc.DateToUpdate.Date = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR5);
        return;
    } else { // 如果未初始化过,则进行初始化 并对BKP1寄存器标记
        /* USER CODE END Check_RTC_BKUP */

        /** Initialize RTC and set the Time and Date
         */
        sTime.Hours   = 21;
        sTime.Minutes = 0;
        sTime.Seconds = 0;

        if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) {
            Error_Handler();
        }
        DateToUpdate.WeekDay = RTC_WEEKDAY_MONDAY;
        DateToUpdate.Month   = RTC_MONTH_MARCH;
        DateToUpdate.Date    = 17;
        DateToUpdate.Year    = 25;

        if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK) {
            Error_Handler();
        }
        /* USER CODE BEGIN RTC_Init 2 */
        HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x32F6);
    }

    /* USER CODE END RTC_Init 2 */
}

void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc)
{
    LED0_TOGGLE();
    HAL_RTC_GetTime(hrtc, &RTC_Time, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(hrtc, &RTC_Date, RTC_FORMAT_BIN);

    sprintf((char *)aShowTime, "%2d:%2d:%2d", RTC_Time.Hours, RTC_Time.Minutes, RTC_Time.Seconds);
    sprintf((char *)aShowDate, "%2d-%2d-%2d", RTC_Date.Month, RTC_Date.Date, 2000 + RTC_Date.Year);

    if (RTC_Time.Seconds == 0) { //每分钟记录当前时间到备份寄存器中
        HAL_RTCEx_BKUPWrite(hrtc, RTC_BKP_DR2, RTC_Date.Year);
        HAL_RTCEx_BKUPWrite(hrtc, RTC_BKP_DR3, RTC_Date.Month);
        HAL_RTCEx_BKUPWrite(hrtc, RTC_BKP_DR4, RTC_Date.WeekDay);
        HAL_RTCEx_BKUPWrite(hrtc, RTC_BKP_DR5, RTC_Date.Date);
    }
}

        main函数:

int main(void)
{
    HAL_Init();

    /* USER CODE BEGIN Init */
    delay_init(72);
    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_FSMC_Init();
    MX_RTC_Init();
    MX_TIM1_Init();
    /* USER CODE BEGIN 2 */
    LCD_Init();
    LCD_ShowString(0, 0, 200, 12, 12, (uint8_t *)"HellowLCD!");
    printf("HellowSerial!\r\n");

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1) {
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
        LCD_ShowString(0, 24, 200, 12, 12, aShowDate);

        LCD_ShowString(0, 36, 200, 12, 12, aShowTime);
    }
    /* USER CODE END 3 */
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值