与独立看门狗不同的是,独立看门狗只需要在计时到0之前喂狗。而窗口看门狗需要在设定好的区间内进行喂狗,否则进行reset。
递减计数器不断的往下递减计数,当减到一个固定值 0X40
时还不喂狗的话,产生复位,这个值叫窗口的下限,是固定的值,不能改变。
是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。
窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗。
PCLK1,PCLK1 最大是 36M,由 RCC 时钟控制器开启。
1.计数器时钟由 CK计时器时钟
经过预分频器分频得到。
2.CK 计时器时钟=PCLK1/4096,除以 4096是手册规定的,没有为什么。
3.分频系数由配置寄存器 CFR 的位 8:7 WDGTB[1:0]配置,可以是[0,1,2,3]。
所以计数器的时钟 CNT_CK=PCLK1/4096/(2^WDGTB),这就可以算出计数器减一个数的时间 T= 1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB)。。
1.窗口看门狗的计数器是一个递减计数器,共有 7 位,其值存在控制寄存器 CR 的位 6:0,即 T[6:0]。
2.但是由于窗口看门狗需要在窗口内喂狗,所以计数器的值只能是:0X40~0X7F 之间。
3.当递减计数器递减到 0X40的时候,还不会马上产生复位,如果使能了提前唤醒中断:CFR位 9 EWI 置1,则产生提前唤醒中断
。
中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等。
详见参考手册
看门狗配置
/* WWDG 配置函数
* tr :递减计时器的值, 取值范围为:0x7f~0x40
* wr :窗口值,取值范围为:0x7f~0x40
* prv:预分频器值,取值可以是
* @arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1/4096)/1
* @arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1/4096)/2
* @arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1/4096)/4
* @arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1/4096)/8
*/
void WWDG_Config(uint8_t tr, uint8_t wr, uint32_t prv)
{
// 开启 WWDG 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
// 设置递减计数器的值
WWDG_SetCounter( tr );
// 设置预分频器的值
WWDG_SetPrescaler( prv );
// 设置上窗口值
WWDG_SetWindowValue( wr );
// 设置计数器的值,使能 WWDG
WWDG_Enable(WWDG_CNT);
// 清除提前唤醒中断标志位
WWDG_ClearFlag();
// 配置 WWDG 中断优先级
WWDG_NVIC_Config();
// 开 WWDG 中断
WWDG_EnableIT();
}
中断NVIC 配置
// WWDG 中断优先级初始化
static void WWDG_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
提前唤醒中断复位程序
这个中断函数的名称就是"提前唤醒中断"
// WWDG 中断复服务程序,如果发生了此中断,表示程序已经出现了故障,
// 这是一个死前中断。在此中断服务程序中应该干最重要的事,
// 比如保存重要的数据等,这个时间具体有多长,要
// 由 WDGTB 的值决定:
// WDGTB:0 113us
// WDGTB:1 227us
// WDGTB:2 455us
// WDGTB:3 910us
void WWDG_IRQHandler(void)
{
// 清除中断标志位
WWDG_ClearFlag();
//真正使用的时候,这里应该是做最重要的事情
}
喂狗函数
// 喂狗
void WWDG_Feed(void)
{
// 喂狗,刷新递减计数器的值,设置成最大 WDG_CNT=0X7F
WWDG_SetCounter( WWDG_CNT );
}
int main(void)
{
uint8_t wwdg_tr, wwdg_wr;
SOFT_Delay(0X00FFFFFF);
// 初始化 WWDG
// 窗口值我们在初始化的时候设置成 0X5F,这个值不会改变
WWDG_Config(0X7F, 0X5F, WWDG_Prescaler_8);
wwdg_wr = WWDG->CFR & 0X7F;
while (1) {
//-----------------------------------------------------
// 这部分应该写需要被 WWDG 监控的程序,这段程序运行的时间
// 决定了窗口值应该设置成多大。
//-----------------------------------------------------
// 计时器值,初始化成最大 0X7F,当开启 WWDG 时候,这个值会不断减小
// 当计数器的值大于窗口值时喂狗的话,会复位,当计数器减少到 0X40
// 还没有喂狗的话就非常非常危险了,计数器再减一次到了 0X3F 时就复位
// 所以要当计数器的值在窗口值和 0X40 之间的时候喂狗,其中 0X40 是固定的。
wwdg_tr = WWDG->CR & 0X7F;
if ( wwdg_tr < wwdg_wr ) {
// 喂狗,重新设置计数器的值为最大 0X7F
WWDG_Feed();
}
}
}