STM32学习笔记19-WDG
WDG简介
- WDG(Watchdog)看门狗
- 看门狗可以监控程序的运行状态,当程序因为设计漏洞、硬件故障、电磁干扰等原因,出现卡死或跑飞现象时,看门狗能及时复位程序,避免程序陷入长时间的罢工状态,保证系统的可靠性和安全性
- 看门狗本质上是一个定时器,当指定时间范围内,程序没有执行喂狗(重置计数器)操作时,看门狗硬件电路就自动产生复位信号
- STM32内置两个看门狗,一般的开启后,不能再随便关闭,除非复位
独立看门狗(IWDG):独立工作(专用的LSI内部低速时钟),对时间精度要求较低
窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用
IWDG
IWDG框图
IWDG键寄存器
- 键寄存器本质上是控制寄存器,用于控制硬件电路的工作
- 在可能存在干扰的情况下,一般通过在整个键寄存器写入特定值来代替控制寄存器写入一位的功能,以降低硬件电路受到干扰的概率
IWDG超时时间
- 超时时间:TIWDG = TLSI × PR预分频系数 × (RL + 1)
- 其中:TLSI = 1 / FLSI
- FLSI 固定为=0.025m
- RL是根据要求的超时时间和已知条件倒退出来的
WWDG
WWDG框图
WWDG工作特性
- 递减计数器T[6:0]的值小于0x40时,WWDG产生复位
- 递减计数器T[6:0]在窗口W[6:0]外被重新装载时,WWDG产生复位——不能过早喂狗
- 递减计数器T[6:0]等于0x40时可以产生早期唤醒中断(EWI),用于重装载计数器以避免WWDG复位——死前中断,紧急警告
- 定期写入WWDG_CR寄存器(喂狗)以避免WWDG复位
WWDG超时时间
- 超时时间:喂狗的最晚时间
TWWDG = TPCLK1 × 4096 ×WDGTB预分频系数 × (T[5:0] + 1)
- 窗口时间:喂狗的最早时间
TWIN = TPCLK1 × 4096 × WDGTB预分频系数 × (T[5:0] - W[5:0])
- 其中:TPCLK1 = 1 / FPCLK1,,x4096是因为PCLK1会固定分个4096的频率,
- WDGTB预分频系数=2 WDGTB预分频系数
IWDG和WWDG对比
接线图:
14-1 独立看门狗
- 开启时钟,开启LSI时钟,根据手册得知LSI不需要手动开启,当开启独立看门狗时会自动开启
- 解除写保护,写入键寄存器的值为0x5555
- 写入预分频和重装值——根据超时时间公式计算
- 启动看门狗,写入键寄存器的值为0xCCCC
- 通过不断执行写入键寄存器为0xAAAA,进行喂狗
IWDG相关函数:
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess); //写使能函数,写入键寄存器的值为0x5555
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler); //写预分频器,写入PR寄存器中
void IWDG_SetReload(uint16_t Reload); //写重装值,写入RLR寄存器
void IWDG_ReloadCounter(void); //重新装载寄存器,就是喂狗
void IWDG_Enable(void); //启用独立看门狗,写入键寄存器的值为0xCCCC
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG); //获取标志位状态
RCC.h //由于本实验我们需要观察究竟是看门狗导致的复位还是上下电导致的复位所以我们使用此函数来查看复位标志位
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);
void RCC_ClearFlag(void); //需要手动清除
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "key.h"
//#include "OLED_Font.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,"IWDGRST");Delay_ms(500);OLED_ShowString(2,1," ");Delay_ms(100);RCC_ClearFlag();}else{OLED_ShowString(3,1,"REST");Delay_ms(500);OLED_ShowString(3,1," ");Delay_ms(100);}//看门狗的配置//开启LSI,自动的//写使能开启IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//配置预分频和重装值,超时时间为1s=1000msIWDG_SetPrescaler(IWDG_Prescaler_16);IWDG_SetReload(2499);IWDG_ReloadCounter();//在喂狗和使能时,会在键寄存器中写入5555之外的值,这样就起到写保护,不用手动配置保护//启动看门狗,在启动之前,先喂一次狗,这样可以使第一次的周期就是1sIWDG_Enable();while(1){Key_GetNum();//按住按键,主循环阻塞,不能及时喂狗,独立看门狗复位IWDG_ReloadCounter();OLED_ShowString(4,1,"FEED");Delay_ms(200);OLED_ShowString(4,1," ");Delay_ms(600);}
}
14-2 窗口看门狗
- 开启APB1窗口看门狗的时钟PCLK1
- 配置各个寄存器:预分频GTB、窗口值CFR
- 写入控制寄存器CR,包含:寄存器使能位,计数器溢出标志位和计数器有效位
- 不断向CR计数器写入重装值-喂狗
WWDG相关函数:
void WWDG_DeInit(void);
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); //写入预分频器
void WWDG_SetWindowValue(uint8_t WindowValue); //写入窗口值
void WWDG_EnableIT(void); //使能中断
void WWDG_SetCounter(uint8_t Counter); //写入计数器
void WWDG_Enable(uint8_t Counter); //使能窗口看门狗 为了避免刚一使能,就立马复位,所以传入uint8_t Counter,进行喂狗
//标志位
FlagStatus WWDG_GetFlagStatus(void);
void WWDG_ClearFlag(void);
读-改-写:函数操作配置
- 先把寄存器读到临时变量中
- 用|=、&=的操作,改变临时变量的指定几位
- 把临时变量,写回到寄存器中
作用:
- 可以单独改变寄存器的某几位,而不影响其他位值;
- 如果连续更改多次不同的位,效率高
- 所有更改的位,在最终写回到寄存器时同时生效
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "key.h"
//#include "OLED_Font.h"
// 窗口看门狗int main(void){OLED_Init();Key_Init();//开启对于时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);OLED_ShowString(1,1,"WWDG TEST");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,"REST");Delay_ms(500);OLED_ShowString(3,1," ");Delay_ms(100);}//配置初始化:预分频器和窗口值:根据公式,确定想要的超时时间:50ms(最晚时间)和窗口时间:30ms(最早时间)//所以预分频GTB为8,控制寄存器T[0:5]为54,窗口值W[0:5]为21WWDG_SetPrescaler(WWDG_Prescaler_8);WWDG_SetWindowValue(0x40|21); //同理T[:]//使能WWDG_Enable(0x40|54);//0x40|T[0:5]:使T[6]为1while(1){Key_GetNum();//喂狗//但是如果喂狗放在这里,则会与使能第一次喂狗太近了,从而触发看门狗复位// WWDG_SetCounter(0x40|54);//会把CR中的WDGA清零0,但是不是关闭看门狗// OLED_ShowString(4,1,"FEED");
// Delay_ms(20);
// OLED_ShowString(4,1," ");Delay_ms(31);WWDG_SetCounter(0x40|54);}
}