“ STM32 复位至关重要,有系统、电源和备份域复位三种类型。本文详解其分类、工作原理,还给出外部复位、看门狗复位等实验步骤,以及复位后寄存器值变化。”
01
—
单片机复位简介
单片机复位是指将系统恢复到初始化状态,确保程序从已知状态开始执行。
stm32共有三种类型的复位,分别为系统复位、电源复位和备份域复位。
常见的应用场景为:
1.上电复位确保硬件(时钟、外设)和软件(变量、堆栈)处于默认状态,避免随机值导致异常。
2.程序跑飞,看门狗复位,恢复系统运行。
3.设备卡死,NRST外部复位实现硬件重启。
4.设备因异常(如电压波动、程序跑飞)导致RTC或备份寄存器配置损坏(例如时钟源错误、写保护异常),通过BDRST复位备份域控制寄存器,恢复RTC默认配置。
NRST 引脚低电平触发的是 系统复位(System Reset),而非 电源复位(Power Reset)。
02
—
复位的分类
系统复位
除了时钟控制寄存器 CSR 中的复位标志和备份域中的寄存器外,系统复位会将其它全部寄存器都复位为复位值。
只要发生以下事件之一,就会产生系统复位:
1. NRST 引脚低电平(外部复位)。
2. 窗口看门狗计数结束(WWDG 复位)。
3. 独立看门狗计数结束(IWDG 复位)。
4. 软件复位(SW 复位)(请参见 软件复位 )。
5. 低功耗管理复位(请参见 低功耗管理复位 )。
电源复位
只要发生以下事件之一,就会产生电源复位:
1. 上电/掉电复位(POR/PDR 复位)或欠压 (BOR) 复位。
2. 在退出待机模式时。
备份域复位
备份域复位会将所有 RTC 寄存器和 RCC_BDCR 寄存器复位为各自的复位值。BKPSRAM 不受此复位影响。BKPSRAM 的唯一复位方式是通过 Flash 接口将 Flash 保护等级从 1 切换到 0。
只要发生以下事件之一,就会产生备份域复位:
1. 软件复位,通过将 RCC 备份域控制寄存器 (RCC_BDCR) 中的 BDRST 位置 1 触发。
2. 在电源 V DD 和 V BAT 都已掉电后,其中任何一个又再上电。
03
—
复位的工作原理
复位从触发到系统初始化的完整流程可分为四个阶段:
1. 复位信号生成阶段
•任意复位源(如 POR、NRST 引脚)触发后,复位控制器根据优先级生成统一复位信号。
•信号经过延时电路确保脉冲宽度足够(如 POR 需等待电压稳定)。
2. 系统模块复位阶段
•CPU 暂停当前指令,清除寄存器状态并从复位向量地址(0x08000004)读取启动地址。
•系统总线将复位信号传播至所有外设,各模块寄存器恢复默认值(如 GPIO 设为输入模式)。
3. 复位状态记录阶段
•RCC_CSR 寄存器记录最近一次复位类型,标志位包括:
PORF(上电 / 掉电复位)、PINRF(NRST 引脚复位)、IWDGRF(独立看门狗复位)等。
•软件可通过读取标志位判断复位原因(如程序异常重启时定位问题)。
4. 系统初始化与启动阶段
•CPU 从复位向量地址获取 PC 初始值,执行启动代码(如配置栈指针、中断向量表)。
•初始化系统时钟(HSI/HSE/PLL)、外设(如 USART、ADC)及全局变量。
•跳转到main()函数,应用程序开始正常运行。
04
—
复位的实现方法
系统复位实验步骤:
1. NRST 引脚低电平(外部复位)
void main(void){ char ch; /* 初始化HAL库;它必须是主程序中执行的第一条指令 */ HAL_Init(); /* 系统时钟初始化成168MHz */ SystemClock_Config(); /* LED 端口初始化 */ LED_GPIO_Config(); /* 初始化串口1 */ DEBUG_USART_Config(); /* 打印指令输入提示信息 */ Show_Message(); /* 控制LED灯 */ while (1) { ch=getchar(); printf("接收到字符:%c\n",ch); /* 根据字符指令控制RGB彩灯颜色 */ switch(ch) { case '1': LED_RED; break; case '2': LED_GREEN; break; case '3': LED_BLUE; break; case '4': LED_YELLOW; break; case '5': LED_PURPLE; break; case '6': LED_CYAN; break; case '7': LED_WHITE; break; case '8': LED_RGBOFF; break; default: /* 如果不是指定指令字符,打印提示信息 */ Show_Message(); break; } }}
2. 窗口看门狗计数结束(WWDG 复位)
int main(void){ // 看门狗复位时,读取寄存器的值 rcc_cr = RCC->CR; rcc_pllcfgr = RCC->PLLCFGR; rcc_csr = RCC->CSR; /* 初始化HAL库;它必须是主程序中执行的第一条指令 */ HAL_Init(); /* 系统时钟初始化成168MHz */ SystemClock_Config(); /* LED 端口初始化 */ LED_GPIO_Config(); // 读取窗口设置值 wwdg_wr = WWDG->CFR & 0X7F; LED2_OFF; /* 控制LED灯 */ while (1) { // 读取当前计数值 wwdg_tr = WWDG->CR & 0X7F; if( wwdg_tr == wwdg_wr) { LED2_ON; } }}
3. 独立看门狗计数结束(IWDG 复位)
int main(void){ //1s内不按下按键,IWDG产生复位,读取相关寄存器 rcc_cr = RCC->CR; rcc_pllcfgr = RCC->PLLCFGR; rcc_csr = RCC->CSR; /* 初始化HAL库;它必须是主程序中执行的第一条指令 */ HAL_Init(); /* 系统时钟初始化成168MHz */ SystemClock_Config(); /* LED 端口初始化 */ LED_GPIO_Config(); /*初始化按键*/ Key_GPIO_Config(); // IWDG,64分频,重装载值为625,超时溢出时间≈1s IWDG_Config(IWDG_PRESCALER_64 ,625); LED2_OFF; while (1) { if( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON ) { // 喂狗,如果不喂狗,系统则会复位,复位后亮红灯,如果在1s // 时间内准时喂狗的话,则会亮绿灯 IWDG_Feed(); //喂狗后亮绿灯 LED2_ON; } }}
4. 软件复位(SW 复位)
int main(void){ /* 初始化HAL库;它必须是主程序中执行的第一条指令 */ HAL_Init(); /* 系统时钟初始化成168MHz */ SystemClock_Config(); /* LED 端口初始化 */ LED_GPIO_Config(); /*初始化按键*/ Key_GPIO_Config(); // 检查复位标志位 if (RCC->CSR & RCC_CSR_SFTRSTF) { // 软件复位成功 RCC->CSR |= RCC_CSR_RMVF; // 清除复位标志 LED2_ON; // 点亮LED2表示复位成功 HAL_Delay(1000); // 延迟1秒 LED2_OFF; //产生软件复位,读取相关寄存器 rcc_cr = RCC->CR; rcc_pllcfgr = RCC->PLLCFGR; rcc_csr = RCC->CSR; } while (1) { //按键按下,产生软件复位 if( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON ) { LED2_ON; System_Reset(); } }} void System_Reset(void){ __DSB(); // 数据同步屏障,确保所有内存访问完成 SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk); // 触发系统复位 __DSB(); // 等待复位完成 while(1); // 进入死循环,等待复位发生}
电源复位实验步骤:
void main(void){ rcc_cr = RCC->CR; rcc_pllcfgr = RCC->PLLCFGR; rcc_csr = RCC->CSR; while (1) { __NOP(); }}
通过硬件操作(完全掉电再上电)触发 POR/PDR(Power-On/Power-Down Reset),并在复位后立即读取 RCC_CR 寄存器,验证其值为 0x0000 XX83。
关键点: 程序上电后 不做任何 RCC 配置,直接读取 RCC->CR 并打印。 使用串口打印,便于观察结果(也可用 LED 闪烁表示,但串口更直观)。
备份域复位实验步骤:
int main(void){ /* 初始化HAL库;它必须是主程序中执行的第一条指令 */ HAL_Init(); /* 系统时钟初始化成168MHz */ SystemClock_Config(); /* LED 端口初始化 */ LED_GPIO_Config(); /*初始化按键*/ Key_GPIO_Config(); rcc_cr = RCC->CR; rcc_pllcfgr = RCC->PLLCFGR; rcc_csr = RCC->CSR; while (1) { //按键按下,产生软件复位 if( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON ) { LED2_ON; BackupDomainReset(); } } /* * 备份域复位函数 */ void BackupDomainReset(void) { /* 使能PWR时钟 */ __HAL_RCC_PWR_CLK_ENABLE(); /* 允许访问备份域 */ HAL_PWR_EnableBkUpAccess(); /* 备份域复位 */ __HAL_RCC_BACKUPRESET_FORCE(); __HAL_RCC_BACKUPRESET_RELEASE(); }
05
—
总结
1.系统复位:复位除备份域和 RCC_CSR 标志位外的所有寄存器。不会重新加载 RCC_CR 的硬件默认值,而是将寄存器清零(0x0000 0000)。
2.电源复位:手册给出的 0x0000 XX83(低字节为 0x83)是芯片从 完全掉电状态(POR/PDR) 上电时的初始值。
•位 0 (HSION) = 1 → HSI 振荡器强制开启
•位 1 (HSIRDY) = 1 → HSI 已就绪
•位 7 (HSICAL[7:0]) = 出厂校准值 → HSI 频率校准
这是芯片在 电源域首次上电 时的状态,由硬件自动加载
3.三种类型复位后寄存器值变化如下表:
|
寄存器类型 |
电源复位后值 |
系统复位后值 |
备份域复位后值 |
|
RCC_CSR |
复位值(除复位标志位) |
复位值(除复位标志位) |
不变 |
|
备份域 |
不变 |
不变 |
仅RTC 寄存器和 RCC_BDCR 寄存器复位 |
|
其它 |
复位值 |
复位值 |
不变 |
4.备份域寄存器说明如下表:
|
寄存器名称 |
功能说明 |
是否属于备份域 |
|
RCC_BDCR |
备份域控制寄存器(控制LSE、RTC时钟源、BDRST等) |
✅ 是 |
|
RTC寄存器 |
RTC_CR、RTC_TR、RTC_DR等所有RTC控制/时间/日期寄存器 |
✅ 是 |
|
RTC备份寄存器 |
RTC_BKP0~RTC_BKP19(20个32位备份寄存器) |
✅ 是 |
|
备份SRAM |
4KB备份SRAM(如STM32F4xx的BKPSRAM) |
✅ 是 |
|
LSE振荡器 |
低速外部32.768kHz晶振(通过RCC_BDCR控制) |
✅ 是 |
|
VBAT电源域 |
由VBAT引脚(电池)独立供电的电路(维持备份域在VDD掉电时工作) |
0