目录
STM32CubeMX软件(Version 6.10.0)
keil μVision5 IDE(MDK-Arm)
CH340G Windows系统驱动程序(CH341SER.EXE)
逻辑分析仪nanoDLA
使用STM32CubeMX软件配置STM32F407开发板的独立看门狗(IWDG)和窗口看门狗(WWDG)并了解其功能实现
STM32F407拥有两个看门狗,分别为独立看门狗和窗口看门狗,这两个看门狗的作用都是监控程序运行,程序死机或跑飞就使系统复位,值得注意的是,一旦开启看门狗就无法停止,除非系统复位
窗口看门狗的结构不复杂,其结构框图上描述了有关窗口看门狗的所有内容,首先WDG的时钟来自于PCLK1(STM32F407最高42MHz)的4096次分频后再进行可选的1/2/4/8分频,其内部有一个7位的递减计数器T[6:0],还有一个WWDG_CFR配置寄存器,该寄存器位6:0包含了用于与递减计数器进行比较的窗口值W[6:0]
当出现以下两种情况时会产生窗口看门狗复位操作,①当看门狗激活(WDGA=1)且T6位由1变为0时(也即T[6:0]<0X3F时),②当看门狗激活且T[6:0]>W[6:0]时用户写WWDG_CR寄存器的值(也即刷新T[6:0]值),如下所示为窗口看门狗逻辑框图(注释1)
通过上述的描述,可知窗口看门狗要想不产生复位操作,必须将其计数器的计数值控制在W[6:0]和0x3F之间才能喂狗(刷新T[6:0]值),当 “计数器的值小于0x3F” 或者 “当计数器的值T[6:0]>W[6:0]时用户喂狗” 都会产生Reset操作,这也是为什么叫窗口看门狗的原因,如下图所示为窗口看门狗的工作时序图(注释1)
窗口看门狗可设置的参数只有三个
?WWDG counter clockprescaler?(时钟分频):可以设置为1/2/4/8分频
?WWDG window value?(窗口W[6:0]值):可设置范围T[6:0]~127
?WWDG down-counter reload value?(递减计数器重装值):可设置范围63-127(7位最大值127且不能小于0x3F)
注意本实验由于独立看门狗较为简单,所以选择将独立/窗口看门狗放在一篇文章里,但是读者复现实验的时候应该分开做,不要同时启用窗口看门狗和独立看门狗(不是不可以同时启用,而是对于本实验例子同时启用不方便理解)
另外需要提醒的是,独立/窗口看门狗只要被初始化就会自动启动,用户只需喂狗即可
打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号)选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示
开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示
详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立”
由于窗口看门狗递减定时器为7位且递减到0x3F就会产生复位,因此最大计数值也才127-63=64,因此其时钟频率尽可能低一点,否则超时时间太短,实验现象不太好观察,这里将PCLK1设置为了21MHz,具体时钟配置如下图所示
本实验需要需要初始化开发板上GREEN_LED和RED_LED,具体配置步骤请阅读“STM32CubeMX教程2 GPIO输出 - 点亮LED灯”
本实验需要需要初始化开发板上KEY2用户按键,具体配置步骤请阅读“STM32CubeMX教程3 GPIO输入 - 按键响应”
本实验需要需要初始化USART1作为输出信息渠道,具体配置步骤请阅读“STM32CubeMX教程9 USART/UART 异步通信”
单击Pinout & Configuration页面左边的System Core的WWDG进入窗口看门狗的设置,在Mode中勾选Activated,在下方配置其分频系数为8,窗口值为90,计数器重装值为最大值127,具体配置如下图所示
现在我们来计算一下窗口看门狗的超时时间
首先PCLK1设置为了21MHz,然后该时钟经过4096次分频,在经过设置的8分频得到的频率为640.869140625Hz
则其超时时间可以计算得到为(127-63)/640.869140625≈0.09986s≈99.86ms
其不允许喂狗的时间可以计算得到为(127-90)/640.869140625≈57.734ms
即当窗口定时器被初始化启动后,如果在57.734ms-100ms之间没有进行喂狗操作,那么窗口看门狗将超时导致程序复位
在Pinout & Configuration页面左边System Core/NVIC中勾选Window watchdog interrupt全局中断,然后选择合适的中断优先级即可
单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示
详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节
此小节为原理讲解,读者无需额外操作,可略过
在生成的工程主函数main()中调用MX_WWDG_Init()函数对WWDG参数配置,并调用了HAL_WWDG_Init()初始化函数
在HAL_WWDG_Init()函数中对WWDG做了初始化,并调用了HAL_WWDG_MspInit()函数对WWDG的时钟、中断优先级和中断使能做了配置
WWDG具体初始化调用流程如下图所示
此小节为原理讲解,读者无需额外操作,可略过
在STM32CubeMX中勾选了WWDG的中断后,会在stm32f4xx_it.c文件中出现串口看门狗中断服务函数WWDG_IRQHandler()
该中断服务函数WWDG_IRQHandler()调用了HAL库WWDG中断统一管理函数HAL_WWDG_IRQHandler()
最终在HAL_WWDG_IRQHandler()函数中调用了早期唤醒回调函数HAL_WWDG_EarlyWakeupCallback(),该函数为虚函数,需要用户重新实现
WWDG具体中断调用流程如下图所示
在wwdg.c中重新实现早唤醒回调函数HAL_WWDG_EarlyWakeupCallback(),当递减计数器递减到0x40,下次递减即将产生看门狗复位时,就会进入到该早唤醒回调函数中,但是该函数只能执行一个时钟节拍,然后系统就复位了,因此该函数内部执行不了复杂的程序,笔者这里也只是输出了一个字符‘1’,源代码如下
/*早唤醒回调函数*/
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
printf("1\r\n");
}
在主函数中初始化完毕拉低PF9引脚,主循环中延时喂狗,并闪烁GREEN_LED,当系统喂狗及时,用户就可以看到GREEN_LED闪烁,当喂狗不及时,系统反复复位,就看不到GREEN_LED闪烁
源代码如下
/*主循环外代码*/
printf("Reset\r\n");
HAL_GPIO_WritePin(RED_LED_GPIO_Port,RED_LED_Pin,GPIO_PIN_RESET);
/*主循环内代码*/
HAL_Delay(70);
//HAL_Delay(40);
HAL_WWDG_Refresh(&hwwdg);
HAL_GPIO_TogglePin(GREEN_LED_GPIO_Port,GREEN_LED_Pin);
/*独立看门狗喂狗函数*/
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
/*窗口看门狗喂狗函数*/
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
/*窗口看门狗早唤醒中断回调函数*/
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
“配置LED灯 -> 配置按键KEY2 -> 配置串口USART1 ->激活IWDG/WWDG并配置参数 -> 勾选启动WWDG中断 -> 重新实现早唤醒中断回调函数 -> 主函数实现逻辑控制”
将程序修改为延时110ms,烧录程序,单片机上电后通过串口可以发现每隔一段时间都会发生进入早唤醒中断和复位操作,此时开发板上只有RED_LED被点亮,GREEN_LED呈现熄灭状态,使用逻辑分析仪捕获PF9引脚的电平,可以发现复位间隔时间大概为99ms,与我们设置预期的99.864ms大致一致,如下图所示为串口输出数据和逻辑分析仪捕获PF9引脚电平图
使用PF9引脚的状态来判断复位时间间隔不太严谨,因此我们将WWDG的参数做修改二次测试,分频不变仍为8,窗口值修改为80,重装值修改为100,此时通过计算可知递减到63大约需要57.734ms,将程序修改为延时70ms,然后使用逻辑分析仪再次捕获PF9引脚的电平,可以发现复位间隔时间大概为57ms,经过这两次测试,可知虽然不严谨但可以验证,如下图所示为逻辑分析仪捕获的PF9引脚电平图
WWDG复原回原来参数,分频8,窗口值90,重装值127,将程序修改为延时70ms,然后烧录程序,单片机上电后通过串口可以发现不会频繁的输出复位信息,也不会进入早唤醒中断回调函数中,此时开发板上RED_LED被点亮,GREEN_LED呈现闪烁状态,证明喂狗比较及时,没有产生窗口看门狗复位
独立看门狗很简单,本质就是一个12位的递减计数器,当递减到0之后就产生看门狗复位操作,其时钟来源于单片机内部的LSI RC(32KHz)且不可更换,该内部RC震荡产生的时钟信号频率误差较大,因此在设置看门狗复位时间时最好留有余量,如下图所示为其时钟来源
独立看门狗可设置的参数只有两个
?IWDG counter clockprescaler?(时钟分频):可以设置为4/8/16/.../256分频
?IWDG down-counter reload value?(递减计数器重装值):可设置范围0-4095(12位)
当其重装值设置为最大值4095,根据时钟分频的不同,看门狗的超时时间也不同,最长可达32.768s,最短只有0.512s,具体超时时间如下表所示
只需在Pinout & Configuration页面左边功能分类栏目System Core中单击其中IWDG,在Mode中勾选Activated,最后在下方配置两个参数即可,时钟使用LSI配置不可调,IWDG无中断,具体步骤如下图所示
程序初始化完毕后拉低PF9引脚,在主循环中实现按键响应,按下KEY2按键执行喂狗操作
源代码如下
/*主函数初始化完后将PF9引脚拉低*/
HAL_GPIO_WritePin(RED_LED_GPIO_Port,RED_LED_Pin,GPIO_PIN_RESET);
/*主循环中程序/
/*按键KEY2被按下*/
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
printf("Now feed the dog\r\n");
HAL_IWDG_Refresh(&hiwdg);
while(!HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin));
}
}
烧录程序,单片机上电后通过串口可以发现每隔一段时间都会发生复位操作,当按下KEY2按键在该间隔时间内喂狗,就不会产生复位操作,而一旦停止喂狗,超时后又会产生复位操作,具体如下图所示
当单片机复位后会首先执行一系列初始化操作,然后手动将PF9引脚设置为低电平(该引脚默认为高),直到由于没有喂狗产生看门狗复位为止,通过逻辑分析仪捕获PF9引脚的电平,可以发现其两次复位间隔时间与我们所设置预期的看门狗超时时间大致一致,具体如下图所示
注释1:图片来源于 STM32F4xx 参考手册 RM0090