最近在项目的时候需要判别STM32的复位类型,网上这部分资料也有许多大神进行总结。但是感觉不是特别深入,因此,小编参考参考了STM32的参考手册进行详细总结了一下。
1、STM32的三种复位类型
分别为系统复位、电源复位和备份域复位。每一种型号的STM32都包含有这三种复位类型!
1.1、系统复位
除了时钟控制寄存器 CSR 中的复位标志和备份域中的寄存器外,
系统复位会将其它全部寄存器都复位为复位值,只要发生以下事件之一,就会产生系统复位:
- NRST 引脚低电平(外部复位)
- 窗口看门狗计数结束( WWDG 复位)
- 独立看门狗计数结束( IWDG 复位)
- 软件复位( SW 复位)
- 低功耗管理复位
1.1.1、软件复位
要对器件进行软件复位,必须将 Cortex™-M4F 应用中断和复位控制寄存器中的SYSRESETREQ 位置 1,标准库和HAL库默认都是置1的,软件复位的代码如下:
void NVIC_SystemReset(void)
{
__DSB();
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk);
__DSB();
while(1);
}
1.1.2、低功耗管理复位
引发低功耗管理复位的方式有两种:
- 进入待机模式时产生复位:
此复位的使能方式是清零用户选项字节中的 nRST_STDBY 位。使能后,只要成功执行
进入待机模式序列,器件就将复位,而非进入待机模式。 - 进入停止模式时产生复位:
此复位的使能方式是清零用户选项字节中的 nRST_STOP 位。使能后,只要成功执行
进入停止模式序列,器件就将复位,而非进入停止模式。
1.2、电源复位
除备份域内的寄存器以外,电源复位会将其它全部寄存器设置为复位值。只要发生以下事件之一,就会产生电源复位:
- 上电/掉电复位( POR/PDR 复位)或欠压 (BOR) 复位
- 在退出待机模式时
这些源均作用于 NRST 引脚,该引脚在复位过程中始终保持低电平。 RESET 复位入口向量
在存储器映射中固定在地址 0x0000_0004。
芯片内部的复位信号会在 NRST 引脚上输出。脉冲发生器用于保证最短复位脉冲持续时间,
可确保每个内部复位源的复位脉冲都至少持续 20 μs。 对于外部复位,在 NRST 引脚处于低
电平时产生复位脉冲。
1.3、备份域复位
备份域复位会将所有 RTC 寄存器和 RCC_BDCR 寄存器复位为各自的复位值。只要发生以下事件之一,就会产生备份域复位:
- 软件复位,通过将 RCC 备份域控制寄存器 (RCC_BDCR) 中的 BDRST 位置 1 触发。
- 在电源 VDD 和 VBAT 都已掉电后,其中任何一个又再上电。
BKPSRAM 不受此复位影响。 BKPSRAM 的唯一复位方式是通过 Flash 接口将 Flash 保护等级从 1 切换到 0。
2、STM32复位类型的区分
在实际项目中需要判断复位的类型,从而进行下一步动作。
判断复位类型的寄存器是RCC_CSR寄存器(RCC 时钟控制和状态寄存器 ),STM32的参考手册如下介绍:
由上面的寄存器介绍可以知道,我们直接读取这个寄存器的值就能知道是什么引起的复位。
读取完成后记得要将第24位,即RMVF置1。清除复位的标志。
2.1、STM32区分复位类型的代码实现
直接操作寄存器的代码:
if(0 != (RCC->CSR & 0x80000000))//低功耗复位标志
{
printf("低功耗复位\r\n");
}
else if(0 != (RCC->CSR & 0x40000000))//窗口看门狗复位标志
{
printf("窗口看门狗复位\r\n");
}
else if(0 != (RCC->CSR & 0x20000000))//独立看门狗复位标志
{
printf("独立看门狗复位\r\n");
}
else if(0 != (RCC->CSR & 0x10000000))//软件复位标志
{
printf("软件复位\r\n");
}
else if(0 != (RCC->CSR & 0x08000000))//上电/掉电复位标志
{
printf("上电/掉电复位\r\n");
}
else if(0 != (RCC->CSR & 0x04000000))//引脚复位标志
{
printf("引脚复位\r\n");
}
else if(0 != (RCC->CSR & 0x02000000))//BOR 复位标志
{
printf("BOR复位\r\n");
}
RCC->CSR |= 0x01000000;//清除复位标志
使用标准库的代码:
if(1 == RCC_GetFlagStatus(RCC_FLAG_LPWRRST))//低功耗复位标志
{
printf("低功耗复位\r\n");
}
else if(1 == RCC_GetFlagStatus(RCC_FLAG_WWDGRST))//窗口看门狗复位标志
{
printf("窗口看门狗复位\r\n");
}
else if(1 == RCC_GetFlagStatus(RCC_FLAG_IWDGRST))//独立看门狗复位标志
{
printf("独立看门狗复位\r\n");
}
else if(1 == RCC_GetFlagStatus(RCC_FLAG_SFTRST))//软件复位标志
{
printf("软件复位\r\n");
}
else if(1 == RCC_GetFlagStatus(RCC_FLAG_PORRST))//上电/掉电复位标志
{
printf("上电/掉电复位\r\n");
}
else if(1 == RCC_GetFlagStatus(RCC_FLAG_PINRST))//引脚复位标志
{
printf("引脚复位\r\n");
}
else if(1 == RCC_GetFlagStatus(RCC_FLAG_BORRST))//BOR 复位标志
{
printf("BOR复位\r\n");
}
RCC_ClearFlag();//清除复位标志
3、复位和iap_load_app的区别
- 发生复位,系统会记录一些标志信息。
- 但是使用iap_load_app跳转到0x8000000的位置,系统会一直默认在执行。不会有复位的标志返回。
如果在代码中使用iap_load_app来代替复位是可行的,即将复位函数NVIC_SystemReset();替换成iap_load_app(FLASH_BASE);即可。
此时RCC->CSR寄存器为0。
if(0 == RCC->CSR)
{
printf("跳转\r\n");
}
RCC_ClearFlag();//清除复位标志
delay_ms(3000);
iap_load_app(FLASH_BASE);
结束
欢迎大家关注我的微信号:redeemer奇
一起交流!一起努力!