【STM32】独立看门狗(提供完整实例代码)_看门狗驱动代码
这篇文章系统总结了 STM32 独立看门狗(IWDG) 的知识,并且我提供了完整的实验示例代码(基于标准库实现)。
为什么要用看门狗?
如果单片机在运行中死机了,此时我们再进行任何操作,单片机都不会再做出响应,这时候只能通过断电让设备重启,设备才能恢复正常。为了解决单片机死机的问题,设计者们给单片机设计了一种叫做 看门狗 的模块,以复位解决单片机死机的问题。
专业点说,
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”
(watchdog)
。
简单点说,
在嵌入式系统中,程序有可能由于 干扰、电磁波、堆栈溢出等原因而“跑飞”,导致系统死机或卡死。
看门狗(Watchdog) 就像一个“定时检查的保安”:
① 正常运行时我们“喂狗”;
② 如果程序异常未喂狗 → 看门狗复位MCU → 系统自动重启。
STM32 的两个看门狗
STM32内置两个看门狗,提供了更高的安全性,时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗/窗口看门狗)可以用来检测和解决由软件错误引起的故障。当计数器达到给定的超时值时,触发一个中断(仅适用窗口看门狗)或者产生系统复位。
独立看门狗
独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它仍有效。
独立看门狗适合应用于需要看门狗作为一个在主程序之外 能够完全独立工作,并且对时间精度要求低的场合。
窗口看门狗
窗口看门狗由从APB1时钟分频后得到时钟驱动。通过可配置的时间窗口来检测应用程序非正常的过迟或过早操作。
窗口看门狗最适合那些要求看门狗在精确计时窗口起作用的程序。
独立看门狗(IWDG)关键特性
独立看门狗功能描述
① 在键值寄存器(IWDG_KR)中写入 0xCCCC,开始启用独立看门狗。此时计数器开始从其复位值0xFFF递减,当计数器值计数到尾值0x000时会产生一个复位信号(IWDG_RESET)。
② 无论何时,只要在键值寄存器IWDG_KR中写入0xAAAA(通常说的喂狗), 自动重装载寄存器IWDG_RLR的值就会重新加载到计数器,从而避免看门狗复位。
③ 如果程序异常,就无法正常喂狗,从而系统复位。
键值寄存器IWDG_KR: 0~15位有效预分频寄存器IWDG_PR:0~2位有效。--- 具有写保护功能,要操作先取消写保护重装载寄存器IWDG_RLR:0~11位有效。--- 具有写保护功能,要操作先取消写保护。状态寄存器IWDG_SR:0~1位有效
常用寄存器和对应库函数:
IWDG_WriteAccessCmd()
、IWDG_Enable()
、IWDG_ReloadCounter()
IWDG_SetPrescaler()
IWDG_SetReload()
IWDG_GetFlagStatus()
独立看门狗(IWDG)超时时间
时钟来源:内部 LSI 40kHz
启动后不可关闭(除非复位)
有写保护,修改前需取消写保护
溢出时间计算:
Tout = ((4×2^prer) ×rlr) /40 (M3)
时钟频率 LSI=40K, 一个看门狗时钟周期就是最短超时时间。
最长超时时间 = (IWDG_RLR寄存器最大值)X看门狗时钟周期
IWDG独立看门狗操作库函数
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//取消写保护:0x5555使能void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//设置预分频系数:写PRvoid IWDG_SetReload(uint16_t Reload);//设置重装载值:写RLRvoid IWDG_ReloadCounter(void);//喂狗:写0xAAAA到KRvoid IWDG_Enable(void);//使能看门狗:写0xCCCC到KRFlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//状态:重装载/预分频 更新
独立看门狗初始化步骤
① 取消寄存器写保护:
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
② 设置独立看门狗的预分频系数,确定时钟:(如:256)
IWDG_SetPrescaler(IWDG_Prescaler_256);
③ 设置看门狗重装载值,确定溢出时间:(最大0xFFF):
IWDG_SetReload(0x0FFF);
④ 使能看门狗(等待寄存器更新完成):
while(IWDG_GetFlagStatus(...) == SET);
⑤ 应用程序喂狗:
IWDG_ReloadCounter();
⑥ 启动看门狗:
IWDG_Enable();
溢出时间计算:
Tout=((4×2^prer) ×rlr) /40 (M3)
实验完整代码(标准库实现)
- 设置 IWDG 超时时间为约 5 秒
- 程序中定时喂狗,避免复位
- 如果人为注释掉喂狗 → 系统将在 5 秒后自动复位
#include \"stm32f10x.h\"// 延时函数(粗略估算用)void Delay(uint32_t time){ while(time--);}// 看门狗初始化函数(超时时间约5秒)void IWDG_Init(void){ // ① 允许写访问 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); // ② 设置预分频值:256 IWDG_SetPrescaler(IWDG_Prescaler_256); // 40kHz ÷ 256 = 156.25Hz // ③ 设置重装载值:0x0FFF(4095) IWDG_SetReload(0x0FFF); // 最大值 // ④ 等待更新完成 while(IWDG_GetFlagStatus(IWDG_FLAG_PVU) != RESET); // 等待预分频更新完成 while(IWDG_GetFlagStatus(IWDG_FLAG_RVU) != RESET); // 等待重装载更新完成 // ⑤ 喂狗一次 IWDG_ReloadCounter(); // ⑥ 启动看门狗 IWDG_Enable();}int main(void){ // 可加LED初始化等调试 IWDG_Init(); // 初始化看门狗 while(1) { // 模拟正常程序,每隔一段时间喂狗 Delay(5000000); // 粗略延时 IWDG_ReloadCounter(); // 喂狗 // 注释掉这一句试试看系统是否会复位 // IWDG_ReloadCounter(); }}
运行效果:正常运行并喂狗 —> 程序持续运行,不复位;注释掉喂狗函数 —> 系统约 5 秒后复位,重新执行 main()
。
超时时间计算方法:(使用上面参数)
- PR = 256,对应
IWDG_Prescaler_256
- RL = 0x0FFF = 4095
Tout = ((4 × 2^7) × 4095) / 40 = (512 × 4095) / 40 = 2097152 / 40 ≈ 52428 ms ≈ 5.24 s
因篇幅有限,这里单独开一篇文章来介绍 看门狗模块 中的关键步骤:弄清楚 超时时间计算 的核心原理 —> 预分频因子(Prescaler)和重装载值(Reload Value)。
总结,因为在 Keil 软件中,函数设计是模块划分的(代码整理):
wdg.c
#include \"wdg.h\"// Tout=((4×2^prer) ×rlr) /40 (M3)// prer:分频因子,值范围 0~7// rlr:重装载值 最大值 2^12 - 1 = 4095// 假如喂狗时间设置为 0.5s = ((4×2^prer) ×rlr) /40// prer 预设值为 2 // 最后算出 rlr void IWDG_Init(uint8_t IWDG_Prescaler,uint16_t Reload){IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//取消写保护,允许写操作IWDG->KR = 0x5555;IWDG_SetPrescaler( IWDG_Prescaler );//设置预分频值IWDG_SetReload( Reload );//设置重装载值IWDG_ReloadCounter();//喂狗IWDG_Enable();//使能看门狗}
wdg.h
#ifndef _IWDG_H_#define _IWDG_H_#include \"stm32f10x.h\"#include void IWDG_Init(uint8_t IWDG_Prescaler,uint16_t Reload);#endif
main.c
/** ****************************************************************************** * @file Project/STM32F10x_StdPeriph_Template/main.c * @author MCD Application Team * @version V3.5.0 * @date 08-April-2011 * @brief Main program body ****************************************************************************** * @attention * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * © COPYRIGHT 2011 STMicroelectronics
****************************************************************************** */ /* Includes ------------------------------------------------------------------*/#include \"stm32f10x.h\"#include \"stdio.h\"#include \"gpio.h\"#include \"systick.h\"#include \"exti.h\"#include \"usart.h\"#include \"string.h\"#include \"wdg.h\"uint8_t SendData [] = {\"你好,世界 \\r\\n\"};int main(){int IWDG_Count = 0;int i = 0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断使用分组2MX_GPIO_Init();delay_Init();//Systick_Initerupt_Init();MX_EXTI0_Init();MX_USART1_Init(115200);USART1_NVIC_Init(1,1);GPIO_WriteBit(GPIOC, GPIO_Pin_7 , Bit_RESET);delay_ms(500);IWDG_Init( 2 , 1250);//预分频因子系数 2 对应预分频系数 16看门狗当前复位时间为500msGPIO_WriteBit(GPIOC, GPIO_Pin_7 , Bit_SET);while(1){if(GPIO_ReadInputDataBit( GPIOA, GPIO_Pin_0) == Bit_RESET){IWDG_Count ++;IWDG_ReloadCounter();//喂狗printf(\"IWDG_Count = %d \\r\\n\", IWDG_Count);}}}/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
总而言之,独立看门狗是一个可靠的 “程序异常自恢复机制”,非常适合用于工业、无人值守等关键场景,提高系统运行的稳定性。
以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!