独立看门狗(IWDG)由专用的低速时钟(LSI)驱动(40kHz),即使主时钟发生故障它仍有效。独立看门狗适合应用于需要看门狗作为一个在主程序之外 能够完全独立工作,并且对时间精度要求低的场合。
窗口看门狗由从APB1时钟(36MHz)分频后得到时钟驱动。通过可配置的时间窗口来检测应用程序非正常的过迟或过早操作。 窗口看门狗最适合那些要求看门狗在精确计时窗口起作用的程序。
一、独立看门狗
1、独立看门狗简介
看门狗其实就是一个定时器,从功能上说它可以让微控制器在程序发生意外(程序进入死循环或跑飞)的时候,能重新回复到系统刚上电状态,以保障系统出问题的时候可以重启一次。说的复杂一点,看门狗就是能让程序出问题是能重新启动系统 STM32的独立看门狗(IWDG)由内部专门的40KHz低速时钟驱动,即使主时钟发生故障,它也仍然有效。注意IWDG的时钟是一个内部RC时钟,是一个在30~60KHz之间的一个可变化的时钟,只是我们在估算的时候以40KHz的频率来计算,看门狗对时间的要求不是很精确 独立看门口功能框图如下。实际上独立看门口狗是一个递减计数器,当计时器的值减到0时,IWDG会产生一个复位信号,系统复位重新启动。为避免产生看门狗复位,则需在计数器减到0之前重载计数器,即“喂狗”。当程序出错时没有刷新计数器,计数器递减到0,系统复位重新启动,避免程序继续错误运行
独立看门狗超时时间(40KHz的输入时钟LSI)
2、 硬件设计
使用USART1来打印调试信息,LED2用来指示程序是否复位。利用按键S1选择是否喂狗。
3、 STM32CubeMX设置
- RCC设置外接HSE,时钟设置为72M;WWDG的时钟挂载在APB1上
- PE5设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
- PE4设置为GPIO输入模式、上拉模式
- USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
- 激活IWDG,IWDG的时钟为40kHz,此时设置计数器时钟为32分频,则分频后的时钟频率为1.25KHz(时钟周期为1s/1250 = 0.8ms),递减基础器重载值(down-counter reload value)配置为1000,即800ms不刷新IWDG则系统复位
超出(溢出)时间计算:
Tout=((4×2^PRER) ×RLR)/LSI时钟频率
Tout=((4×2^PRER) ×RLR)/LSI=((4×2^3) ×1000)/40=800ms
输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
4、程序编程
在iwdg.c文件中可以看到独立看门狗的初始化函数
void MX_IWDG_Init(void)
{
/* USER CODE BEGIN IWDG_Init 0 */
/* USER CODE END IWDG_Init 0 */
/* USER CODE BEGIN IWDG_Init 1 */
/* USER CODE END IWDG_Init 1 */
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_32;
hiwdg.Init.Reload = 1000;
if (HAL_IWDG_Init(&hiwdg) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN IWDG_Init 2 */
/* USER CODE END IWDG_Init 2 */
}
main函数中添加调试程序,while中检测按键是否按下,按键没按下就喂狗,程序不会重启。当按键按下时,不在进行喂狗,程序重启。
int main(void)
{
///****省略****///
/* USER CODE BEGIN WHILE */
printf1("IWDG 测试!\r\n");//初始先输出测试
while (1)
{
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0) //S1 按下
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0)
{
printf1("S1 按下,不喂狗了\r\n");
}
}
else
{
HAL_IWDG_Refresh(&hiwdg); //喂狗
printf1("S1 没有按下,正常喂狗\r\n");
}
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
5、下载验证
程序编译无误后下载到板子上查看效果,按键没按下就喂狗,程序不会重启。当按键按下时,不在进行喂狗,程序重启。
二、窗口看门狗
1、窗口看门狗简介
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障;除非递减计数器的值在T6位变成0前被刷新,看门狗电路在达到预置的时间周期时,会产生一个MCU复位,在递减计数器达到窗口寄存器数值之前,如果7位的递减计数器数值被刷新,也将产生一个MCU复位。因此递减计数器需要在一个有限的时间窗口中被刷新,其主要特性有:
- 可编程的自由运行递减计算器
- 条件复位:当递减计数器的值小于0x40,则产生复位;当递减计数器在窗口外被重新装载,则产生复位
- 如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可用于重新装载计数器以避免WWDG复位
看门狗框图
窗口看门狗时序图
上图中,T[6:0]就是窗口看门狗的计数器,W[6:0]是窗口看门狗的上窗口、下窗口是固定值(0x40),WWDG计数器的频率为:PCLK1/(4096 * 计数器预分频值),由于PCLK1时钟频率过高因此除以4096 WWDG超时时间:(4096 * 计数器预分频值)*(T[5:0]+1)/PCLK1,此处T[5:0]+1即为T[6:0]-0x3F
窗口看门狗计数器的值只有在2和3 之间(上窗口和下窗口之间)才可以喂狗,并且窗口看门狗还可以使能中断,如果使能了提前唤醒中断,系统出现问题,喂狗函数没有生效,那么在计数器由减到0x40 (0x3f+1) 的时候,便会先进入中断,之后才会复位,你也可以在中断里面喂狗
2、硬件设计
使用USART1来打印调试信息,PC0用来指示程序是否复位
3、 STM32CubeMX设置
- RCC设置外接HSE,时钟设置为72M;WWDG的时钟挂载在APB1上
- PE5设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平
- PE4设置为GPIO输入模式、上拉模式
- USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位
- 激活WWDG,计数器预分频值设为8,窗口寄存器设为W[6:0] = 0x5A,递减计数器刷新值设置为T[6:0] = 0x7F;根据公式算出超时时间为 (4096 * 8)*(127-63)/ 36MHz = 53.8ms;使能EWI中断,在NVIC设置中开启窗口看门狗中断
个人理解是,使能了看门狗计时器后,计数器会从上窗口值(127)一直减到下窗口值(0x40-1即63),当计数器减到63时触发中断,在中断中重新喂狗让计数器的值重置为127。其实当计数器的值减到90的时候也是可以进行喂狗的,但并不会触发中断。
而计数器减1的周期是 (4096 * 8)/ 36MHz =0. 91ms;从127减到63需要计数64(127-63),也就是说每触发一次中断的间隔为64*0.91=53.8ms
使能看门狗中断
输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码
4、程序编程
- 在wwdg.c文件中可以看到窗口看门狗的初始化函数
void MX_WWDG_Init(void){
hwwdg.Instance = WWDG;
hwwdg.Init.Prescaler = WWDG_PRESCALER_8;
hwwdg.Init.Window = 0x5a;
hwwdg.Init.Counter = 0x7f;
hwwdg.Init.EWIMode = WWDG_EWI_ENABLE;
if (HAL_WWDG_Init(&hwwdg) != HAL_OK){
Error_Handler();
}
}
找到弱符号早期唤醒中断函数原型,并在wwdg.c中自定义该回调函数 __weak void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
看门狗中断回调函数中添加喂狗程序,按键没按下就喂狗,程序不会重启。当按键按下时,不在进行喂狗,程序重启,同时让LED2状态翻转。
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg){
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==0) //S1 按下
{
printf1("S1 按下\r\n");
}
else
{
HAL_WWDG_Refresh(hwwdg); //在早期唤醒中断函数中喂狗
printf1("S1 没有按下,正常喂狗\r\n");
}
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5);
}
- 在main函数中while前输出测试信息,方便查看重启状态
int main(void)
{
///****省略****///
printf1("\r\nWWDG 测试!\r\n");
while(1)
{
///*****省略******//
}
}
5、下载验证
程序编译无误后下载验证, 按键没按下就喂狗,程序不会重启。当按键按下时,不在进行喂狗,程序重启,同时LED2状态翻转。