STM32 IWDG&WWDG

STM32 IWDG&WWDG

启动看门狗之后,看门狗是不能再被关闭的,除非发生复位。

IWDG独立看门狗

独立看门狗配置流程

  • 开启LSI时钟,只有LSI时钟开启了,独立看门狗才能运行。

    • 但是开启LSI的代码,并不需要我们来写,因为如果独立看门狗已经由硬件选项或软件启动,LSI振荡器将被强制在打开状态,且不能被关闭。在LSI振荡器稳定后,时钟供应给IWDG。
  • 解除IWDG_PR和IWDG_RLR的写保护(向键寄存器写入0x5555)

  • 写入预分频器(IWDG_PR)和重装寄存器(IWDG_RLR)。

    预分频值和重装值具体写入多少,可以通过超时时间:TIWDG = TLSI × PR预分频系数 × (RL + 1) (其中:TLSI = 1 / FLSI)来计算。

  • 启用独立看门狗(向键寄存器写入0xCCCC)

  • 在主循环中,不断向键寄存器写入0xAAAA(使IWDG_RLR中的值重新加载到计数器(喂狗)

预分频值和重装值计算

  • TIWDG = TLSI × PR预分频系数 × (RL + 1) (其中:TLSI = 1 / FLSI

    • 比如现在设置超时时间位1000ms,也就是1s,那就是要求,喂狗时间间隔,不能超过1000ms。

    • TIWDG=1000ms,TLSI=1/40KHz=0.025ms。

    • PR和RL都是待定的数值,并且它们的值,可以有多种组合,并不是固定的,随着预分频系数的不同,RL也对应的有不同的选择。

    • 目前,我们要设置1000ms,所以前两个预分频是不能选择的(计数器计数最长时间超过了1000ms),剩下的预分频系数都可以选择,因为它们计数的最长时间和最短时间都包含了1000ms。优先选择较小的预分频系数,可以最大化利用计数器的值,来减小时间误差。因为有的时候,得到的RL值是个小数,但RL只能给整数,所以四舍五入取整就会造成误差。

    • 这里选择预分频系数为16,计算可得RL=1000/0.025/16-1=2499。(RL范围0~4096)

STM32 IWDG&WWDG_第1张图片

代码示例

main.c
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Delay.h"
#include "Key.h"
int main(void)
{
    OLED_Init();
    Key_Init();
    
    OLED_ShowString(1,1,"IWDG TEST");
    
    if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)==SET)//查看独立看门狗复位的标志位,判断是否是独立看门狗导致的程序复位
    {
        OLED_ShowString(2,1,"IWDGSET");
        Delay_ms(500);
        OLED_ShowString(2,1,"       ");
        Delay_ms(500);
        
        RCC_ClearFlag();//清除标志位
    }
    else
    {
        OLED_ShowString(3,1,"RST");
        Delay_ms(500);
        OLED_ShowString(3,1,"   ");
        Delay_ms(100);
    }
    
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//解除写保护
    IWDG_SetPrescaler(IWDG_Prescaler_16);//配置预分频值
    IWDG_SetReload(2499);//配置重装值
    
    IWDG_ReloadCounter();//在启动前先喂一次狗,这样启动后的第一个喂狗周期,就是1000ms。
    IWDG_Enable();//启动看门狗
    //喂狗或使能的时候,会在键寄存器写入0x5555之外的值,又顺便给寄存器写保护了,不用再手动执行写保护。
    
    while(1)
    {
        Key_GetNum();//按住按键不放,主循环就会阻塞,主循环阻塞,不能及时喂狗,独立看门狗就会复位。
        
        IWDG_ReloadCounter();//喂狗
        
        OLED_ShowString(4,1,"FEED");
        Delay_ms(200);
        OLED_ShowString(4,1,"    ");
        Delay_ms(600);
    }
}

WWDG窗口看门狗

窗口看门狗配置流程

  • 开启窗口看门狗APB1的时钟
  • 配置预分频系数和窗口值
    • 窗口看门狗没有写保护,可以直接写寄存器
  • 写入控制寄存器CR
    • 看门狗使能位
    • 计数器溢出标志位
    • 计数器有效位
  • 不断向计数器写入想要的重装值,进行喂狗

预分频值和重装值计算

  • 超时时间:TWWDG = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] + 1)

  • 窗口时间:TWIN = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] - W[5:0])

  • 其中:TPCLK1 = 1 / FPCLK1

    • 超时时间
      • 比如现在设置超时时间是50ms,窗口时间是30ms。
      • 首先带入第一个公式,确定预分频和喂狗要给的计数器值,由于想要设置的超时时间为50ms,所以前三个预分频系数是不能选择的(计数器计数最长时间超过了50ms),只能选择最后一个分频系数,只有最后一个分频系数对应的时间范围包含50ms,这里WDGTB=3,对应预分频系数就是23=8。
      • TWWDG=50ms TPCLK=1/36M (单位为ms,所以取36000)WDGTB预分频系数=8,计算(取整)可得T+1=55,T[5:0]=54,但这个54只是T[5:0]的值,还有一个T6位也要设置为1,所以再54的基础上,需要再或上0x40,也就是把控制寄存器次高位T6位设置为1。(0x41 | 54)
    • 窗口时间
      • 预分频系数=8,T=54,TPCLK=1/36M,TWIN=30ms,计算(取整)可得 T-W = 33,W[5:0]=21,同理这个窗口值也是只有W[5:0],低6位,W6这一位,也需要或上0x40,给该位置1。(0x40 | 21)

STM32 IWDG&WWDG_第2张图片

代码示例

main.c
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Delay.h"
#include "Key.h"
int main(void)
{
    OLED_Init();
    Key_Init();
    
    OLED_ShowString(1,1,"WWDG TEST");
    
    if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST)==SET)//查看窗口看门狗复位的标志位,判断是否是窗口看门狗导致的程序复位
    {
        OLED_ShowString(2,1,"WWDGSET");
        Delay_ms(500);
        OLED_ShowString(2,1,"       ");
        Delay_ms(500);
        
        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时钟
    
    WWDG_SetPrescaler(WWDG_Prescaler_8);//配置预分频值
    WWDG_SetWindowValue(0x40 | 21);//设置窗口值 30ms
    WWDG_Enable(0x40 | 54);//开启窗口看门狗,同时喂狗并在窗口看门狗使能位置1 50ms

    while(1)
    {
        Key_GetNum();
                
        OLED_ShowString(4,1,"FEED");
        Delay_ms(20);
        OLED_ShowString(4,1,"    ");
        Delay_ms(20);
        
        WWDG_SetCounter(0x40 | 54);//先经过40ms的延迟再喂狗(防止立刻复位) 同时在窗口看门狗使能位置0,但是不会关闭窗口看门狗,因为启动看门狗之后,看门狗是不能再被关闭的,除非发生复位
    }
}

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Delay.h"
#include "Key.h"
int main(void)
{
    OLED_Init();
    Key_Init();
    
    OLED_ShowString(1,1,"WWDG TEST");
    
    if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST)==SET)//查看窗口看门狗复位的标志位,判断是否是窗口看门狗导致的程序复位
    {
        OLED_ShowString(2,1,"WWDGSET");
        Delay_ms(500);
        OLED_ShowString(2,1,"       ");
        Delay_ms(500);
        
        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时钟
    
    WWDG_SetPrescaler(WWDG_Prescaler_8);//配置预分频值
    WWDG_SetWindowValue(0x40 | 21);//设置窗口值 30ms
    WWDG_Enable(0x40 | 54);//开启窗口看门狗,同时喂狗并在窗口看门狗使能位置1 50ms

    while(1)
    {
        Key_GetNum();
                
        OLED_ShowString(4,1,"FEED");
        Delay_ms(20);
        OLED_ShowString(4,1,"    ");
        Delay_ms(20);
        
        WWDG_SetCounter(0x40 | 54);//先经过40ms的延迟再喂狗(防止立刻复位) 同时在窗口看门狗使能位置0,但是不会关闭窗口看门狗,因为启动看门狗之后,看门狗是不能再被关闭的,除非发生复位
    }
}

你可能感兴趣的:(stm32,嵌入式硬件,单片机)