在工作中遇到较为复杂的项目时,往往需要使用软件复位来重启单片机,我刚刚接手的一个项目中就遇到了这样的情况:项目中用了较多的任务和中断处理,在出现某些特定情况时,必须重新启动设备,于是就用了软件复位的方式,调用NVIC_SystemReset()函数来进行软件复位。
但是在代码运行过程中却发现了这样的问题:当某一条件成立,程序跑到NVIC_SystemReset()函数后,并没有重新运行,而是卡死了。
经过分析发现原因:NVIC_SystemReset()函数是通过将SYSRESETREQ置位有效来复位的,但是从SYSRESETREQ 被置为有效,到复位发生器执行复位命令,有一个延时,在这个延时期间,CPU可以被其他中断打断。但我们的要求是程序执行到这个函数之后立即停止,不再处理任何事件;
所以,最好在发出复位请求前,先把FAULTMASK置位,也就是加上这个函数:__set_FAULTMASK(1);意思是关闭所有中断的意思,目的是在执行NVIC_SystemReset()复位函数过程中不被中断所打断。两个函数执行后系统复位重新执行代码,包括之前所配置好的外设寄存器也都回到复位状态。
完整的重启方法是:
__set_FAULTMASK(1); //关闭所有中断
NVIC_SystemReset(); //复位
如果上面这两行代码还是无法完成软件复位的话,可以找到NVIC_SystemReset()函数的源代码:
static __INLINE void NVIC_SystemReset(void)
{
SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk); /* Keep priority group unchanged */
__DSB(); /* Ensure completion of memory access */
while(1); /* wait until reset */
}
把上述代码中第5行的SCB_AIRCR_SYSRESETREQ_Msk 修改为 SCB_AIRCR_VECTRESET_Msk 即可。
我在工程中用的是第二种方法,目前亲测没问题