依旧转的正点的教材
http://www.openedv.com/posts/list/0/11806.htm?privmsg=1#71344
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位(WWDG->CR的第六位)变成0前被刷新,看门狗电路在达到预置的时间周期时,会产生一个MCU复位。在递减计数器达到窗口配置寄存器(WWDG->CFR)数值之前,如果7位的递减计数器数值(在控制寄存器中)被刷新, 那么也将产生一个MCU复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。他们的关系可以用图12.1.1来说明:
图12.1.1 窗口看门狗工作示意图
图12.1.1中,T[6:0]就是WWDG_CR的低七位,W[6:0]即是WWDG->CFR的低七位。T[6:0]就是窗口看门狗的计数器,而W[6:0]则是窗口看门狗的上窗口,下窗口值是固定的(0X40)。当窗口看门狗的计数器在上窗口值之外被刷新,或者低于下窗口值都会产生复位。
上窗口值(W[6:0])是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保窗口值大于0X40,否则窗口就不存在了。
窗口看门狗的超时公式如下:
Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;
其中:
Twwdg:WWDG超时时间(单位为ms)
Fpclk1:APB1的时钟频率(单位为Khz)
WDGTB:WWDG的预分频系数
T[5:0]:窗口看门狗的计数器低6位
根据上面的公式,假设Fpclk1=36Mhz,那么可以得到最小-最大超时时间表如表12.1.1所示:
表12.1.1 36M时钟下窗口看门狗的最小最大超时表
接下来,我们介绍窗口看门狗的3个寄存器。首先介绍控制寄存器(WWDG_CR),该寄存器的各位描述如图12.1.2所示:
图12.1.2 WWDG_CR寄存器各位描述
可以看出,这里我们的WWDG_CR只有低八位有效,T[6:0]用来存储看门狗的计数器值,随时更新的,每个看窗口看门狗计数周期(4096×2^ WDGTB)减1。当该计数器的值从0X40变为0X3F的时候,将产生看门狗复位。
WDGA位则是看门狗的激活位,该位由软件置1,以启动看门狗,并且一定要注意的是该位一旦设置,就只能在硬件复位后才能清零了。
窗口看门狗的第二个寄存器是配置寄存器(WWDG_CFR),该寄存器的各位及其描述如图12.1.3所示:
图12.1.3 WWDG_ CFR寄存器各位描述
该位中的EWI是提前唤醒中断,也就是在快要产生复位的前一段时间(T[6:0]=0X40)来提醒我们,需要进行喂狗了,否则将复位!因此,我们一般用该位来设置中断,当窗口看门狗的计数器值减到0X40的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中断里面向WWDG_CR重新写入计数器的值,来达到喂狗的目的。注意这里在进入中断后,必须在不大于1个窗口看门狗计数周期的时间(在PCLK1频率为36M且WDGTB为0的条件下,该时间为113us)内重新写WWDG_CR,否则,看门狗将产生复位!
最后我们要介绍的是状态寄存器(WWDG_SR),该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位0有效,其他都是保留位。当计数器值达到40h时,此位由硬件置1。它必须通过软件写0来清除。对此位写1无效。即使中断未被使能,在计数器的值达到0X40的时候,此位也会被置1。
在介绍完了窗口看门狗的寄存器之后,我们介绍要如何启用STM32的窗口看门狗。这里我们介绍的方法是用中断的方式来喂狗的。采取的步骤如下:
1)使能WWDG时钟
WWDG不同于IWDG,IWDG有自己独立的40Khz时钟,不存在使能问题。而WWDG使用的是PCLK1的时钟,需要先使能时钟。
2)设置WWDG_CFR和WWDG_CR两个寄存器
在时钟使能完后,我们设置WWDG的CFR和CR两个寄存器,对WWDG进行配置。包括使能窗口看门狗、开启中断、设置计数器的初始值、设置窗口值并设置分频数WDGTB等。
3)开启WWDG中断并分组
在设置完了WWDG后,需要配置该中断的分组及使能。这点通过我们之前所编写的MY_NVIC_Init函数实现就可以了。
4)编写中断服务函数
在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当窗口看门狗计数器值减到0X3F的时候,就会引起软复位了。在中断服务函数里面也要将状态寄存器的EWIF位清空。
完成了以上4个步骤之后,我们就可以使用STM32的窗口看门狗了。这一章的实验,我们将通过DS0来指示STM32是否被复位了,如果被复位了就会点亮300ms。DS1用来指示中断喂狗,每次中断喂狗翻转一次。
1 //初始化窗口看门狗 2 //tr :T[6:0],计数器值 3 //wr :W[6:0],窗口值 4 //fprer:分频系数(WDGTB),仅最低2位有效 5 //Fwwdg=PCLK1/(4096*2^fprer). 6 //窗口看门狗的超时公式如下: 7 // 8 // Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1; 9 // 10 //其中: 11 // 12 // Twwdg:WWDG超时时间(单位为ms) 13 // 14 // Fpclk1:APB1的时钟频率(单位为Khz) 15 // 16 // WDGTB:WWDG的预分频系数 17 // 18 // T[5:0]:窗口看门狗的计数器低6位 19 20 void WWDG_Config(u8 tr,u8 wr,u32 fprer) 21 { 22 RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG时钟使能 23 24 //WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT. 25 WWDG_SetPrescaler(fprer);////设置IWDG预分频值 26 27 WWDG_SetWindowValue(wr);//设置窗口值 28 29 //WWDG_Enable(WWDG_CNT); //使能看门狗 , 设置 counter . 30 WWDG_Enable(tr); 31 32 WWDG_ClearFlag();//清除提前唤醒中断标志位 33 34 WWDG_NVIC_Init();//初始化窗口看门狗 NVIC 35 36 WWDG_EnableIT(); //开启窗口看门狗中断 37 38 }
1 //重设置WWDG计数器的值 2 void WWDG_Set_Counter(u8 cnt) 3 { 4 WWDG_Enable(cnt);//使能看门狗 , 设置 counter . 5 }
1 void WWDG_NVIC_Init() 2 { 3 NVIC_InitTypeDef NVIC_InitStructure; 4 NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //WWDG中断 5 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占2,子优先级3,组2 6 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //抢占2,子优先级3,组2 7 NVIC_Init(&NVIC_InitStructure);//NVIC初始化 8 }
1 void WWDG_IRQHandler(void) 2 { 3 WWDG_SetCounter(WWDG_CNT); //当禁掉此句后,窗口看门狗将产生复位 4 WWDG_ClearFlag(); //清除提前唤醒中断标志位 5 6 }
#define WWDG_CNT 0x7f
WWDG_Config(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8