打印

STM32之------独立看门狗(IWDG)和窗体看门狗(WWDG)

[复制链接]
4380|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sunmeat|  楼主 | 2014-11-28 10:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
看门狗通俗解释:
    单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路就是为了避免这种情况的发生。看门狗的作用就是在一定时间内(通过定时计数器实现)没有接收喂狗信号(表示 MCU 已经挂了),便实现处理器的自动复位重启(发送复位信号)。

沙发
sunmeat|  楼主 | 2014-11-28 10:47 | 只看该作者
STM32芯片一共有两个看门狗,一个是独立看门狗(IWDG),另一个是窗体看门狗(WWDG)
1.先来讲讲独立看门狗:
STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部 RC 时钟,所以并不是准确的 40Khz,而是在 30~60Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 40Khz 的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。

使用特权

评论回复
板凳
sunmeat|  楼主 | 2014-11-28 10:47 | 只看该作者
独立看门狗的配置工作代码:
void IWDG_Init(u8 prer,u16 rlr)
{
   IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //①使能对寄存器 I 写操作
   IWDG_SetPrescaler(prer); //②设置 IWDG 预分频值:设置 IWDG 预分频值
   IWDG_SetReload(rlr); //②设置 IWDG 重装载值
  IWDG_ReloadCounter(); //③按照 IWDG 重装载寄存器的值重装载 IWDG 计数器
  IWDG_Enable(); //④使能 IWDG
}
//喂独立看门狗
void IWDG_Feed(void)
{
   IWDG_ReloadCounter();//reload
}

使用特权

评论回复
地板
sunmeat|  楼主 | 2014-11-28 10:48 | 只看该作者
主逻辑区代码:
delay_init();//延时函数初始化
NVIC_Configuration(); //设置 NVIC 中断分组 2:2 位抢占优先级,2 位响应优先级
KEY_Init(); //按键初始化
IWDG_Init(4,625); //与分频数为 64,重载值为 625,溢出时间为 1s
while(1)
{
    if(KEY_Scan(0)==KEY_UP)
    {
        IWDG_Feed(); //如果 按键按下,则喂狗
    }
    delay_ms(10);
}
程序的功能就是通过按键打开看门狗,当看门狗被触发之后执行相应的操作。

使用特权

评论回复
5
sunmeat|  楼主 | 2014-11-28 10:48 | 只看该作者
再来看看窗体看门狗
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在 T6 位(WWDG->CR 的第六位)变成 0 前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU 复位。在递减计数器达到窗口配置寄存器(WWDG->CFR)数值之前,如果 7 位的递减计数器数值(在控制寄存器中)被刷新, 那么也将产生一个 MCU 复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。

使用特权

评论回复
6
sunmeat|  楼主 | 2014-11-28 10:49 | 只看该作者
看门狗时间计算公式:

窗口看门狗的超时公式如下:
Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;
其中:
Twwdg:WWDG 超时时间(单位为 ms)
Fpclk1:APB1 的时钟频率(单位为 Khz)
WDGTB:WWDG 的预分频系数
T[5:0]:窗口看门狗的计数器低 6 位

使用特权

评论回复
7
sunmeat|  楼主 | 2014-11-28 10:49 | 只看该作者
void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能
    WWDG_CNT=tr&WWDG_CNT; //初始化 WWDG_CNT.
    WWDG_SetPrescaler(fprer); //设置 IWDG 预分频值
    WWDG_SetWindowValue(wr); //设置窗口值
    WWDG_Enable(WWDG_CNT);
    //使能看门狗,设置 counter
    WWDG_ClearFlag(); //清除提前唤醒中断标志位
    WWDG_NVIC_Init(); //初始化窗口看门狗 NVIC
    WWDG_EnableIT(); //开启窗口看门狗中断
}
//重设置 WWDG 计数器的值
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt); //使能看门狗,设置 counter .
}
//窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG 中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占 2 子优先级 3 组 2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //抢占 2,子优先级 3,组 2
    NVIC_Init(&NVIC_InitStructure); //NVIC 初始化
}
void WWDG_IRQHandler(void)
{
    WWDG_SetCounter(WWDG_CNT);
    //当禁掉此句后,窗口看门狗将产生复位
    WWDG_ClearFlag();
    //清除提前唤醒中断标志位
    LED1=!LED1;
    //LED 状态翻转
}

使用特权

评论回复
8
sunmeat|  楼主 | 2014-11-28 10:49 | 只看该作者
主逻辑区代码:
int main(void)
{
    delay_init();//延时函数初始化
    NVIC_Configuration(); //设置 NVIC 中断分组 2
    usart1_init();串口1初始化
    LED_Init(); //LED 初始化
    KEY_Init(); //按键初始化
    LED0=0;
    delay_ms(500);
    WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为 7f,窗口寄存器为 5f,//分频数为 8
    while(1)
    {
        LED0=1;
    }
}

使用特权

评论回复
9
sunmeat|  楼主 | 2014-11-28 10:50 | 只看该作者
功能:
通过 LED0(DS0)来指示是否正在初始化。而 LED1(DS1)用来指示是否发生了中断。我们先让 LED0 亮 300ms,然后关闭以用于判断是否有复位发生了。在初始化 WWDG 之后,我们回到死循环,关闭 LED1,并等待看门狗中断的触发/复位。

使用特权

评论回复
10
sunmeat|  楼主 | 2014-11-28 10:50 | 只看该作者
再来分析一下独立看门狗(IWDG)和窗体看门狗(WWDG)的区别:

(1)独立看门狗没有中断,窗口看门狗有中断

(2)独立看门狗有硬件软件之分,窗口看门狗只能软件控制

(3)独立看门狗只有下限,窗口看门狗又下限和上限

(4)独立看门狗是12位递减的。窗口看门狗是7位递减的

(5)独立看门狗是用的内部的大约40KHZ RC振荡器,窗口看门狗是用的系统时钟APB1ENR

使用特权

评论回复
11
clvert| | 2017-2-16 11:09 | 只看该作者
请教一下楼主。我用的独立看门狗,大概是在大循环前初始化一下看门狗,然后没有在大循环里喂狗。实际效果是确实到了设定的时间大循环里的调试信息停了,但并没有重启。这是为何啊

附上看门狗初始化代码
void Inter_WatchDogInit(void)
{               
          // Enable write access to IWDG_PR and IWDG_RLR registers
    IWDG_Write_Enable(IWDG_WRITEACCESS_ENABLE);

    // IWDG counter clock: LSI/32
    /*   prescaler     min/ms      max/ms
            4                  0.1             409.6
            8                  0.2             819.2
            16                0.4             1638.4
            32                0.8             3276.8
            64                1.6             6553.5
            128              3.2             13107.2
            256              6.4             26214.4   
    */
    IWDG_SetPrescaler(IWDG_PRESCALER_64);

    /* Set counter reload value to obtain 250ms IWDG TimeOut.
    Counter Reload Value = 250ms/IWDG counter clock period
                  = 250ms / (LSI/32)
                  = 0.25s / (LsiFreq/32)
                  = LsiFreq/(32 * 4)
                  = LsiFreq/128
    */
    IWDG_SetReloadValue(3125);//625¶ÔӦΪ1 S
       
    // Reload IWDG counter
    IWDG_ReloadCounter();

    // Enable IWDG (the LSI oscillator will be enabled by hardware)
    IWDG_Enable();                       
}

使用特权

评论回复
12
pengxiao618| | 2017-2-16 11:33 | 只看该作者
clvert 发表于 2017-2-16 11:09
请教一下楼主。我用的独立看门狗,大概是在大循环前初始化一下看门狗,然后没有在大循环里喂狗。实际效果是 ...

你的代码注释写的是32分频,实际代码是64分频
代码注释写的是1s复位,实际算一算要50s左右才会复位

使用特权

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

本版积分规则

208

主题

2132

帖子

13

粉丝