打印
[应用相关]

stm32看门狗系列

[复制链接]
90|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32 看门狗简介
看门狗(Watchdog) 是一种常用于微控制器中的定时器,它可以在程序出现故障或卡死时重新启动系统,以确保系统能够恢复正常运行。在 STM32 系列中,通常有两种类型的看门狗:独立看门狗(IWDG) 和 窗口看门狗(WWDG)。

1. 独立看门狗(IWDG)
独立看门狗(IWDG)是 STM32 系列中一个非常常见的看门狗,它用于在 MCU 出现故障时复位系统。

总结:
这个框图描述了 STM32 的 独立看门狗(IWDG) 工作原理。IWDG 通过 LSI 时钟 和 重载寄存器 定时,保证系统在遇到死循环或其他异常时能进行复位,恢复正常工作。看门狗的定时是独立于主系统时钟的,因此在系统发生故障时,IWDG 仍能继续工作,确保系统的可靠性。

工作原理:IWDG 通过定期喂狗来重启 MCU。通过向看门狗寄存器写入一个特定的值来重置计数器,如果看门狗没有在预定的时间内被“喂食”,它会产生一个 复位信号,将 MCU 复位。

独立看门狗(IWDG)框图功能说明:



LSI(低速内部时钟):

IWDG 使用 LSI(40 kHz) 作为定时器源。这个时钟源是独立于主系统时钟的,即使系统主时钟出现故障,IWDG 仍能工作,保证系统安全。
预分频器(IWDG_PR):

IWDG_PR 是一个 8 位的预分频器,用来调整定时器的计数频率。通过调整预分频器,可以让 IWDG 计时器根据需要产生不同的超时周期。
状态寄存器(IWDG_SR):

IWDG_SR 用于存储当前 IWDG 的状态,检测是否发生了复位或者其它状态信息。
重载寄存器(IWDG_RLR):

IWDG_RLR 是 12 位的重载寄存器,它定义了 IWDG 定时器的周期(也就是定时器计时的上限)。如果在重载值设定的时间内没有进行“喂狗”操作,IWDG 会触发复位。
12 位速率计数器(IWDG Counter):

IWDG 通过一个 12 位计数器来计算定时器超时,计数器会从重载寄存器加载的值开始计数,直到超时。
IWDG 控制寄存器(IWDG_KR):

IWDG_KR 是一个键寄存器,通过写入特定的密钥来启动或复位 IWDG 功能。
复位功能:

如果 IWDG 计时器超时(即计时器未被“喂狗”),则触发 复位,以确保 MCU 被复位并重新启动。
主要特点:

硬件独立性:即使主系统时钟故障,看门狗仍能正常工作。
定时器:IWDG 内部使用 LSI(低速内部时钟) 作为定时源,具有独立于主系统时钟的特性。
复位功能:超时后,IWDG 会触发一个 硬件复位,系统重新启动。
使用方法:

启动 IWDG,设置预分频器和计数器值。
在应用程序中定期“喂狗”(重新加载计数器)。
如果在规定时间内没有喂狗,IWDG 会复位 MCU。
代码示例:

#include "stm32f10x.h"

// 启动 IWDG 并设置计数器
void IWDG_Init(void) {
    // 使能 IWDG 外设时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_IWDG, ENABLE);

    // 配置 IWDG 时钟,设置预分频器和计数器值
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  // 使能 IWDG 写访问
    IWDG_SetPrescaler(IWDG_Prescaler_64);  // 设置预分频器
    IWDG_SetReload(0xFFF);  // 设置重载值(最大值)

    // 启动 IWDG
    IWDG_Enable();
}

// 定期喂狗函数
void IWDG_Feed(void) {
    IWDG_ReloadCounter();  // 喂狗,重装计数器
}

int main(void) {
    SystemInit();  // 系统初始化
    IWDG_Init();  // 初始化看门狗

    while (1) {
        // 主循环中定期喂狗
        IWDG_Feed();
    }
}

2. 窗口看门狗(WWDG)
窗口看门狗(WWDG)与独立看门狗类似,但是它具有一个“窗口”功能,用于增强系统的可靠性。

总结
工作原理:WWDG 会在设定的时间窗口内等待“喂狗”。如果在此窗口内没有喂狗,WWDG 将重置系统。不同的是,窗口看门狗要求喂狗操作在特定的时间窗口内完成,超过窗口时间将触发复位。



框图分析:
这个框图展示了 STM32 的 窗口看门狗(WWDG) 工作原理。窗口看门狗(WWDG)是一个定时器,常用于确保系统不会进入死循环或卡死状态。通过定期喂狗,可以避免系统复位。

主要功能组件分析:
PCLK1 时钟(来自 RCC 时钟控制器):

WWDG 的时钟源是来自 PCLK1 时钟,该时钟可以是系统时钟的一部分,通过 RCC 时钟控制器 进行配置。
窗口看门狗预分频器(WDGTB):

用于生成用于看门狗计数器的时钟信号。通过预分频器调整时钟频率,确保看门狗的计时周期符合系统要求。
窗口看门狗计数器(CNT):

这是一个 6 位的计数器,每次递增。当计数器达到重载值时,会触发看门狗复位,除非在指定的“窗口”内进行了喂狗操作。
窗口机制:窗口看门狗不同于独立看门狗,窗口机制要求在设定的时间窗口内喂狗,否则会触发复位。
窗口看门狗配置寄存器(WWDG_CFR):

配置寄存器用来设定 重载值 和 窗口值,影响看门狗的计时行为。
W6 ~ W0:这些位用于设置窗口值,以定义喂狗操作必须发生的窗口。
窗口看门狗 是一个可以在特定的时间窗口内进行喂狗操作的定时器。
如果在这个时间窗口内没有喂狗,系统将会触发复位,保证系统的可靠性。
该框图显示了 WWDG 的时钟、计数器、配置寄存器等各个模块是如何协同工作,来监控系统状态并确保其稳定运行的。
窗口看门狗控制寄存器(WWDG_CR):

WDGA:启动窗口看门狗操作。写入此寄存器启用看门狗计数。
T6 ~ T0:这些位设置计数器的初始值,并决定计数器的重载值。
比较器(Comparator):

用于比较 WWDG_CR 寄存器的值与 WWDG_CFR 寄存器的窗口值,来决定是否可以喂狗。
如果比较结果是 1,即在窗口内喂狗,那么系统将继续运行;如果比较结果是 0,则触发复位。
主要特点:

时间窗口:需要在规定的时间窗口内进行喂狗操作,否则会复位系统。
快速复位:通过控制喂狗的时间窗口,可以更严格地控制系统的稳定性。
使用方法:

启动 WWDG,设置计数器和窗口值。
在应用程序中定期“喂狗”,并确保在窗口内进行操作。
如果在窗口外喂狗,WWDG 会复位 MCU。
代码示例:

#include "stm32f10x.h"

// 启动 WWDG 并设置计数器和窗口值
void WWDG_Init(void) {
    // 使能 WWDG 外设时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);

    // 设置窗口值、计数器和预分频器
    WWDG_SetWindowValue(0x7F);  // 设置窗口值
    WWDG_SetCounter(0x7F);  // 设置计数器值
    WWDG_Enable(0x7F);  // 启动 WWDG
}

// 定期喂狗函数
void WWDG_Feed(void) {
    WWDG_SetCounter(0x7F);  // 在窗口内喂狗
}

int main(void) {
    SystemInit();  // 系统初始化
    WWDG_Init();  // 初始化窗口看门狗

    while (1) {
        // 主循环中定期喂狗
        WWDG_Feed();
    }
}

总结
独立看门狗(IWDG):硬件独立、使用低速内部时钟,适用于系统保护,超时后会触发复位。
窗口看门狗(WWDG):具有更严格的时间窗口控制,只有在指定时间内喂狗,才能避免复位。
两种看门狗的使用方式和设置方法有所不同,IWDG 更加简单且适用于大多数场景,而 WWDG 提供了更高的灵活性和保护。

项目:对IDWG进行一个检测,进行“喂狗”检测IWDG防止其复位,通过OLDE屏来显示检测结果

操作:

1判断IWDG的复位状态,可通过OLED屏来观察

2开始IWDG模式(LSI会被自动开启时钟设置)调用函数:IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);

3对键寄存器进行解除预分频值和重装载值的写保护

4设置预分频值和重装载值的参数(也就设置"喂狗"的时间) (设置1000ms的喂狗时间)

5调试喂狗的时间,在while循环里面延时一定时间定时喂狗观察设置的喂狗时间是否一致

#include "stm32f10x.h"                  // Device header
#include "Dog.h"
#include "oled.h"
#include "Delay.h"
void iwdg_Init()
{
          OLED_Init();
          OLED_ShowString (1,1,"IWDG TEST");
        if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)!=RESET )
        {
            OLED_ShowString (2,1,"IWDGRESET");
                  delay_ms (500);
                  OLED_ShowString (2,1,"       ");
                   delay_ms (100);
      RCC_ClearFlag();
               
        }
        else{
               
                 OLED_ShowString (3,1,"RST");
                 delay_ms (500);
                  OLED_ShowString (3,1,"  ");
                 delay_ms (100);
      RCC_ClearFlag();
                       
        }
        //WWDG的初始化
        //Tiwdg=TLSI*PR预分频系数*(RC+1)
         IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
         IWDG_SetPrescaler(IWDG_Prescaler_16);       //选择16分频
        IWDG_SetReload(2499);           //选择2499重装载值  总计算为1000ms
        IWDG_ReloadCounter();         //先提前喂狗一次
        IWDG_Enable();
         while(1)
         {
                 IWDG_ReloadCounter(); //每隔xxms喂狗一次
                 delay_ms (1100);     
                 
         }
       
       
       
       
}

通过按键来进行喂狗操作:

#include "stm32f10x.h"                  // Device header
#include "Dog.h"
#include "oled.h"
#include "Delay.h"
#include  "key.h"
void iwdg_Init()
{  
           key_Init();
          OLED_Init();
          OLED_ShowString (1,1,"IWDG TEST");
        if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)!=RESET )
        {
            OLED_ShowString (2,1,"IWDGRESET");
                  delay_ms (500);
                  OLED_ShowString (2,1,"       ");
                   delay_ms (100);
      RCC_ClearFlag();
               
        }
        else{
               
                 OLED_ShowString (3,1,"RST");
                 delay_ms (500);
                  OLED_ShowString (3,1,"  ");
                  delay_ms (100);
      RCC_ClearFlag();
                       
        }
        //WWDG的初始化
        //Tiwdg=TLSI*PR预分频系数*(RC+1)
         IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
         IWDG_SetPrescaler(IWDG_Prescaler_16);       //选择16分频
        IWDG_SetReload(2499);           //选择2499重装载值  总计算为1000ms
        IWDG_ReloadCounter();         //先提前喂狗一次
        IWDG_Enable();
         while(1)
         {
                 Get_keynum (); //如果一致按下按键,那么无法进行后面喂狗,就会复位
                 IWDG_ReloadCounter(); //每隔xxms喂狗一次
                 OLED_ShowString (4,1,"FEED");
                 delay_ms (200);
                 OLED_ShowString (4,1,"   ");
                 delay_ms (600);     
                  
         }
        #include "stm32f10x.h"                  // Device header
#include "key.h"
#include  "Delay.h"


//按键模块,该模块建议独立文件
void key_Init()
{
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
        GPIO_InitTypeDef key_inItsturt;
        key_inItsturt.GPIO_Mode = GPIO_Mode_IPU ;
        key_inItsturt.GPIO_Pin =GPIO_Pin_1 ;
        key_inItsturt.GPIO_Speed =GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &key_inItsturt);
       
       
       
}
uint8_t Get_keynum(void)
{
        uint8_t keynum=0;
        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET)
        {
                delay_ms (20);
                while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET);
                delay_ms (20);               
                keynum=1;
               
        }
       
        return keynum;
}

IWDG(独立看门狗)的超时时间公式可以通过以下公式来计算:

超时时间=(重载值+1)×(预分频器值+1)LSI_频率\text{超时时间} = \frac{(重载值 + 1) \times (预分频器值 + 1)}{LSI\_频率}"

重载值(IWDG_RLR):设置IWDG定时器的计数器上限,通常为12位(0~4095),表示计时器的计数周期。
预分频器值(IWDG_PR):设置IWDG定时器的预分频器。该值可以是 4、8、16、32、64、128、256 中的一个。
LSI 频率:IWDG 使用 LSI(低速内部时钟) 作为时钟源,其频率为 40 kHz(标准值),但可以根据实际情况略有不同。
公式中的每个部分:
重载值:设置定时器计数的最大值。
预分频器:决定了定时器计数的频率。
LSI频率:独立时钟源频率,通常为 40 kHz。
举个例子:
假设:

重载值 = 0x0FFF (4095)
预分频器 = 0x03(预分频器为 64)
LSI频率 = 40 kHz
则超时时间计算为:

超时时间计算为:超时时间=(4095+1)×(64+1)40000=4096×6540000=6.656秒超时时间=40000(4095+1)×(64+1)​=400004096×65​=6.656秒

WWDG(窗口看门狗)项目:

操作:

1调用APB窗口看门狗的时钟,

2初始化窗口看门狗,包括设置预分频参数,窗口时间WDGTB(T位6保证为1,后五位设置想要"喂狗的时间区段")

3使能    WWDG_Enable()窗口看门狗,同时也要保证WDGTB T位6为1(进行一次初始喂狗)

4在while循环里面进行按键喂狗操作以及测试喂狗的时间

代码案例:


void wwdg_Init()
{
          key_Init();
          OLED_Init();
          OLED_ShowString (1,1,"WWDG TEST");
                if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST )!=RESET )//判断WWDG复位情况
                {
                       
                        OLED_ShowString (2,1,"WWDGRESET");
                  delay_ms (500);
                  OLED_ShowString (2,1,"       ");
                   delay_ms (100);
      RCC_ClearFlag();
                       
                }
                else{
                       
                        OLED_ShowString (3,1,"RST");
                 delay_ms (500);
                  OLED_ShowString (3,1,"  ");
                  delay_ms (100);

                       
                       
                }
                //初始化窗口看门狗
                RCC_APB1PeriphClockCmd( RCC_APB1Periph_WWDG,ENABLE );
                WWDG_SetPrescaler(WWDG_Prescaler_8);//2*2*2=8;
                WWDG_SetWindowValue(0x40|21);   //到窗口时间30ms
                WWDG_Enable(0x40|54);           //最晚一共50ms
                while(1)
                {
                       

                         
                        Get_keynum (); //如果一致按下按键,那么无法进行后面喂狗,就会复位
                                         
            //每隔xxms喂狗一次
                 OLED_ShowString (4,1,"FEED");
                 delay_ms (20);
                 OLED_ShowString (4,1,"   ");
                 delay_ms (10);      
                WWDG_SetCounter(0x40|54);
                       
                }
       
}





void key_Init()
{
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );
        GPIO_InitTypeDef key_inItsturt;
        key_inItsturt.GPIO_Mode = GPIO_Mode_IPU ;
        key_inItsturt.GPIO_Pin =GPIO_Pin_1 ;
        key_inItsturt.GPIO_Speed =GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &key_inItsturt);
       
       
       
}
uint8_t Get_keynum(void)
{
        uint8_t keynum=0;
        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET)
        {
                delay_ms (20);
                while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 )==RESET);
                delay_ms (20);               
                keynum=1;
               
        }

关于 窗口看门狗(WWDG) 的 时间范围公式:

窗口看门狗的超时时间由两个因素决定:

计数器值(CNT):6位计数器的值,范围从 0 到 63(即 0x00 到 0x3F)。
窗口值:控制在指定的时间窗口内喂狗的时限。
公式
窗口看门狗的超时时间 T_window 的计算公式如下:

Twindow=(预分频器值+1)×(计数器值+1)PCLK1 时钟T_{window} = \frac{(预分频器值 + 1) \times (计数器值 + 1)}{PCLK1 \, 时钟}

预分频器值(WDGTB):该值控制看门狗时钟的频率,常见值有 1, 2, 4, 8。具体选择哪个预分频器值取决于你的系统时钟(PCLK1)。
计数器值(CNT):6 位计数器,范围从 0 到 0x3F。
PCLK1 时钟:这是窗口看门狗的时钟源,通常与系统时钟相同,可能是 72 MHz。
举个例子:
假设:

PCLK1 时钟 = 72 MHz
预分频器值 = 4
计数器值 = 0x3F(最大值)
则 窗口看门狗时间范围 为:

Twindow=(4+1)×(63+1)72×106=5×6472×106≈0.0000444 秒=44.4 μsT_{window} = \frac{(4 + 1) \times (63 + 1)}{72 \times 10^6} = \frac{5 \times 64}{72 \times 10^6} \approx 0.0000444 \, \text{秒} = 44.4 \, \mu s
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/2301_80127410/article/details/145559623

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

176

主题

4190

帖子

5

粉丝