今天刚好遇到使用窗口看门狗的情况,开始设置不是很理解,摸索了几个小时后终于明白了。记录下以备不时之需。
如上图,从手册的截图,首先找到WWDG的时钟来源就是APB1了。其次我们看到下面WWDG复位条件两个:①如果启动了看门狗当看门狗计数器(7bit 最大值127)少于0x40(64)时复位,②如果启动了看门狗,如果看门狗计数器不在设置的window值(也可以认为是大于设置的window值)内喂狗也会进行复位,window值下面说明。
/**
* @brief WWDG Initialization Function
* @param None
* @retval None
*/
static void MX_WWDG_Init(void)
{
/* USER CODE BEGIN WWDG_Init 0 */
/* USER CODE END WWDG_Init 0 */
/* USER CODE BEGIN WWDG_Init 1 */
/* USER CODE END WWDG_Init 1 */
hwwdg.Instance = WWDG;
hwwdg.Init.Prescaler = WWDG_PRESCALER_8;//分频系数
hwwdg.Init.Window = 74; //window 值
hwwdg.Init.Counter = 74; /*看门狗计数器 74-64 = 10 *8.192 = 80ms*/
hwwdg.Init.EWIMode = WWDG_EWI_DISABLE;
if (HAL_WWDG_Init(&hwwdg) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN WWDG_Init 2 */
/* USER CODE END WWDG_Init 2 */
}
先看下上面初始化窗口看门狗的代码,这个是STM32cube软件生成初始化窗口看门狗的代码。这里我们关心的最主要的有三个参数,①hwwdg.Init.Prescaler,这个是分频参数,那么这个分频参数是分哪个的呢?请看下图,分的就是PCLK/4096后的值,椭圆圈起来的部分就是分频值(只能写0,1,2,3其中一个),右上角的WDGTB就是这个值,上面WWDG_PRESCALER_8宏的值其实是3,这样通过2^3这样就是8分频了。这个时钟分频之后的脉冲就是用来让看门狗计数器进行递减的脉冲了,一个脉冲计数器减一。②hwwdg.Init.Window,这个就是第一段里的window值也就是说这个值设定之后,同时启动了看门狗,看门狗计数器就开始根据分频后的脉冲进行递减了,如果在这个计数器大于这个window值的时候进行了喂狗操作则也会复位。窗口值就是此作用。③hwwdg.Init.Counter,这个就是计数器的重载值也就是喂狗之后把这个值加载到递减计数器中去。
上面都是一些说明,下面我们来看一个例子,比如说我们主循环中只有一个函数正常执行时间应该>20ms并且会<40ms其他的运行时间都说明系统出错了则需要复位系统。为了监测这个函数我们开启了窗口看门狗来进行守护。
假设PCLK时钟为32Mhz,分频系数为8分频也就是hwwdg.Init.Prescaler=3。这样的话经过上图计算32Mhz / 4096 / 8 ≈ 976.5hz的时钟脉冲给看门狗计数器进行递减。根据T=1/f则得出1/(32Mhz / 4096 / 8)推导->T = 4096*8/32Mhz = 1.024ms。说明了在PCLK32Mhz 分频系数为8的时候看门狗计数器递减一个数需要的时间为1.024ms。如果你觉得这个时间不合适,可以通过修改PCLK,或者更改分频系数来改变。得出这个递减计数器时间之后我们就可以根据需求来设置window值和count值了。根据WWDG的说明我们知道当计数器小于64时系统复位,如果我们给count的值是74那么 74 - 64 = 10就是说计10个数之后就复位了,上面计算的值是1.024ms计一个数那么当count = 74的时候不进行喂狗的话 1.024*10 = 10.24ms后系统会复位。题目要求的复位最大值是40ms则count的计数到64要等于40ms则count值为40 / 1.024 + 64 ≈ 104(注意count值不能大于127,如果不能满足需求则需要重新配置PCLK以及分频系数)也就是如果函数执行时间超过了40ms则系统会进行复位,看看另外一个条件运行时间也必须大于20ms也就是说小于20ms进行喂狗也是错误的也应该进行复位,所以可以得出window值为84。因为104-84=20大概就是20ms。所以综上当PCLK为32Mhz的时候可以如下初始化完成题目要求。
hwwdg.Instance = WWDG;
hwwdg.Init.Prescaler = WWDG_PRESCALER_8; /*8分频*/
hwwdg.Init.Window = 84;//窗口值84
hwwdg.Init.Counter = 104;//重载值 104
系统运行:
while (1)
{
SystemRun();
HAL_WWDG_Refresh(&hwwdg);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
如上则可以完成题目需求。
当然如果系统只需要复位的上限时间比超过40ms不喂狗就复位没有下限时间,则只需要把window值也设置为count值就没有下限时间了。直接两个值都是104就可以达到目的了。
上面针对的是HAL库的操作,实际上HAL的库 也是操作寄存器,如果需要寄存器操作也可以通过下面寄存器说明进行操作。
/* Set WWDG Counter */
WRITE_REG(hwwdg->Instance->CR, (WWDG_CR_WDGA | hwwdg->Init.Counter));
/* Set WWDG Prescaler and Window */
WRITE_REG(hwwdg->Instance->CFR, (hwwdg->Init.EWIMode | hwwdg->Init.Prescaler | hwwdg->Init.Window));
HAL函数初始化的时候实际也是操作CR和CFR寄存器如上面的代码。所以寄存器操作可以直接根据手册操作即可,值直接赋值就行了。