独立看门狗
防止程序陷入死循环----使程序进行一个复位,和窗口看门狗都是进行一个软件层面的故障排除,提升程序抗干扰的能力
独立看门狗以及窗口看门狗
独立看门狗(IWDG)–LSI提供时钟
其和主程序使用的是两个不同的时钟
原理:实质是一个12位的递减计数器–每来一个时钟脉冲就进行减1,再减到0的时候,单片机就会进行一个复位。所以再再等到计数器减少到0x000之前就要提供一个重装载值进去
独立看门狗初始化
1.操作看门狗-首先对预分频器进行一个设置也就是设置多少时间减少一次
2.设置预装载值,再这个值的基础上,每来一个脉冲进行减一操作。
初始化流程
- 判断是不是独立看门狗引发的复位-进行相应的操作
- 设置键寄存器的值,表示允许写入预分频器的值以及各种值
- 开始写入值
- 预分频器决定计时时间 40Khz / 分频数(此时32分频) = 1250HZ
- 设置重装值(因为是12位的计数器所以最大设置成4095),设置成1250就是超过1S就喂狗一次
- 预分频器值说明:也就是1S产生1250个脉冲,重装值此时就是设置1250个值,每来一个脉冲值就会减1,所以此时就是1S中进行一次喂狗
代码
void IWDG_Init(void)
{
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) //如果是独立看门狗复位
{
/*
可以添加显示操作
*/
RCC_ClearFlag(); //清除标志位
}
else //否则,即为正常的系统复位
{
/*
可以添加显示操作
*/
}
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//这一步表示允许写入预装值以及预分频器的值
IWDG_SetPrescaler(IWDG_Prescaler_32); //设置预分频为32
IWDG_SetReload(1249); //设置重装值为2499,独立看门狗的超时时间为1000ms
IWDG_ReloadCounter(); //重装计数器,喂狗
IWDG_Enable(); //独立看门狗使能
}
喂狗操作:
也就是再主程序中某一个位置,再看门狗减少到0之前进行一个喂狗操作。现在我800ms就喂一次狗,保证程序执行正常
int main()
{
while (1)
{
Key_GetNum(); //调用阻塞式的按键扫描函数,模拟主循环卡死
IWDG_ReloadCounter(); //重装计数器,喂狗
OLED_ShowString(4, 1, "FEED"); //OLED闪烁FEED字符串
Delay_ms(200); //喂狗间隔为200+600=800ms
OLED_ShowString(4, 1, " ");
Delay_ms(600);
}
}
注意:在主函数中会导致各种进程加这个自己延时的时间是不准确的喂狗,所以可以加一个定时器来实现定时喂狗。标准操作。
在定时中断中,假设定时是1ms进一次中断,所以就此时表示400ms喂一次狗。
void Time_IRqHandler(void)
{
const uint8_t count;
……
count++;
if(count>=400)
{
count=0;
IWDG_ReloadCounter(); //喂狗
}
}
窗口看门狗-WWDG
**定义:**比独立看门狗的时间要求更见严格,必须要在一个时间窗口之内进行喂狗,提前喂狗和之后,都会导致复位–窗口看门狗的时钟是来源于系统时钟
特点:这个在递减过程中,当递减到0X40的时候,就会产生复位,并不是和独立看门狗一样的0x00,此时会产生早期的中断
其中存在的计数器就是设置这个最大的计数时间(保证来时钟脉冲之后从哪一个值开始减1),127最大。看门狗的配置寄存器就是用于设置具体喂狗的窗口时间的上限值(低于计数值,大于下限值),下限值已经确定好了就是0X40这个时间。
初始化看门狗的流程
- 判断是不是进行了窗口看门狗的复位
- 由于脉冲信号是来源于系统时钟,所以需要先开启系统时钟
- 设置预分频器的值。1/2/4/8分频,PCLK1(36MHZ /4096)/8 =1099HZ (约910us),此时里面已经确定了先进行4096分频,在进行8分频,所以此时就是约910us减一一次
- 设置配置寄存器的值,也就是窗口值的上限,下限值已经内部确定了就是0x40
- 此时设置的80,所以((127-80)+1)*910=43ms,这就表示43ms就会减少到80的值
- 下限值为64 ((127-64)+1)*910 = 58ms,所以就需要在43ms --58ms之内进行喂狗,不会引发复位
代码
void WWDG_Init(void)
{
/*判断复位信号来源*/
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) //如果是窗口看门狗复位
{
/*执行相关的操作*/
RCC_ClearFlag(); //清除标志位
}
else //否则,即为其他复位
{
/*执行相关的操作*/
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //开启WWDG的时钟
WWDG_SetPrescaler(WWDG_Prescaler_8); //设置预分频为8
WWDG_SetWindowValue(80); //设置窗口值,窗口时间为80
WWDG_Enable(127);// 最大127
}
喂狗操作
更新计数值即可实现喂狗的操作。一般还是使用定时中断或者使用这个窗口看门狗独有的中断进行喂狗
int main()
{
while(1)
{
Key_GetNum(); //调用阻塞式的按键扫描函数,模拟主循环卡死
OLED_ShowString(4, 1, "FEED"); //OLED闪烁FEED字符串
Delay_ms(20); //喂狗间隔为20+20=40ms
OLED_ShowString(4, 1, " ");
Delay_ms(20);
WWDG_SetCounter(127); //重装计数器,喂狗
}
}
在定时中断中,假设定时是1ms进一次中断,所以此时就要注意喂狗时间要在58-43ms之间进行喂狗操作。一定要在窗口期进行喂狗
void Time_IRqHandler(void)
{
const uint8_t count;
……
count++;
if(count>=50)
{
count=0;
WWDG_SetCounter(127); //喂狗
}
}
###窗口看门狗独有的中断###
在初始化中需要配置好中断–EWI早期唤醒中断
void WWDG_Init(void)
{
/*判断复位信号来源*/
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET) //如果是窗口看门狗复位
{
/*执行相关的操作*/
RCC_ClearFlag(); //清除标志位
}
else //否则,即为其他复位
{
/*执行相关的操作*/
}
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); //开启WWDG的时钟
WWDG_SetPrescaler(WWDG_Prescaler_8); //设置预分频为8
WWDG_SetWindowValue(80); //设置窗口值,窗口时间为80
WWDG_Enable(127);// 最大127,给定计数值,差不多也就是使能窗口看门狗
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //选择配置NVIC的USART1线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
WWDG_ClearFlag();//清除标志位,防止立刻进入中断,先清除,在施使能,不可以改变顺序
WWDG_EnableIT();//使能中断
}
**中断服务函数:**在0X40的时候就会进入这个早期唤醒中断,但是在0x40-1=0x3f的时候就会执行复位操作
void WWDG_IRQHandler(void)
{
if(WWDG_GetFlagStatus() == SET)
{
/*
在此处就进行一些参数保存,重要的操作,
*/、
WWDG_Enable(127);// 最大127,给定计数值,差不多也就是使能窗口看门狗,一般不在这里喂狗,主要是执行特殊的操作
WWDG_ClearFlag();//清除标志位
}
}
http://note.youdao.com/s/bUfnimyN 最后附上学习的老师——金善愚老师的文档,大家可以一起学习