独立看门狗概念
独立看门狗工作在主程序之外,能够完全独立工作,它的时钟是专用的低速时钟(LSI),由VDD 电压供电, 在停止模式和待机模式下仍能工作
独立看门狗本质
独立看门狗本质是一个 12 位的递减计数器,当计数器的值从某个值一直减到0的时候,系统就会产生一个复位信号,即 IWDG_RESET 。
如果在计数没减到0之前,刷新了计数器的值的话,那么就不会产生复位信号,这个动作就是我们经常说的喂狗。
独立看门狗框图
独立看门狗时钟
独立看门狗的时钟由独立的RC振荡器LSI提供,即使主时钟发生故障它仍然有效,非常独立。启用IWDG后,LSI时钟会自动开启。LSI时钟频率并不精确,F1用40kHz。
LSI经过一个8位的预分频器得到计数器时钟。
预分频寄存器
分频系数算法
prer是IWDG_PR 的值
溢出计算时间公式
HAL_UART_Transmit(&huart1,(unsigned char *)"hello world\r\n",strlen("hello world\r\n"),200); //while(1) 之前运行,每1秒溢出,重复程序
//按键喂狗 使得程序继续运行
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY1_Pin)
{
HAL_IWDG_Refresh(&hiwdg);
}
}
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);//喂狗: 写0xAAAA到KR
void IWDG_Enable(void);//使能看门狗: 写0xCCCC到KR
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);//状态:重装载/预分频 更新
IWDG_WriteAccessCmd();
IWDG_SetPrescaler();
IWDG_SetReload();
IWDG_Enable();
IWDG_ReloadCounter();
//初始化独立看门狗
//prer: 分频数:0~7(只有低3位有效!)
//分频因子=4*2^prer.但最大值只能是256!
//rlr:重装载寄存器值:低11位有效.
//时间计算(大概):Tout=((4*2^prer)*rlr)/40 (ms).
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//使能对寄存器IWDG_PR和IWDG_RLR的写操作,取消写保护
IWDG_SetPrescaler(prer); //设置IWDG预分频值:设置IWDG预分频值为64
IWDG_SetReload(rlr); //设置IWDG重装载值
IWDG_ReloadCounter(); //按照IWDG重装载寄存器的值重装载IWDG计数器 加载寄存器
IWDG_Enable(); //使能看门狗
}
//喂独立看门狗
void IWDG_Feed(void)
{
IWDG_ReloadCounter(); //重载计数值
}
int main(void)
{
delay_init(); //延时函数初始化
LED_Init();
KEY_Init();
delay_ms(1000); //看得到灭
IWDG_Init(4,625); //预分频数64, 重载值为625, 溢出时间为1s
LED1=0; //点亮LED0
while(1)
{
//按键进行对独立看门狗喂狗
if(KEY_Scan()==KEY1_PRES)
{
IWDG_Feed(); //如果KEY1按下,则喂狗
}
delay_ms(10);
}
}
什么是窗口看门狗?
窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测程序运行时间的场合。
窗口看门狗的本质是一个能产生系统复位信号和提前唤醒中断的6位计数器。
产生复位条件:
当递减计数器值从 0x40 减到 0x3F 时复位(即T6位跳变到0)
计数器的值大于 W[6:0] 值时喂狗会复位。
产生中断条件: 当递减计数器等于 0x40 时可产生提前唤醒中断 (EWI)。
在窗口期内重装载计数器的值,防止复位,也就是所谓的喂狗。
窗口看门狗工作原理
WWDG框图
控制寄存器
配置寄存器
状态寄存器
超时时间计算
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET);
HAL_Delay(500);
MX_WWDG_Init();
while (1)
{
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET);
HAL_Delay(500);
}
}
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
HAL_WWDG_Refresh(hwwdg); //喂狗
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
}
窗口看门狗配置过程
1.使能看门狗时钟:RCC_APB1PeriphClockCmd();
2.设置分频系数:WWDG_SetPrescaler();
3.设置窗口值:WWDG_SetWindowValue();
4.开启提前唤醒中断并分组(可选):
WWDG_EnableIT();
NVIC_Init();
5.使能看门狗:
WWDG_Enable();
6.喂狗:WWDG_SetCounter();
7.编写终端服务函数:WWDG_IRQHandler();
wwdg.c 窗口看门狗程序设计
//保存WWDG计数器的设置值,默认为最大.
u8 WWDG_CNT=0x7f;
//初始化窗口看门狗
//tr :T[6:0],计数器值
//wr :W[6:0],窗口值
//fprer:分频系数(WDGTB),仅最低2位有效
//Fwwdg=PCLK1/(4096*2^fprer).
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_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure); //NVIC初始化
}
主函数程序初始化
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
LED_Init();
LED1=0; //点亮LED0
delay_ms(1000);
WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8
while(1)
{
LED1 = 1;
delay_ms(40);
}
}
提前唤醒中断服务函数
void WWDG_IRQHandler(void) //窗口看门狗 中断服务函数
{
WWDG_SetCounter(WWDG_CNT); //当禁掉此句后,窗口看门狗将产生复位
WWDG_ClearFlag(); //清除提前唤醒中断标志位
LED1=!LED1; //LED状态翻转
}
对比点 | 独立看门狗 | 窗口看门狗 |
---|---|---|
时钟源 | 独立时钟,LSI (40KHz) ,不精确 | PCLK1或PCLK3,精确 |
复位条件 | 递减计数到0 | 窗口期外喂狗或减到0x3F |
中断 | 没有中断 | 计数值减到0x40可产生中断 |
递减计数器位数 | 12位(最大计数范围:4096 ~ 0) | 7位(最大计数范围:127~63) |
应用场合 | 防止程序跑飞,死循环,死机 | 检测程序时效,防止软件异常 |