本帖最后由 Alden 于 2023-11-6 14:32 编辑
#申请原创# #技术资源#
应用开发中有时需要区分不同的状态来进行不同的操作。
比如上电复位进行比较长的自检,而软件指令或者复位按键进行复位不需要。
或者需要监测是否出现看门狗复位,表示程序运行出现过异常没有喂狗。
通过查看APM32F103系列的用户手册可以在复位与数字隔离的寄存器中找到相关描述
NRST** (发生 NRST 引脚复位标志):NRST引脚出现复位型号就会置位,软硬件复位方式都会有NRST复位。
PODRST**(发生上电/掉电复位标志):发生上电/掉电复位就会置位。
SWRST**(发生软件复位标志):发生软件复位标志会置位,例如 __NVIC_SystemReset();
IWDTRST**(发生独立看门狗复位标志):发生独立看门狗复位会置位。
WWDTRST**(发生窗口看门狗复位标志):发生窗口看门狗复位会置位。
LPWRRST**(发生低功耗复位标志):发生低功耗复位会置位,需要选项字节配置低功耗复位。
以上标志位发生后不会自动清空,可以写RST**CLR(清除复位标志)来清空复位标志位。
代码首先可以直接读寄存器判断,或者调用库函数来判断是哪个标志位置位了。
void ReadRSTflag(void)
{
printf("\r\nRCM->CSTS=%x\r\n",RCM->CSTS);
if(SET==RCM_ReadStatusFlag(RCM_FLAG_PINRST))
{
printf("发生NRST引脚复位\r\n");
}
if(SET==RCM_ReadStatusFlag(RCM_FLAG_PORRST))
{
printf("发生上电掉电复位\r\n");
}
if(SET==RCM_ReadStatusFlag(RCM_FLAG_SWRST))
{
printf("发生软件复位\r\n");
}
if(SET==RCM_ReadStatusFlag(RCM_FLAG_IWDTRST))
{
printf("发生独立看门狗复位\r\n");
}
if(SET==RCM_ReadStatusFlag(RCM_FLAG_LPRRST))
{
printf("发生低功耗复位\r\n");
}
if(SET==RCM_ReadStatusFlag(RCM_FLAG_WWDTRST))
{
printf("发生窗口看门狗复位\r\n");
}
RCM_ClearStatusFlag();
}
读标志位后进行一次清标志位,避免下次读时受影响。
int main(void)
{
RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
APM_MINI_LEDInit(LED2);
APM_MINI_LEDInit(LED3);
APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);
usart1_init();
UserOptionByt();
APM_MINI_LEDOn(LED2);
APM_MINI_LEDOff(LED3);
PMU_EnableWakeUpPin();
PMU_EnableBackupAccess();
RTC_Init();
SysTick_Init();
ReadRSTflag();
while(1)
{
}
}
基本的软件逻辑就是上电初始化后读复位标志位,来判断上一次复位的来源,用串口打印出来。
接下来就可以烧录代码到APM32F103VC开发板中,简单测试下个复位标志位的功能。
1.上电/掉电复位
给开发板断电后再上电,可以看到能识别到NRST引脚复位和上电掉电复位。
2、复位按键复位
上电状态按开发板复位按键,可以看到串口正确打印了NRST引脚复位。
3、软件复位
软件复位就是通过单片机的软件复位指令__NVIC_SystemReset();进行复位,
void SystemReset(void)
{
__NVIC_SystemReset();
}
int main(void)
{
RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)(RCM_APB1_PERIPH_PMU | RCM_APB1_PERIPH_BAKR));
APM_MINI_LEDInit(LED2);
APM_MINI_LEDInit(LED3);
APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_EINT);
usart1_init();
UserOptionByt();
APM_MINI_LEDOn(LED2);
APM_MINI_LEDOff(LED3);
PMU_EnableWakeUpPin();
PMU_EnableBackupAccess();
RTC_Init();
SysTick_Init();
ReadRSTflag();
while(1)
{
Delay();
SystemReset();
}
}
设置复位函数后在main中,延时一小段时间运行软件复位,MCU复位后串口就能打印出发生了软件复位。
4、独立看门狗复位。
独立看门口可以软件初始化打开或者通过配置选项字节开启硬件见看门狗,因为低功耗复位也是需要选项字节配置。
所以都使用选项字节配置打开硬件看门狗。窗口看门狗的效果跟独立看门狗的差不多,就不单独测试了。
void UserOptionByt(void)
{
FMC_UserConfig_T FMC_ConfigStruct;
FMC_ConfigStruct.iwdtSet=OB_IWDT_HARD;
FMC_ConfigStruct.stopSet=OB_STOP_NORST;
FMC_ConfigStruct.stdbySet=OB_STDBY_NORST;
FMC_Unlock();
FMC_EraseOptionBytes();
FMC_ConfigUserOptionByte(&FMC_ConfigStruct);
FMC_Lock();
}
配置选项字节打开硬件看门狗,不配置喂狗,就会一直发生独立开门狗复位。
5、低功耗复位
低功耗复位是在选项字节中配置,进入低功耗就会发生复位。配置按键进入standby低功耗。
void UserOptionByt(void)
{
FMC_UserConfig_T FMC_ConfigStruct;
FMC_ConfigStruct.iwdtSet=OB_IWDT_SOTF;
FMC_ConfigStruct.stopSet=OB_STOP_NORST;
FMC_ConfigStruct.stdbySet=OB_STDBY_RST;
FMC_Unlock();
FMC_EraseOptionBytes();
FMC_ConfigUserOptionByte(&FMC_ConfigStruct);
FMC_Lock();
}
void EINT1_IRQHandler(void)
{
if(EINT_ReadIntFlag(KEY1_BUTTON_EINT_LINE) != RESET)
{
EINT_ClearIntFlag(KEY1_BUTTON_EINT_LINE);
APM_MINI_LEDOn(LED2);
RTC_ClearStatusFlag(RTC_FLAG_SEC);
while(RTC_ReadStatusFlag(RTC_FLAG_SEC) == RESET);
RTC_ConfigAlarm(RTC_ReadCounter()+ 3);
RTC_WaitForLastTask();
PMU_ClearStatusFlag(PMU_FLAG_WUE);
PMU_EnterSTANDBYMode();
}
}
由次可以看到,MCU对复位标志的判断还是很准确的,有这方面需求的可以参考我配置使用。
APM32F10x_SDK_V1.8.zip
(1.78 MB)
|
通过APM32F103 的复位标志位,追踪程序复位状态,便于调试和异常跟踪,在特殊场合十分实用。