STM32F4X 窗口看门狗 WWDG
上一节简单讲了STM32F4X中的独立看门狗的使用,除了独立看门狗之外,STM32F4X还有一个叫窗口看门狗的外设。
STM32F4X窗口看门狗使用
独立看门狗与窗口看门狗区别
独立看门狗 | 窗口看门狗 | |
---|---|---|
时钟源 | LSI低速时钟 | APB时钟 |
喂狗条件 | 在复位前的任意时刻喂狗 | 需要在窗口值喂狗 |
独立看门狗与窗口看门狗的的区别就在与时钟源和复位条件的不同。
窗口看门狗复位条件
窗口看门狗有两种复位条件
- 当CR寄存器里面的bit6~bit0减到0x3F时,产生一个复位信号
- 当在窗口值之外重装载递减计数器时,产生复位信号。
窗口看门狗时钟
窗口看门狗的时钟源是系统的APB1时钟,因此窗口看门狗的的计数时间比独立看门狗的更加准确。在窗口看门狗的CFR寄存器中的bit7~bit8可以对APB1时钟源进行分频
窗口看门狗的分频器支持1/2/4/8分频。
窗口看门狗时钟计数频率
窗口看门狗的计数频率计算跟普通定时器的计算是一样的,假设APB1时钟为42MHZ,分频器设置为0,由于窗口看门狗的计数器为7位,理论上可以计128个数,但是由于计数器减到0x3F时就复位,所以计数器最多只能计64个数,假设计数器计数为64。窗口看门狗的溢出时间如下
TCLK = 42MHZ
PSC = 0
COUNT = 64
Tout = (1 / (TCLK / (4096 * 2 ^ PSC) ) ) * COUNT
Tout得到的就是6.24ms
窗口看门狗的窗口值
窗口看门狗的窗口值是在CFR寄存器的bit0~bit6设置。
最大的窗口值为0x7F,窗口值的作用是限制喂狗的时间,用户不能再窗口值之外进行喂狗,否则系统会复位。假设窗口值设置为0x5F,那么窗口值的上限为0x5F,窗口值下限为0x3F,在0x3F~0x5F这个时间段外不能进行喂狗操作,否则系统会复位。
窗口看门狗喂狗操作
用户可以将CFR寄存器的bit9设置为1,使能窗口看门狗中断,当计数器计数到0x40的时候会产生一个中断,然后在中断里面进行喂狗操作。
窗口看门狗例程
#include "iwdt.h"
static uint8_t count = 0x7F;
void bsp_wwdg_init(uint32_t psc,uint8_t tr,uint8_t wr)
{
NVIC_InitTypeDef NVIC_InitStruct;
count = count & tr;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); // 使能窗口看门狗时钟
WWDG_SetPrescaler(psc); // 设置预分配系数
WWDG_SetWindowValue(wr); // 设置窗口值
WWDG_Enable(count); // 使能窗口看门狗
NVIC_InitStruct.NVIC_IRQChannel = WWDG_IRQn; // WWDG 中断编号
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级为2
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; // 响应优先级为2
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; // 使能中断
NVIC_Init(&NVIC_InitStruct); // 初始化中断
WWDG_ClearFlag();//清除提前唤醒中断标志位
WWDG_EnableIT();// 使能中断
}
void WWDG_IRQHandler(void)
{
static int cnt = 0;
if(cnt++ <= 100) // 喂狗100次后停止喂狗
{
WWDG_SetCounter(count); //重设窗口看门狗值
WWDG_ClearFlag();//清除提前唤醒中断标志位
GPIO_ToggleBits(LED_GREEN_GPIO,LED_GREEN_GPIO_PIN); // 翻转绿色LED
}
}
int main(void)
{
NVIC_PriorityGroupConfig(2);
system_tick_init();
bsp_usart_init(115200);
bsp_led_init(); // 初始化LED
GPIO_ResetBits(LED_RED_GPIO,LED_RED_GPIO_PIN); // 打开红色LED
delay_ms(2000); // 延时2s
// 使能窗口看门狗
// 分频器为8
// 计数器值为0x7F
// 窗口值为0x5F
bsp_wwdg_init(WWDG_Prescaler_8,0x7F,0x5F);
while(1){
GPIO_SetBits(LED_RED_GPIO,LED_RED_GPIO_PIN); // 关闭红色LED
}
}