笔记来源于江科协议的视频
芯片采用与stm32F103C8T6
简介
•WDG(Watchdog)看门狗
•看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性
•看门狗本质上是一个定时器,当指定时间范围内,程序没有执行喂狗(重置计数器)操作时,看门狗硬件电路就自动产生复位信号
•STM32内置两个看门狗
独立看门狗(IWDG):独立工作,对时间精度要求较低,每隔一段时间就喂狗
窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用,在固定的时间范围内喂狗,超时或早喂狗都不行,用的是APB1的时钟。
独立看门狗
框图
最左边是预分频器,在预分频器之前是输入时钟LSI,内部低速时钟,时钟频率40KHZ,时钟进入预分频器进行分频,预分频器只有8位,最大能进行256分频,上面的IWDG_PR可以配置分频系数,经过预分频器分频之后,时钟驱动递减计数器,每来一个时钟,递减一个数,计数器是12位的,最大值是4095,当自减到0后,产生IWDG复位。正常运行时,在重装寄存器IWDG_RLR写一个值,写好值之后,在运行过程中,在键寄存器中,写一个特定数据,控制电路,进行喂狗,这时重装值就会复制到计数器中,这样计数器就会回到重装值,重新自减运行,状态寄存器IWDG_SR,这就是标志电路的状态,里面只有两个更新同步位,上面的寄存器位于1.8V供电区域,下面主要工作区域位于VDD供电区,即在停机和待机模式仍能正常工作。独立看门狗也能唤醒待机模式。
键寄存器
•键寄存器本质上是控制寄存器,用于控制硬件电路的工作,如喂狗操作。
•在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值来代替控制寄存器写入一位的功能,以降低硬件电路受到干扰的概率
0xCCCC是启动看门狗,0xAAAA是看门狗寄存器的值加载到计数器中, 0x5555解除看门狗预分频器和重装值寄存器的保护,其他值是启动预分频器和重装值寄存器的写保护,状态寄存器是只读的。
•超时时间:TIWDG = TLSI × PR预分频系数 × (RL + 1)
•其中:TLSI = 1 / FLSI
窗口看门狗
框图
左下角是时钟源部分,是PCLK1,右边是预分频器,叫WDGTB,上面是6位递减计数器CNT,这个计数器是控制计数器CR里面的,窗口看门狗没有重装计数器,需要喂狗,直接在CNT写入数据即可,上面那一块是窗口值,也就是喂狗的最早时间界限,左边就是 输出信号的操作逻辑。
时钟来源PCLK1,也就是APB1的时钟,这个时钟是36Mhz,先经过预分频器分频,分频之后的时钟驱动计数器进行计数,每来一个时钟,递减一次,这个计数器只有T0~T5是有效计数值,最高位T6作为溢出标志位,T6=1时没有溢出,T6=0时溢出, WDGA是窗门狗的激活位,也就是使能位,写1启动看门狗,T6位一旦等于0就表示计数器溢出。
首先,需要计算最早界限的计数值,写到W6~W0,写入后,是固定不变的,一旦执行写入CR操作后,比较器后面的与门开关就会打开,写入CR也就是写入计数器,也就是喂狗,在喂狗时,比较器开始工作,一旦比较T6:0 > W6:0比较结果就输出为1. 就是喂狗时把当前计数值和预设的窗口值进行比较,喂狗太晚6位计数器减到0,复位,喂狗太早,计数器的值超过窗口值,复位。
工作特性
•递减计数器T[6:0]的值小于0x40时,WWDG产生复位
•递减计数器T[6:0]在窗口W[6:0]外被重新装载时,WWDG产生复位
•递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI),用于重装载计数器以避免WWDG复位,这个中断就是在溢出的前一刻发生,计数器的值为0x3F的时候才溢出。
•定期写入WWDG_CR寄存器(喂狗)以避免WWDG复位
上图是工作示意图,纵轴是T[6:0],递减计数器,喂狗之后,数值往下递减,计数值高于W[6:0],不允许喂狗,当计数值小于窗口值,进入到刷新窗口,可以喂狗,要在0x3F之前喂狗。0x3F就是T6等于0的时刻。下面T6和复位信号都在这个时刻产生。
超时时间
•超时时间:
TWWDG = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] + 1)
4096:因为时钟进来固定执行了一个4096分频,所以上面公式要乘以4096
•窗口时间:
TWIN = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] - W[5:0])
•其中:TPCLK1 = 1 / FPCLK1
分频系数只有1/2/4/8
对比
配置流程
独立看门狗
第一步:开启LSI内部低速时钟,这里的内部时钟可以随这看门狗的开启打开。并不需要写打开时钟
第二步:解除写保护 写入0x5555
第三步:然后再写入预分频和重装值
第四步:启动开门狗 0xCCCC
第五步:主循环喂狗 0xAAAA
窗口看门狗
第一步:开启apb1的时钟,
第二步:配置各个寄存器 //预分频 、窗口值
第三步:写入控制寄存器CR //看门狗使能、计数器溢出标志位、计数器有效位
第四步:不断写入重装值
代码
独立看门狗
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
Key_Init();
OLED_ShowString(1,1,"IWDG TEXT");
if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET)
{
OLED_ShowString(2,1,"IWDGRST");
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);
}
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //启动看门狗
IWDG_SetPrescaler(IWDG_Prescaler_16); //分频系数
IWDG_SetReload(2500 - 1); //重装值
IWDG_ReloadCounter(); //喂狗
IWDG_Enable(); //打开
while (1)
{
//Delay_ms(944);
IWDG_ReloadCounter(); //喂狗
OLED_ShowString(4, 1, "FEED"); //OLED闪烁FEED字符串
Delay_ms(200); //喂狗间隔为200+600=800ms
OLED_ShowString(4, 1, " ");
Delay_ms(600);
}
}
窗口看门狗
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
Key_Init();
OLED_ShowString(1,1,"WWDG TEXT");
if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)
{
OLED_ShowString(2,1,"WWDGRST");
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);
WWDG_SetWindowValue(0x40 | 0x21); //窗口值20ms
WWDG_Enable(0x40 | 0x54); //使能并第一次喂狗,超时时间为50ms
while (1)
{
Key_GetNum();
OLED_ShowString(4, 1, "FEED");
Delay_ms(20);
OLED_ShowString(4, 1, " ");
Delay_ms(20);
WWDG_SetCounter(0x40 | 0x54);
}
}