[STM32F1] STM32F103x 中 HAL_RTC_GetTime () 与 RTC 中断中ALR 和 SEC 标志混用导致的异常

[复制链接]
21|10
唐纳德d 发表于 2026-2-21 12:38 | 显示全部楼层 |阅读模式

我用 STM32F103C8T6 开发项目,使用的IDE是 STM32CubeIDE 1.13.2 版本,HAL 库为 STM32Cube FW 1.8.5 版本。我将闹钟设置为 00:00:00 触发,且闹钟中断触发后,会重新配置闹钟使其在 20 秒后再次触发。
在这个项目中我用到了 RTC 提供的两个中断:每秒触发一次的秒中断,以及闹钟中断。
中断优先级的设置顺序(从高到低)为:
SysTick 中断
闹钟中断
RTC 全局中断
定时器 3 中断
SysTick 中断的优先级必须高于所有 RTC 中断 , 因为它是 RTC 模块各类函数中超时计算的时间基准。
当我在秒中断的回调函数中执行 HAL_RTC_GetTime() 函数时,闹钟能在正确时间触发,但在中断处理过程中丢了一秒。我想找出该异常的原因,推测是在这个场景下执行 HAL_RTC_GetTime 函数内的某些操作并不完全合适。
4097669990d58e4a0f.png

void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc){
        if(hrtc->Instance == RTC){
                HAL_RTC_GetTime(hrtc, &now_Time, RTC_FORMAT_BIN);
                (void)snprintf (message_buffer, (size_t)sizeof(message_buffer), "Current Hour %d:%d:%d\r\n", now_Time.Hours, now_Time.Minutes, now_Time.Seconds);
                HAL_UART_Transmit(&huart1, (uint8_t *)message_buffer, strlen (message_buffer), HAL_MAX_DELAY);
                secondsUpdate++;
                seconds_flag = 1;
        }
}

while (1)
{
          if(seconds_flag ==1){
//                  HAL_RTC_GetTime(&hrtc, &now_Time, RTC_FORMAT_BIN);
//                  (void)snprintf (message_buffer, (size_t)sizeof(message_buffer), "Current Hour %d:%d:%d\r\n", now_Time.Hours, now_Time.Minutes, now_Time.Seconds);
//                  HAL_UART_Transmit(&huart1, (uint8_t *)message_buffer, strlen (message_buffer), HAL_MAX_DELAY);
                  seconds_flag =0;
          }

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
}
由于不建议在中断中运行过多代码,因此我修改为:秒中断触发时将一个标志位设为 1,在 while 主循环中读取时间并将该标志位重置为 0。但这种情况下,闹钟中断完全无法触发。
232269990dad6610a.png
void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc){
        if(hrtc->Instance == RTC){
//                HAL_RTC_GetTime(hrtc, &now_Time, RTC_FORMAT_BIN);
//                (void)snprintf (message_buffer, (size_t)sizeof(message_buffer), "Current Hour %d:%d:%d\r\n", now_Time.Hours, now_Time.Minutes, now_Time.Seconds);
//                HAL_UART_Transmit(&huart1, (uint8_t *)message_buffer, strlen (message_buffer), HAL_MAX_DELAY);
                secondsUpdate++;
                seconds_flag = 1;
        }
}

while (1)
{
          if(seconds_flag ==1){
                  HAL_RTC_GetTime(&hrtc, &now_Time, RTC_FORMAT_BIN);
                  (void)snprintf (message_buffer, (size_t)sizeof(message_buffer), "Current Hour %d:%d:%d\r\n", now_Time.Hours, now_Time.Minutes, now_Time.Seconds);
                  HAL_UART_Transmit(&huart1, (uint8_t *)message_buffer, strlen (message_buffer), HAL_MAX_DELAY);
                  seconds_flag =0;
          }

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
}
如果我既不在回调函数中、也不在 while 循环中调用 HAL_RTC_GetTime() 函数,闹钟能正常触发,但此时我无法判断是否仍存在 “丢失一秒钟” 的问题。
我想知道以上的操作是否存在错误?
有人知道问题可能出在哪里吗?会不会是 HAL 层的 bug?

公羊子丹 发表于 2026-2-23 18:40 | 显示全部楼层
我怀疑是HAL_RTC_GetTime的读写保护机制坑了你,F103的RTC寄存器读写需要解锁,这个函数里会做解锁操作,和中断里的标志位检测冲突,导致秒中断的标志被误清,自然就丢秒了。
周半梅 发表于 2026-2-23 18:45 | 显示全部楼层
兄弟你检查过RTC中断的标志位清除顺序没?F1的RTC秒中断和闹钟中断的标志位要单独清,要是在GetTime里被HAL库自动清了,另一个中断就触发不了,这坑我在F103上踩过好几次。
帛灿灿 发表于 2026-2-23 18:46 | 显示全部楼层
这问题太常见了,HAL库的RTC函数本身就会占用RTC外设,你在主循环里调用GetTime的时候,刚好赶上闹钟中断触发,外设被占用就导致中断响应失败,闹钟自然没反应了。
童雨竹 发表于 2026-2-23 18:47 | 显示全部楼层
我建议你把HAL_UART_Transmit换成非阻塞模式,你用的HAL_MAX_DELAY是阻塞的,在中断里执行会占用大量时间,导致SysTick的计时基准偏移,RTC的超时计算出错就丢秒了。
万图 发表于 2026-2-23 18:48 | 显示全部楼层
想问下你调用HAL_RTC_GetTime后,有没有紧接着调用HAL_RTC_GetDate?F1的RTC时间和日期寄存器必须连续读取,少了一步的话,寄存器值会错乱,大概率会导致时间读取异常和中断冲突。
Wordsworth 发表于 2026-2-23 18:49 | 显示全部楼层
我猜你是没给RTC的操作加临界区保护,主循环和中断都在访问RTC外设,会出现资源竞争,你可以在调用GetTime前后加__disable_irq()和__enable_irq(),试试能不能解决冲突。
Bblythe 发表于 2026-2-23 18:50 | 显示全部楼层
哈哈,你这情况绝壁是HAL库的小坑,F103的RTC HAL层函数对中断标志位的处理不严谨,我建议直接操作RTC的寄存器读时间,别用HAL库的封装函数,能彻底避免这种冲突问题。
Pulitzer 发表于 2026-2-23 18:51 | 显示全部楼层
你检查下中断优先级的配置是不是真的生效了?CubeIDE里配置完RTC中断优先级,要确认NVIC的分组有没有设对,要是分组错了,SysTick优先级没高于RTC,计时基准就会乱,中断也会冲突。
Uriah 发表于 2026-2-23 18:52 | 显示全部楼层
分享个实操技巧,你可以在RAM里开个全局变量存当前时间,秒中断里只更新这个变量,主循环里直接读变量不用调GetTime,既避免了外设竞争,又能让中断里的代码更精简。
Clyde011 发表于 2026-2-23 18:53 | 显示全部楼层
我建议你先做个简单测试,把UART打印和GetTime都去掉,只在秒中断和闹钟中断里分别置不同的标志位,主循环里检测标志位,看看闹钟标志能不能正常置位,先排除是不是外设占用的问题。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

105

主题

106

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0