赞
踩
目录
我们将使用窗口看门狗的中断功能来喂狗,通过 DS0 和 DS1提示程序的运行状态
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。
除非递减计数器的值在 T6 位(WWDG->CR 的第六位) 变成 0 前被刷新,看门狗电路在达到预置的时间周期时,会产生一个 MCU 复位。在递减计数器达到窗口配置寄存器(WWDG->CFR)数值之前,如果 7 位的递减计数器数值(在控制寄存器中) 被刷新, 那么也将产生一个 MCU 复位。这表明递减计数器需要在一个有限的时间窗口中被刷新。
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 位
(1)
WWDG_CR 只有低八位有效,T[6:0]用来存储看门狗的计数器值, 随时更新的,每个窗口看门狗计数周期(4096×2^ WDGTB)减 1。当该计数器的值从 0X40 变 为 0X3F 的时候,将产生看门狗复位。
WDGA 位则是看门狗的激活位,该位由软件置 1,以启动看门狗,并且一定要注意的是该 位一旦设置,就只能在硬件复位后才能清零了。
(2)
该位中的 EWI 是提前唤醒中断,也就是在快要产生复位的前一段时间(T[6:0]=0X40)来 提醒我们,需要进行喂狗了,否则将复位!因此,我们一般用该位来设置中断,当窗口看门狗 的计数器值减到 0X40 的时候,如果该位设置,并开启了中断,则会产生中断,我们可以在中断里面向WWDG_CR 重新写入计数器的值,来达到喂狗的目的。注意这里在进入中断后,必 须在不大于 1 个窗口看门狗计数周期的时间(在 PCLK1 频率为 36M 且 WDGTB 为 0 的条件下, 该时间为 113us)内重新写 WWDG_CR,否则,看门狗将产生复位!
(3)
状态寄存器(WWDG_SR),该寄存器用来记录当前是否有提前唤醒的标志。该寄存器仅有位 0 有效,其他都是保留位。当计数器值达到 40h 时,此位由硬件置 1。 它必须通过软件写 0 来清除。对此位写 1 无效。即使中断未被使能,在计数器的值达到 0X40 的时候,此位也会被置 1。
(1)
1)使能 WWDG 时钟 WWDG 不同于 IWDG,IWDG 有自己独立的 40Khz 时钟,不存在使能问题。而 WWDG 使用的是 PCLK1 的时钟,需要先使能时钟。方法是: RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); // WWDG 时钟使能
2)设置窗口值和分频数 设置窗口值的函数是:
void WWDG_SetWindowValue(uint8_t WindowValue);
这个函数就一个入口参数为窗口值,很容易理解。 设置分频数的函数是: void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
这个函数同样只有一个入口参数就是分频值。
3)开启 WWDG 中断并分组 开启 WWDG 中断的函数为: WWDG_EnableIT(); //开启窗口看门狗中断 接下来是进行中断优先级配置
4)设置计数器初始值并使能看门狗 这一步在库函数里面是通过一个函数实现的:
void WWDG_Enable(uint8_t Counter);
该函数既设置了计数器初始值,同时使能了窗口看门狗。
5)编写中断服务函数 在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当 窗口看门狗计数器值减到 0X3F 的时候,就会引起软复位了。在中断服务函数里面也要将状态 寄存器的 EWIF 位清空。
我 们将通过DS0来指示 STM32 是否被复位了,如果被复位了就会点亮 300ms。DS1 用来指示中 断喂狗,每次中断喂狗翻转一次。
(2)代码
- #include "wdg.h"
- #include "led.h"
-
- 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(); //使能IWDG
- }
- //喂独立看门狗
- void IWDG_Feed(void)
- {
- IWDG_ReloadCounter(); //重载计数值
- }
-
-
- //保存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初始化
- }
-
- void WWDG_IRQHandler(void)
- {
-
- WWDG_SetCounter(WWDG_CNT); //当禁掉此句后,窗口看门狗将产生复位
-
- WWDG_ClearFlag(); //清除提前唤醒中断标志位
-
- LED1=!LED1; //LED状态翻转
- }
-
- #include "led.h"
- #include "delay.h"
- #include "key.h"
- #include "sys.h"
- #include "usart.h"
- #include "wdg.h"
-
- int main(void)
- {
- delay_init(); //延时函数初始化
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
- uart_init(115200); //串口初始化为115200
- LED_Init();
- KEY_Init(); //按键初始化
- LED0=0;
- delay_ms(300);
- WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8
- while(1)
- {
- LED0=1;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。