ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32 RTC中断不触发?从CubeMX到HAL库的完整排查指南

STM32 RTC中断不触发?从CubeMX到HAL库的完整排查指南 先交代背景我最近在调一块 STM32L432KC 的低功耗项目板子是自己画的主控就是 L432KC系统时钟用的 MSIRTC 走的 LSE 外部晶振需求是每 2 秒唤醒一次 MCU 做数据采集再睡回去。CubeMX 里配置了半天NVIC 该勾的勾了代码里回调也写了但下载进去之后 RTC 中断死活不触发。断点打在主回调函数里根本走不到但 RTC 计数确实在走唤醒标志也置上了——典型的“外设已经在工作但中断事件没送到 CPU”的问题。这种问题在 STM32 的 RTC 外设上特别容易踩坑因为 RTC 的中断链路比普通外设多一环外设事件源 → NVIC 使能 → 中断服务函数 → HAL 回调任何一环断了都会出现“看着配置了实际不工作”的假象。这篇文章就把我这次排查的完整过程、根因分析、以及 CubeMX 和 HAL 库的注意事项写透希望能帮到被同样问题卡住的兄弟。1. 问题现象与根因分析1.1 典型“配置正确但中断不触发”的现象先说症状。我用 CubeMX 做初始化配置步骤大概是使能 RTC选 External Clock 的 LSE激活 WakeUp 定时器把 WakeUp Time 设为 2 秒然后在 NVIC Settings 里勾上 RTC global interrupt 的 Enabled 复选框生成代码后在main.c里重写了HAL_RTCEx_WakeUpTimerEventCallback并在while(1)之前调用了HAL_RTCEx_SetWakeUpTimer_IT()。下载后观察电流波形和调试变量结果发现 RTC 的秒中断、唤醒标志位都在正常变化系统也能在低功耗模式中被唤醒但回调函数就是进不去。这个现象很典型RTC 外设本身工作正常因为唤醒标志位已经置上了说明 RTC 的计数和事件产生都没问题。问题一定出在“事件产生之后”的链路上。1.2 RTC 中断的完整链路外设事件 → NVIC → 中断服务函数STM32 的中断系统我的理解可以类比成一条物流链路外设产生事件包裹生成→ 外设中断使能位包裹是否允许发出→ NVIC快递公司是否接收→ CPU 响应并执行中断服务函数包裹送达。任何一环没打通包裹就到不了手里。具体到 RTC 唤醒定时器这条链路是RTC 的唤醒定时器计数器递减到 0硬件置位RTC_ISR.WUTF唤醒标志同时如果RTC_CR.WUTIE唤醒定时器中断使能位被置 1就把中断请求信号发给 NVIC。NVIC 只有当RTC_IRQn对应的中断使能位被置 1且优先级分组配置有效才会触发 CPU 进入RTC_IRQHandler中断服务函数最终由 HAL 库调用弱定义的HAL_RTCEx_WakeUpTimerEventCallback。我这次的问题就出在RTC_CR.WUTIE这一环。CubeMX 的图形界面里如果你在 RTC 配置页面勾选了 WakeUp 定时器并且激活了中断CubeMX 生成的代码会同时设置WUTIE。但如果某些版本的 CubeMX 在特定配置组合下不会自动生成这个位例如先使能了 RTC 全局中断之后才添加 WakeUp 功能或者使用低功耗模式后 CubeMX 生成的初始化顺序出现问题那就只有 NVIC 使能了外设本身的中断使能没开事件发不出来。1.3 为什么在 CubeMX 里“勾了 NVIC”还不够这是我写这篇文章最想强调的一点CubeMX 里 NVIC 页面勾选 RTC global interrupt只是把中断请求“放行”到了 CPU并不代表外设产生的事件会自动成为中断请求。外设层的中断使能必须在 RTC 自身配置中打开二者是“串联”的关系缺一不可。HAL 库的管理模式跟标准库不太一样标准库时期外设中断使能和 NVIC 使能经常在初始化函数里一次性处理而 HAL 库更多是“外设初始化只配置外设本身NVIC 配置单独由 CubeMX 生成的HAL_NVIC_EnableIRQ()处理”。这种分离设计的好处是模块化清晰但坏处是容易让人漏掉某一环。我做核对的思路是先看生成的RTC_Init()之后的MX_RTC_Init()函数里有没有sConfig.EnableWakeUp和sConfig.EnableWakeUpInterruptHAL 库里实际不存在这个成员但我习惯先检查初始化参数再看HAL_RTCEx_SetWakeUpTimer_IT()是否有被调用最后检查 NVIC 代码。检查顺序很重要从外设到 CPU逐级确认。2. CubeMX 配置 RTC 中断的完整流程2.1 时钟树配置RTC 时钟源的选择与验证ST公司的参考手册用较大篇幅描述 RTC 时钟源的细节。L432 的 RTC 可以有三种时钟来源LSE32.768kHz 外部低速晶振、LSI内部低速 RC典型值 32kHz、HSE 分频也可以来自 LSE 旁路模式。选择不同时钟源直接影响后续唤醒定时器的计数精度和功耗。我在这个项目里选择 LSE原因是它精度高适合长时间定时和日历功能。LSI 的优点是可以省掉外部晶振成本但精度差且随温度漂移。CubeMX 的 Clock Configuration 页面里RTC 时钟源在LSE或LSI的RTC框中勾选然后系统会自动给出可用的异步预分频和同步预分频推荐值。需要注意L432 的 LSE 有两个驱动能力配置LSE_DRIVE_LOW和LSE_DRIVE_HIGH。很多人忽视这个配置导致 LSE 振荡偏慢或启动失败。对 32.768kHz 晶振我一般先选LSE_DRIVE_LOW如果发现起振不稳定再调高。调试时在RTC_ISR.LSERDY标志被置位之前不要启动 RTC 操作否则会有不可预期的行为。2.2 WakeUp 定时器参数设置从 2 秒唤醒示例说起RTC 唤醒定时器本质上是一个 16 位递减计数器计数时钟可以来自 RTCCLK 的分频。CubeMX 中配置 WakeUp Time 时会自动计算WakeUpClock分频系数和WakeUpCounter重载值。两者关系 想要唤醒周期T_wakeup (Counter 1) × 分频后时钟周期。分频后时钟频率跟WakeUpClock的配置相关具体可以参考 RM0394 中 RTC 唤醒定时器的时钟选择表。我这次用 2 秒唤醒选择RTC_WAKEUPCLOCK_CK_SPRE_16BITS该模式直接用RTC_SSR相关的同步预分频时钟作为唤醒时钟能实现以亚秒为单位的选择。CubeMX 界面上选择 wakeup clock 1Hzcounter 填 1就是 2 秒因为计数器从 1 递减到 0共 2 个周期。这里要特别小心 counter 的语义很多人第一次用会在这里栽跟头把 counter 理解为“秒数1”就错了要看具体的时钟源和分频。2.3 NVIC 设置详解RTC 的多个中断如何在 CubeMX 中区分L432 的 RTC 外设不止一个中断请求源。RTC 全局中断RTC_IRQn通道里面打包了闹钟 A、闹钟 B、唤醒定时器、时间戳、入侵检测等多种事件的中断标志。CubeMX 的 NVIC 页面中你看到的“RTC global interrupt”就是这一整个打包的通道。另外如果你的设计里同时用到了 Tamper入侵检测事件L432 还可能有单独的RTC_TAMP_IRQn通道它和RTC_IRQn是分开的两个 NVIC 通道。在 CubeMX 中分别勾选即可。我在调试中发现有些用户在 NVIC 设置里不小心同时关掉了RTC_IRQn以为只要在 RTC 配置里使能了唤醒中断就行——同样会卡住。3. HAL 库中断处理机制与代码实现3.1 中断服务函数与弱回调函数的调用关系HAL 库把中断处理的基本框架写好了芯片产生 RTC 中断后CPU 跳转到stm32l4xx_it.c或启动文件中定义的RTC_IRQHandler。这个函数在 HAL 库中是被定义成弱函数还是强函数关键在于你是否在stm32l4xx_it.c中显式定义了。CubeMX 生成的代码中RTC_IRQHandler是强定义的内部会调用HAL_RTCEx_WakeUpTimerIRQHandler(hrtc)但这个HAL_RTCEx_WakeUpTimerIRQHandler内部又会根据中断标志位调用对应的回调函数。回调函数的原型是void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc);在 HAL 库源文件中是__weak弱定义默认空实现。如果你在自己的代码里重写一个同名函数编译器会优先链接你的函数。很多人的错误是用 CubeMX 生成代码后在新加的文件里复制粘贴了同一个函数名但函数所在文件没有被加入编译或者函数被写成了HAL_RTCEx_WakeUpTimerEventCallBack注意大小写回调的后缀Callback名字对不上链接器自然就用了弱定义的那个空函数。3.2 正确重写回调函数位置与命名细节CubeMX 生成的项目中代码位置建议放回调函数到main.c的/* USER CODE BEGIN 4 */和/* USER CODE END 4 */之间或者单独的.c文件。我习惯单独建一个app_rtc.c文件专门放用户层回调这样便于维护但前提是文件要加入工程编译头文件路径要正确。函数签名必须是void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)注意参数类型如果你误写成RTC_HandleTypeDef hrtc而不是指针编译能过但链接时因为参数类型不匹配生成的符号名C 有重载的情况另说C 语言没有重载还是同一个函数名结果还是会被当作回调执行吗不会C 里函数名不带参数类型修饰所以即使写错也能链接上但传入参数的内存布局不对hrtc的成员访问很可能出错。这是个隐蔽坑。我实测中发现最保险的做法是在main.c中的回调函数内加一个 LED 翻转或者一个全局变量累加稍后通过调试器观察。这样可以快速确认中断是否真的进来而不是去查看WUTF标志——那个标志在外设层中断是否进入完全可以从回调执行来判断。3.3 从代码层面查看 CubeMX 生成了什么RTC 初始化的关键片段CubeMX 生成的关键函数在main.c的MX_RTC_Init()大致如下static void MX_RTC_Init(void) { rtcHandle.Instance RTC; rtcHandle.Init.HourFormat RTC_HOURFORMAT_24HOUR; rtcHandle.Init.AsynchPrediv RTC_ASYNCH_PREDIV; rtcHandle.Init.SynchPrediv RTC_SYNCH_PREDIV; rtcHandle.Init.OutPut RTC_OUTPUT_DISABLE; rtcHandle.Init.OutPutPolarity RTC_OUTPUT_POLARITY_HIGH; rtcHandle.Init.OutPutType RTC_OUTPUT_TYPE_OPENDRAIN; if (HAL_RTC_Init(rtcHandle) ! HAL_OK) { Error_Handler(); } RTC_TimeTypeDef sTime {0}; sTime.Hours 0x0; sTime.Minutes 0x0; sTime.Seconds 0x0; sTime.DayLightSaving RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation RTC_STOREOPERATION_RESET; if (HAL_RTC_SetTime(rtcHandle, sTime, RTC_FORMAT_BCD) ! HAL_OK) { Error_Handler(); } RTC_DateTypeDef sDate {0}; sDate.WeekDay RTC_WEEKDAY_MONDAY; sDate.Month RTC_MONTH_JANUARY; sDate.Date 0x1; sDate.Year 0x0; if (HAL_RTC_SetDate(rtcHandle, sDate, RTC_FORMAT_BCD) ! HAL_OK) { Error_Handler(); } }这里注意CubeMX 生成的代码里HAL_RTC_Init()内部已经做了不少事情比如使能访问备份域、选择时钟源、设置预分频等。但唤醒定时器和唤醒中断的初始化CubeMX 通常不会直接在MX_RTC_Init()里调用HAL_RTCEx_SetWakeUpTimer_IT()而是把这个函数的调用放到你的业务代码里。这既是好事也是坑好处是灵活性高坏处是你忘记调用它时外设完全不产生中断。我的做法是在main()初始化阶段RTC 初始化完成后立即调用HAL_RTCEx_SetWakeUpTimer_IT(hrtc, 1, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);这个函数的第一个参数是 RTC 句柄第二个是重载计数值第三个是唤醒时钟源选择。我在这个项目里用的是RTC_WAKEUPCLOCK_CK_SPRE_16BITS对应 1Hz 时钟counter 填 1得到 2 秒唤醒。也可以配置成RTC_WAKEUPCLOCK_DIV1024这类分频模式但算周期时留意 clock source 的实质频率。然后必须确认 NVIC 使能代码存在通常在MX_RTC_Init()之后或者main()前半部分HAL_NVIC_SetPriority(RTC_IRQn, 0, 0); HAL_NVIC_EnableIRQ(RTC_IRQn);如果这两个函数缺失或者被某些预处理宏屏蔽掉也会导致中断不触发。4. 排查流程与典型问题清单4.1 逐级检查法从外设标志到 NVIC 的定位思路遇到 RTC 中断不触发时我强烈建议不要瞎猜按顺序从外设往 CPU 一层层确认。第一层RTC 外设是否产生了事件可以通过调试器查看RTC-ISR的WUTF位如果为 1说明外设事件已经发生。如果为 0就得查时钟源和唤醒定时器配置。第二层RTC 外设的中断使能位RTC-CR.WUTIE是否为 1如果不为 1事件不会变成中断请求。这也是我这次踩的坑打开寄存器窗口发现WUTIE 0一切豁然开朗。第三层NVIC 是否使能查看NVIC-ISER[0]中RTC_IRQn对应的位是否为 1。第四层中断服务函数是否执行在RTC_IRQHandler函数入口打断点如果进不去基本可以确定是 1、2、3 层的问题如果进去了但回调没执行查HAL_RTCEx_WakeUpTimerIRQHandler()是否被正确调用。一套检查下来80% 的问题都能定位。我一般把这种排查方式叫“四级定位法”在嵌入式开发场景下特别实用。很多复杂问题其实是细节遗漏不是理论不懂。4.2 备份域寄存器为什么改了配置后需要复位备份域RTC 在 L432 上位于备份域Backup Domain它有自己的电源轨VBAT。备份域寄存器的访问需要先使能电源接口时钟和备份域访问允许HAL 库在HAL_RTC_Init()里通过__HAL_RCC_RTC_ENABLE()和PWR-CR1 | PWR_CR1_DBP完成了这些操作。但另一个容易被忽略的是RTC 寄存器包括RTC_CR、RTC_ISR等在备份域内不是所有位都能随时写入。有些配置寄存器在 RTC 处于初始化模式INIT位为 1时才能修改。HAL 库的初始化流程会处理这些但如果在运行中动态修改WUTIE我建议遵循手册先调用HAL_RTCEx_DeactivateWakeUpTimer()再设置再调用HAL_RTCEx_SetWakeUpTimer_IT()确保状态机正确。很多人忽视这个顺序导致WUTIE位写入失败。另外有个细节如果之前有一些遗留的 RTC 配置在备份域中没有被新固件正确覆盖可能出现“代码看起来配置了但硬件还是老配置”的情况。此时最简单粗暴的办法是调用HAL_RTC_DeInit()或者手动复位备份域但注意备份域复位会同时清掉日历、闹钟、唤醒配置要慎重用在量产环境中。调试阶段倒是很实用。4.3 踩坑记录中断标志为什么没有清除HAL 库的中断处理函数通常会在进入中断后读取中断状态标志然后调用回调再清除标志。但 RTC 唤醒定时器中断有个特点WUTF标志在读取状态寄存器后建议通过写 0 到RTC_ISR的对应位来清除实际上 STM32L4 的很多 RTC 标志位只能由硬件清除或者需要先读再写特定序列。如果在中断服务中反复进入循环最常见的原因就是标志没有被正确清除。我看到过不少新手直接在回调里加了死循环然后又问为什么while(1)在中断里出不去——这是逻辑问题而不是芯片问题。在实际应用中如果你的唤醒中断执行时间较长建议在回调中先把WUTF清掉再执行其他耗时操作避免后续中断源冲突。清除标志的方式__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG();或者操作寄存器hrtc-Instance-ISR ~RTC_ISR_WUTF;HAL 封装的宏更稳妥但要注意不同系列可能有差异。4.4 中断优先级分组与 HAL 延迟中断的关系L432 的 NVIC 优先级分组在HAL_Init()中通过HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)设置一般默认是 4 位抢占优先级。如果 RTC 中断优先级设置得较低而主循环里有大量关闭中断的临界区操作RTC 中断就会一直被延迟响应。但注意这不会导致“中断不触发”只会导致响应延迟。如果因为HAL_Delay()或在其他中断服务函数中调用了HAL_Delay()由于 SysTick 中断的优先级可能低于当前中断HAL_Delay()会卡死。这种问题跟 RTC 中断不触发不一样别混在一起排查。我这次的项目里因为在RTC_IRQHandler中调用了HAL_Delay()导致系统看起来像死机了实际上不是没触发而是触发后卡死在延时等待。排查时要区分“中断没进”和“中断进了但卡在里面”这两种完全不同的现象。4.5 常见问题速查表现象可能原因检查方法WUTF 置位但中断不进RTC_CR.WUTIE未使能查看寄存器值确认 HAL_RTCEx_SetWakeUpTimer_IT 被调用WUTF 置位且 WUTIE 为 1 但中断不进NVIC 未使能 RTC_IRQn查看 NVIC-ISER 对应位中断进了但回调不执行回调函数命名或文件未编译打断点确认是否进入 HAL_RTCEx_WakeUpTimerIRQHandler中断执行一次后不再触发唤醒定时器没有重新装载检查 HAL_RTCEx_SetWakeUpTimer_IT 是否在回调中重新调用睡眠中被唤醒但程序卡死时钟切换或 PWR 配置问题检查低功耗模式下的时钟源切换流程LSE 无法起振晶振匹配电容/驱动能力问题查看 LSERDY 位调整 LSE_DRIVE5. 低功耗场景下的特殊坑5.1 STM32L432KC 的低功耗模式与 RTC 唤醒组合L432 主打低功耗支持 Sleep、Low-power run、Low-power sleep、Stop 0/1/2、Standby 和 Shutdown 模式。RTC 在 Stop 和 Standby 模式下都能运行这也是很多低功耗产品让 RTC 负责定时唤醒的原因。但这里有个大坑在 Stop 模式下MSI 可能被关闭系统从 Stop 唤醒后需要重新配置时钟。CubeMX 生成的SystemClock_Config()使用 MSI 作为系统时钟时如果你在进入 Stop 前把 MSI 关闭了唤醒后需要HAL_RCC_ClockConfig重新配置否则系统跑在错误时钟频率下。RTC 中断本身能触发但系统不稳定看起来就像“RTC 中断出问题”。另外一个问题是在 Stop 模式中RTC 唤醒中断可以配置为 EXTI 事件线来唤醒 MCU。CubeMX 的 RTC 配置里有一项WakeUp interrupt internal和WakeUp interrupt external的区别如果你选择了 internal 中断即只唤醒 CPU 内核但不走 EXTI那么在 Stop 模式下EXIT 控制器无法通过该中断唤醒 MCU导致只有 Stop 模式退出不了反而表现为“中断不触发”。这个细节在 L432 参考手册里有明确解释我建议计划使用 Stop 模式唤醒功能的读者一定要检查 EXTI 相关配置。5.2 唤醒后立即重新配置 RTC 的时序问题低功耗场景中还存在另一个时序坑MCU 从 Stop 模式下被 RTC 唤醒后RTC 可能仍在运行但系统时钟要重新稳定。如果在系统时钟还没有稳定MSI 或 HSI16 没 ready时就去操作 RTC 寄存器读回的数据可能不对。保险做法是等HAL_RCC_ClockConfig返回成功后再访问 RTC。调试低功耗逻辑时我会在唤醒码路径的各个关键节点放置时间戳记录通过串口或 RTT 打印出来。对于无法打断的现场也可以借助逻辑分析仪观察 GPIO 翻转来确认唤醒流程。这个方法比单纯依靠仿真器可靠因为低功耗模式下调试器可能会把 MCU 从低功耗状态唤醒干扰真实运行场景。6. 针对 L432 系列的额外注意事项6.1 内核电压范围与 RTC 工作电压的关系L432 有多种内核电压范围选择Range 11.71V-3.6V最高性能、Range 21.71V-3.6V降低功耗。在某些低电压范围下Flash 的访问等待周期和部分外设的行为会受限。RTC 本身工作在备份域只要 VBAT 供电正常一般不受 VDD 电压范围影响。但如果你想在 Range 2 下跑 80MHz那是行不通的可能影响系统整体行为。我遇到的一个场景因为把PWR-CR5中的R1MODE写错导致系统运行在 Range 2Flash 读取速度跟不上代码执行异常表现为中断回调不执行。这个坑虽然不常见但排查起来非常隐蔽。6.2 复位类型对 RTC 的影响L432 有不同类型的复位电源复位、系统复位、备份域复位。RTC 寄存器和备份域的 SRAM 只有在备份域复位时才会被清除系统复位不会。这意味着下载新固件后如果不复位备份域旧的 RTC 状态可能残留导致新固件的配置没有完全生效。我在调试时发现使用 ST-Link 的“复位并运行”按钮有时候并不能触发备份域复位尤其是当你开启了RTC_CR.BKP相关保护或备份域写入保护时烧录器无法自动清理。所以如果遇到“新固件配置不起作用”的情况建议先手动做一次完整的断电重新上电或者调用库函数复位备份域再去分析 RTC 初始化是否成功。7. 实操记录从失败到跑通的完整过程先说明一下我的应用逻辑系统上电后初始化 RTC 和低功耗配置进入 Stop 模式等待 2 秒唤醒唤醒后读取传感器数据并通过串口 Debug 输出或通过某种无线链路上报然后再次进入 Stop 模式。实现这个流程的关键步骤在 CubeMX 中配置 LSE、RTC、唤醒定时器、NVIC在main()中调用HAL_RTCEx_SetWakeUpTimer_IT()启动唤醒中断重写HAL_RTCEx_WakeUpTimerEventCallback在其中执行唤醒处理并重新设置下一次唤醒通过HAL_PWR_EnterSTOPMode()进入 Stop 模式使用PWR_STOPENTRY_WFI使 MCU 等待中断唤醒配置 EXTI 唤醒线确保 RTC 唤醒事件能拉高 EXTI 线。我最初的失败代码中第四步和第五步的配置顺序有问题我先设置了 EXTI再调用HAL_PWR_EnterSTOPMode()然后 RTC 中断确实能唤醒但唤醒后没有重新配置时钟源导致传感器读取时 I2C 时序错乱。后来加上SystemClock_Config()的重新配置才解决。这再次验证了低功耗模式下 RTC 中断不只是“触发”的问题还涉及后续的系统恢复。对于 Stop 模式唤醒L432 需要在停止前关闭无关外设时钟否则唤醒后功耗不理想。在调试 RTC 中断这个阶段我先不追求功耗指标只是通过测量IDD估算是否进入了 Stop 模式。如果电流没有明显下降基本可以断定 Stop 进入失败或者存在看门狗、调试接口等阻止 Stop 的因素。8. 给同样在用 CubeMX 做 RTC 开发的读者几条建议第一不要只依赖 CubeMX 的自动代码务必用调试器看一眼关键寄存器。特别是RTC_CR.WUTIE、RTC_ISR.WUTF、NVIC-ISER这三个一眼就能定位大多数问题。我用的是 ST-Link 配合 IAR 或 STM32CubeIDE 的寄存器窗口操作很简单但能节省大量排查时间。第二HAL 库的HAL_RTCEx_SetWakeUpTimer_IT()必须在 NVIC 使能之后调用还是之前调用理论上前者或后者都可以但我的习惯是先使能 NVIC再启动唤醒定时器。因为如果你先启动定时器计数器立刻开始递减如果 NVIC 尚未使能第一次中断事件就会丢失。虽然定时器是周期性的下次还会触发但如果你的周期很长或者事件只在特定条件下产生就可能导致第一次中断永远丢失。第三养成看勘误手册的习惯。STM32L432 的勘误手册里确实提到过 RTC 在特定边界条件下的行为比如在初始化模式与用户模式切换时某些中断标志可能被意外清除或设置。虽然大多数情况下碰不到但当你觉得“寄存器完全正确但就是不行”的时候翻翻勘误手册可能会找到答案。第四多利用 STM32CubeMX 的“生成独立外设初始化代码”功能。在 Project Manager 里可以选择每个外设单独生成一个.c/.h对这样你可以单独查看 RTC 相关的初始化代码不会跟其他外设代码混在一起。我建议把 RTC 外设初始化独立出来方便日后维护和移植。第五如果在调试中发现 RTC 中断反复触发但只想在特定时间醒来可以在回调中清掉唤醒定时器对应的 EXTI 挂起位。实际场景中RTC 唤醒中断从 Stop 模式唤醒 MCU 后EXTI 线的挂起状态如果没有及时清除可能会在退出中断服务函数后再次引发中断导致 MCU 无法继续睡觉。这个现象在有的系列上比较礼貌但 L432 上实测要显式清除。最后我再分享一个小技巧调试 RTC 中断时可以先用 RTC 闹钟中断代替唤醒中断做验证。两者共享大部分中断链路但闹钟中断的配置路径略有不同。如果你连闹钟中断都能触发但唤醒中断不触发那问题基本锁定在唤醒定时器本身的配置上。反过来如果闹钟中断也不行就得回到 NVIC 和时钟配置去找原因。这种类比法在很多 STM32 外设调试中都很有效。
返回列表