目录
一.看门狗简介
二.代码实现
一.看门狗简介
IWDG的专用时钟是LSI,内部低速时钟
WWDG使用的是APB1的时钟,并没有专门的时钟,所以并不独立
如果独立看门狗已经由硬件选项或软件启动, LSI振荡器将被强制在打开状态,并且不能被关闭。在LSI振荡器稳定后,时钟供应给IWDG
喂狗或使能的时候会在键寄存器写入0x5555之外的值
进行寄存器的写保护
尽量让预分频系数小,因为有时根据结果算出的RL可能是小数,那么取整以后会造成每次喂狗都会有一点的误差,但预分频系数大的话,会减少RL的重置频率
这些时间是按照40kHz时钟给出。实际上,MCU内部的RC频率会在30kHz到60kHz之间变化
所以在计算超时时间时,可以对频率进行范围取值
PCLK1时钟信号进入时先执行一个固定的4096分频
窗口看门狗需要自行启动时钟
但没有写入保护
EWI:死前中断,可以用来执行一些紧急操作,保存数据,关闭危险设备
看门狗一旦启用就无法关闭了,系统复位后可以关闭 ,且计时时的计数器的值无法读取出来
二.代码实现
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);//对写操作进行配置
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//写预分频器
void IWDG_SetReload(uint16_t Reload);//写重装值
void IWDG_ReloadCounter(void);//重新装载寄存器,喂狗
void IWDG_Enable(void);//启动独立看门狗
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG);
void RCC_ClearFlag(void);
* @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
* @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
* @arg RCC_FLAG_PLLRDY: PLL clock ready
* @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
* @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready//前面都是等待时钟准备
* @arg RCC_FLAG_PINRST: Pin reset按键复位
* @arg RCC_FLAG_PORRST: POR/PDR reset上电复位和掉电复位
* @arg RCC_FLAG_SFTRST: Software reset软件复位
* @arg RCC_FLAG_IWDGRST: Independent Watchdog reset独立看门狗
* @arg RCC_FLAG_WWDGRST: Window Watchdog reset窗口
* @arg RCC_FLAG_LPWRRST: Low Power reset低功耗复位
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
int main(void)
{
OLED_Init();
Key_Init();
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(200);
OLED_ShowString(3,1," ");
Delay_ms(200);
}
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_16);
IWDG_SetReload(2499);
IWDG_ReloadCounter();
IWDG_Enable();//喂狗或使能的时候会在键寄存器写入0x5555之外的值,实现写保护
while(1)
{
Keynum();
IWDG_ReloadCounter();
OLED_ShowString(4,1,"FEED");
Delay_ms(170);
OLED_ShowString(4,1," ");
Delay_ms(800);
//加“Feed”延时970就超时喂狗了
//无35,36,37,延时979就超时了
}
}
(2)窗口看门狗
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);//递减计数器处于自由运行状态,为避免刚一使能就立马复位,所以使能时要随便喂一下狗
FlagStatus WWDG_GetFlagStatus(void);
void WWDG_ClearFlag(void);
但由于看门狗开启后是不能再被关闭的,所以最高位写入0的操作是无效的
“读-改-写”操作
1.先将寄存器读到临时变量里
2.用|= ,&=的操作,改变临时变量的指定几位
3.将临时变量写回寄存器
这样可以单独改变寄存器的某几位,而不改变其他位的值,且如果连续改变不同的位,效率较高,而且所以更改的位在最后写回寄存器时同时生效
但窗口看门狗启动后,由于对最高位的写入没有任何作用,所以不用使用到“读-改-写”操作,可以直接进行写入计数值
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"
int main(void)
{
OLED_Init();
Key_Init();
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(200);
OLED_ShowString(3,1," ");
Delay_ms(200);
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
WWDG_SetPrescaler(WWDG_Prescaler_8);
WWDG_SetWindowValue(21 | 0x40);//将次高位置1,将T[6:0]和W[6:0]都加上0x40
WWDG_Enable(54 | 0x40);//将次高位置1,防止其产生溢出触发
while(1)
{
Keynum();
OLED_ShowString(4,1,"FEED");
Delay_ms(20);
OLED_ShowString(4,1," ");
Delay_ms(20);
WWDG_SetCounter(54 | 0x40);//喂狗放在延时之后目的是防止程序运行,与使能函数间隔太小,过早喂狗,程序卡死
}
}
,