STM32突然复位?教你查明真相,告别盲猜!

adminadmin 欧易资讯 2026-07-22 34 0

#endif /* __RESET_CAUSE_H__ */

3.2 核心实现

/* reset_cause.c */

#include "reset_cause.h"

/* 备份寄存器操作宏(STM32G0系列为例,注意:RTC基地址可能因芯片而异) */

/* 在G0系列上,备份寄存器由RTC模块控制,地址为RTC_BASE + 0x50 */

#define BKP_REG_ADDR(reg) (RTC_BASE + 0x50 + (reg * 4))

#define BKP_REG_WRITE(reg, val) (*(__IO uint32_t *)(BKP_REG_ADDR(reg)) = (val))

#define BKP_REG_READ(reg) (*(__IO uint32_t *)(BKP_REG_ADDR(reg)))

/* 复位原因字符串表 */

static const char* reset_cause_strings = {

"Unknown", /* 0 */

"POR/PDR Reset", /* 1 */

"BOR Reset", /* 2 */

"External Reset", /* 3 */

"IWDG Reset", /* 4 */

"WWDG Reset", /* 5 */

"Software Reset", /* 6 */

"Low Power Reset", /* 7 */

};

/**

* @brief 初始化复位原因检测

* @note 必须在系统启动后尽早调用,并在调用前确保RCC时钟(RCC外设)已使能。

* 此函数会读取并保存复位原因,然后清除复位标志位。

*/

void ResetCause_Init(void)

uint32_t csr_value;

ResetCause_t cause = RESET_CAUSE_UNKNOWN;

/* 1. 读取RCC_CSR寄存器 */

csr_value = RCC->CSR;

/* 2. 解析复位原因,注意优先级:通常按从高优先级到低优先级顺序判断,

* 以避免多个标志同时置位时产生误判。

* PORRSTF 优先级最高,LPWRRSTF 优先级最低。

*/

if (csr_value & RCC_CSR_PORRSTF) {

cause = RESET_CAUSE_POR_PDR;

} else if (csr_value & RCC_CSR_BORRSTF) {

cause = RESET_CAUSE_BOR;

} else if (csr_value & RCC_CSR_PINRSTF) {

cause = RESET_CAUSE_EXTERNAL;

} else if (csr_value & RCC_CSR_SFTRSTF) {

cause = RESET_CAUSE_SOFTWARE;

} else if (csr_value & RCC_CSR_IWDGRSTF) {

cause = RESET_CAUSE_IWDG;

} else if (csr_value & RCC_CSR_WWDGRSTF) {

cause = RESET_CAUSE_WWDG;

} else if (csr_value & RCC_CSR_LPWRRSTF) {

cause = RESET_CAUSE_LOW_POWER;

/* 3. 保存到备份寄存器 */

BKP_REG_WRITE(BKP_REG_RESET_CAUSE, (uint32_t)cause);

/* 4. 清除复位标志(写1清除RMVF位)

* 必须在所有读取和处理完成后执行,以防止后续代码修改标志位。

* 注意:RMVF位只清除复位标志,不影响其他配置。

*/

RCC->CSR |= RCC_CSR_RMVF;

/**

* @brief 获取上次复位原因

* @retval 复位原因枚举值

*/

ResetCause_t ResetCause_Get(void)

return (ResetCause_t)BKP_REG_READ(BKP_REG_RESET_CAUSE);

/**

* @brief 获取复位原因字符串

* @param cause 复位原因枚举值

* @retval 字符串指针

*/

const char* ResetCause_GetString(ResetCause_t cause)

if (cause > RESET_CAUSE_LOW_POWER) {

cause = RESET_CAUSE_UNKNOWN;

return reset_cause_strings;

/**

* @brief 打印复位原因到日志

* @note 需要在串口或其他日志输出设备初始化完成后调用。

* 如果日志设备初始化前就调用了此函数,可能不会有任何输出。

*/

void ResetCause_Print(void)

ResetCause_t cause = ResetCause_Get();

LOG_PRINTF("\r\n========================================\r\n");

LOG_PRINTF(" System Reset Detected!\r\n");

LOG_PRINTF(" Reset Cause: %s\r\n", ResetCause_GetString(cause));

LOG_PRINTF("========================================\r\n");

3.3 主函数调用示例

/* main.c */

#include "reset_cause.h"

/* 包含项目自己的串口初始化头文件 */

/* #include "usart.h" */

int main(void)

/* 1. 初始化HAL库 */

HAL_Init();

/* 2. 初始化串口(用于打印日志) */

/* MX_USART1_UART_Init(); */

/* 3. 初始化复位原因检测(必须在其他与日志相关的初始化之后调用,

* 但必须在RCC时钟初始化之后,且在清除RCC_CSR之前) */

ResetCause_Init();

/* 4. 打印复位原因 */

ResetCause_Print();

/* 5. 正常应用程序 */

while (1) {

/* 你的应用代码 */

四、不同STM32系列的适配

不同系列的STM32,RCC_CSR寄存器的位定义略有差异。一定要参考所使用的单片机型号。

五、实际应用案例

案例1:看门狗复位排查

某设备在现场频繁复位,客户投诉。通过日志发现:

========================================

System Reset Detected!

Reset Cause: IWDG Reset

========================================

确认是独立看门狗复位。进一步分析发现,主循环中有一个耗时操作超过了看门狗喂狗周期。优化后问题解决。

案例2:电源不稳排查

另一设备在特定工况下复位,日志显示:

========================================

System Reset Detected!

Reset Cause: BOR Reset

========================================

确认是欠压复位。检查电源发现,电机启动瞬间电压跌落超过BOR阈值。增加大电容后解决。

六、进阶技巧

待续。

STM32突然复位?教你查明真相,告别盲猜!

版权声明

本文仅代表作者观点,不代表xx立场。
本文系作者授权xx发表,未经许可,不得转载。

喜欢0评论已闭