一 前沿废语:
之前有很风靡的游戏,名字叫《看门狗》。该游戏用了很新的引擎技术,打造出了一个辽阔庞大的世界,内容是玩家Aiden·Pearce(主角)是一名精通黑客技术的高手,当时的世界是处于所有物品都被置了电子设备控制,整个城市都在依赖着他们,主人公决定利用自己的技术为这个世界惩奸除恶。
这个游戏以极高的*度、出色的游戏质量与丰富的游戏内容被业界公认为开启次世代游戏的大门之作,该游戏被IGN评为年度最佳射击游戏(下载地址:http://down.ali213.net/pcgame/WatchDogs.html 有机会一定玩玩。)
二 开门见山:
下面言归正传,在工作中用的STM32需要使用看门狗技术:
看门狗通俗解释:
单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路就是为了避免这种情况的发生。看门狗的作用就是在一定时间内(通过定时计数器实现)没有接收喂狗信号(表示 MCU 已经挂了),便实现处理器的自动复位重启(发送复位信号)。
三 庐山面目:
STM32芯片一共有两个看门狗,一个是独立看门狗(IWDG),另一个是窗体看门狗(WWDG)
①先来讲讲独立看门狗:
STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然
有效。这里需要注意独立看门狗的时钟是一个内部 RC 时钟,所以并不是准确的 40Khz,而是
在 30~60Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 40Khz 的频率来计算,看
门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。
独立看门狗的配置工作代码:
1 void IWDG_Init(u8 prer,u16 rlr) 2 { 3 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //①使能对寄存器 I 写操作 4 IWDG_SetPrescaler(prer); //②设置 IWDG 预分频值:设置 IWDG 预分频值 5 IWDG_SetReload(rlr); //②设置 IWDG 重装载值 6 IWDG_ReloadCounter(); //③按照 IWDG 重装载寄存器的值重装载 IWDG 计数器 7 IWDG_Enable(); //④使能 IWDG 8 } 9 //喂独立看门狗 10 void IWDG_Feed(void) 11 { 12 IWDG_ReloadCounter();//reload 13 }
主逻辑区代码:
1 delay_init();//延时函数初始化 2 NVIC_Configuration(); //设置 NVIC 中断分组 2:2 位抢占优先级,2 位响应优先级 3 KEY_Init(); //按键初始化 4 IWDG_Init(4,625); //与分频数为 64,重载值为 625,溢出时间为 1s 5 while(1) 6 { 7 if(KEY_Scan(0)==KEY_UP) 8 { 9 IWDG_Feed(); //如果 按键按下,则喂狗 10 } 11 delay_ms(10); 12 }
程序的功能就是通过按键打开看门狗,当看门狗被触发之后执行相应的操作。
②再来看看窗体看门狗
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序
背离正常的运行序列而产生的软件故障。除非递减计数器的值在 T6 位(WWDG->CR 的第六位)
变成 0 前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU 复位。在递减计数
器达到窗口配置寄存器(WWDG->CFR)数值之前,如果 7 位的递减计数器数值(在控制寄存器中)
被刷新, 那么也将产生一个 MCU 复位。这表明递减计数器需要在一个有限的时间窗口中被刷
新。
看门狗时间计算公式:
窗口看门狗的超时公式如下:
Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;
其中:
Twwdg:WWDG 超时时间(单位为 ms)
Fpclk1:APB1 的时钟频率(单位为 Khz)
WDGTB:WWDG 的预分频系数
T[5:0]:窗口看门狗的计数器低 6 位
1 void WWDG_Init(u8 tr,u8 wr,u32 fprer) 2 { 3 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能 4 WWDG_CNT=tr&WWDG_CNT; //初始化 WWDG_CNT. 5 WWDG_SetPrescaler(fprer); //设置 IWDG 预分频值 6 WWDG_SetWindowValue(wr); //设置窗口值 7 WWDG_Enable(WWDG_CNT); 8 //使能看门狗,设置 counter 9 WWDG_ClearFlag(); //清除提前唤醒中断标志位 10 WWDG_NVIC_Init(); //初始化窗口看门狗 NVIC 11 WWDG_EnableIT(); //开启窗口看门狗中断 12 } 13 //重设置 WWDG 计数器的值 14 void WWDG_Set_Counter(u8 cnt) 15 { 16 WWDG_Enable(cnt); //使能看门狗,设置 counter . 17 } 18 //窗口看门狗中断服务程序 19 void WWDG_NVIC_Init() 20 { 21 NVIC_InitTypeDef NVIC_InitStructure; 22 NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG 中断 23 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占 2 子优先级 3 组 2 24 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //抢占 2,子优先级 3,组 2 25 NVIC_Init(&NVIC_InitStructure); //NVIC 初始化 26 } 27 void WWDG_IRQHandler(void) 28 { 29 WWDG_SetCounter(WWDG_CNT); 30 //当禁掉此句后,窗口看门狗将产生复位 31 WWDG_ClearFlag(); 32 //清除提前唤醒中断标志位 33 LED1=!LED1; 34 //LED 状态翻转 35 }
主逻辑区代码:
1 int main(void) 2 { 3 delay_init();//延时函数初始化 4 NVIC_Configuration(); //设置 NVIC 中断分组 2 5 usart1_init();串口1初始化 6 LED_Init(); //LED 初始化 7 KEY_Init(); //按键初始化 8 LED0=0; 9 delay_ms(500); 10 WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为 7f,窗口寄存器为 5f,//分频数为 8 11 while(1) 12 { 13 LED0=1; 14 } 15 }
功能:
通过 LED0(DS0)来指示是否正在初始化。而 LED1(DS1)用来指示是否发生了中
断。我们先让 LED0 亮 300ms,然后关闭以用于判断是否有复位发生了。在初始化 WWDG 之
后,我们回到死循环,关闭 LED1,并等待看门狗中断的触发/复位。
四 泛泛而谈:
再来分析一下独立看门狗(IWDG)和窗体看门狗(WWDG)的区别: