在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,因此产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 。MM32内置两个看门狗(独立看门狗和窗口看门狗),提供了更高的安全性、时间的精确性和使用的灵活性,可以用来检测和解决由软件错误引起的故障,其中可以使用独立看门狗在stop低功耗模式下进行MCU不复位唤醒功能。
独立看门狗与窗口看门狗的区别
同样是看门狗,独立看门狗(IWDG)和窗口看门狗(WWDG)十分相似,但还是有些不同之处需要注意:
独立看门狗(IWDG)由专门的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效,可在停止(STOP)和待机(STANDBY)模式下工作。
窗口看门狗(WWDG)则由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
IWDG介绍
IWDG 最适合应用于那些需要看门狗作为一个正在主程序外,能够完全独立工作,并且对时间精度要求低的场合,可以在低功耗的停机和待机模式下唤醒或复位MCU。当计数器达到给定的超时值时,触发一个产生系统复位。在SPIN2x系列中,加入了IWDG中断功能。
• 自由运行的递减计数器
• 时钟由独立的振荡器提供(可在停止和待机模式下工作)
• 看门狗被激活后,则在计数器计数至 0x0000 时产生复位或外部中断信号。
注:MM32不同型号IWDG中断功能和中断线的设置不同,本文仅介绍MM32SPIN2x系列。
MM32SPIN2x系列芯片的独立看门狗的时钟来源为LSI(40kHz),根据预分频寄存器的值,LSI可以最多256分频,最少4分频,配合重装载寄存器,超时时间可以设置为最少0.1ms,最多26.2s,如下图
IWDG使用
使用IWDG的基本步骤如下:
1、(可选)配置看门狗外部中断线和中断函数;
2、配置独立看门狗的预分频系数和重装载值;
3、重载计数值喂狗;
4、启动看门狗。
在SPIN2x系列中,IWDG使用外部中断线24,与WWDG使用同一个中断处理函数,若使用IWDG中断,再退出中断之后需要重新配置IWDG。
下面我们简单的配置一下MM32SPIN27的IWDG中断模式:
1、(可选)配置看门狗外部中断线和中断函数
void Iwdg_Interrupt_Config() { NVIC_InitTypeDef NVIC_InitSturcture; EXTI_InitTypeDef EXTI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能外部中断 EXTI_InitStructure.EXTI_Line = EXTI_Line24; //IWDG中断线 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 EXTI_Init(&EXTI_InitStructure); NVIC_InitSturcture.NVIC_IRQChannel = WWDG_IRQn; NVIC_InitSturcture.NVIC_IRQChannelCmd = ENABLE; NVIC_InitSturcture.NVIC_IRQChannelPriority = 0; NVIC_Init(&NVIC_InitSturcture); GPIO_LED_Config();//使用LED显示看门狗是否进入中断 } void WWDG_IRQHandler()//IWDG与WWDG使用同一个中断函数 { GPIOB->ODR ^= GPIO_Pin_4; iwdg_flag = 1; EXTI->PR |= 0x1 << 24; IWDG_ClearIT(); UartSendGroup((u8 *)printBuf, sprintf(printBuf, "interrupt\r\n")); }
2、配置独立看门狗
void PVU_CheckStatus(void)//查询看门狗预分频更新标志 { while (1) if (IWDG_GetFlagStatus(IWDG_FLAG_PVU) == RESET) break; } void RVU_CheckStatus(void)//查询看门狗计数器重载值更新标志 { while (1) if (IWDG_GetFlagStatus(IWDG_FLAG_RVU) == RESET) break; } void Interrput_Iwdg_ON(unsigned short int IWDG_Prescaler, unsigned short int Reload) { RCC_LSICmd(ENABLE);//启用LSI并等待时钟就绪 while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET); PVU_CheckStatus();//配置时钟分频 IWDG_WriteAccessCmd(0x5555); IWDG_SetPrescaler(IWDG_Prescaler); RVU_CheckStatus();//配置重装载值 IWDG_WriteAccessCmd(0x5555); IWDG_SetReload(Reload & 0xfff); IWDG_EnableIT(); //启用中断模式 IWDG_ReloadCounter();//使能IWDG前先喂狗 IWDG_Enable(); }
3、时钟配置函数
void HSI_SYSCLK(void)//设置为HIS 8分频 { RCC_HSICmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY)==RESET); RCC->CFGR &=~ 0xf; while((RCC->CFGR&0xf) != 0x0); }
4、main函数
int main(void) { HSI_SYSCLK(); //设置为HIS 8分频 Uart_ConfigInit(9600); UartSendGroup((u8 *)printBuf, sprintf(printBuf, "sprintf ok\r\n")); Iwdg_Interrupt_Config();//中断配置 Interrput_Iwdg_ON(IWDG_Prescaler_16, 0xFFF); //配置并使能IWDG PWR_EnterSTOPMode(0, PWR_STOPEntry_WFI);//进入STOP模式 while (1) { if (iwdg_flag) { iwdg_flag = 0; Interrput_Iwdg_ON(IWDG_Prescaler_16, 0xFFF); //退出中断函数后重新配置IWDG,建议在清除中断标志位之后有一个延迟在执行这一函数 PWR_EnterSTOPMode(0, PWR_STOPEntry_WFI); //进入STOP模式 } // IWDG_ReloadCounter(); //取消注释开启喂狗 } }
运行结果
编译下载并运行程序,在GPIO的B4引脚上接上一个LED灯,我们可以看到LED灯在闪烁,在UART定时输出”interrupt”,如图3。使用设备记录MCU的供电电流,可以得到图4,在STOP模式下电流仅为3.8uA,持续1.36s唤醒,电流增加为1.65mA。我们可以改变Interrput_Iwdg_ON()函数中的分频值和重装载值来得到想要的唤醒间隔。
到这里,一个简单的IWDG中断程序就配置好了。
相比复位模式,在IWDG的中断模式中,我们可以根据需要,在超时的时候向外界发送一些信息,比如MCU的运行状态,更加方便的调试程序。
本文转自: 灵动MM32MCU(MindMotion-MMCU),转载此文目的在于传递更多信息,版权归原作者所有。