接上一篇分享【STM32WB09KE测评】Demo程序编译烧写 - STM32/STM8单片机论坛 - ST MCU意法半导体官方技术支持论坛 - 21ic电子技术开**坛,这次分享看门狗功能测试。
在例程文件中有看门狗例程源码,所以分享一下该例程代码框架。看门狗例程用的是STM32WB09KE\STM32Cube_FW_WB0_V1.0.0\Projects\NUCLEO-WB09KE\Examples\IWDG\IWDG_Reset文件下的例程。
在系统时钟初始化时也会打开LEI的时钟,因为看门狗的时钟源是LSI,对应代码如下 /** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
在时钟树中的位置如下图
第二步是先判断设备是正常启动还是看门狗自启动,判断代码如下 /*##-1- Check if the system has resumed from IWDG reset ####################*/
if ((RAM_VR.ResetReason & RCC_FLAG_WDGRST) == RCC_FLAG_WDGRST)
{
/* IWDGRST flag set: Turn LD1 on and set IwdgStatus */
IwdgStatus = 1;
BSP_LED_On(LD1);
/* Insert 4s delay */
HAL_Delay(4000);
/* Notification done: Turn LD1 off */
BSP_LED_Off(LD1);
}
主要是通过检测特定的寄存器的值进行判断,如果是看门狗自启动则打开LED1指示灯,亮4S后会关闭。
第三步是清除看门狗标志,实现代码如下
/* Clear reset flags in any cases */
__HAL_RCC_CLEAR_RESET_FLAGS();
IwdgStatus = 0;
第四步是获取LSI的频率,因为LSI的时钟源是内部时钟,容易受温度等的影响。测量LSI的频率是用TIM17定时器测量LSI一个时钟周期的时间,通过仿真测试发现时钟确实有些偏差。原本的重载值应为1000,但是仿真的结果比1000大一点,仿真结果如下
对应的代码如下
/*##-2- Get the LSI frequency: TIM17 is used to measure the LSI frequency ###*/
GetLSIFrequency();
接下来是初始化看门狗了,主要是配置看门狗的预分频器的值和重载值等。这里预分频器的值配置的是32,主要是时钟源是32KHz,配置成32,正好一个周期是1ms。重载值是根据LSI的实际频率进行配置,配置时间是1S,即两次喂狗时间间隔不得大于或等于1S。重载值的计算方式如下
#define IWDG_RELOAD (uwLsiFreq / 32)
其中uwLsiFreq是LSI的真实始终频率。
除此之外还配置了GPIO中断,中断源是B1按键。中断执行程序是向未被映射的内存区域写数据,这样就会触发安全机制,使程序进入死循环,而不能按时喂狗,最终触发看门狗复位。中断执行的程序如下
/* Failure is generated by user, turn LD1 off */
BSP_LED_Off(LD1);
/* As the following address is invalid (not mapped), a Hardfault exception
will be generated with an infinite loop and when the IWDG counter falls to 0
the IWDG reset occurs */
*(__IO uint32_t *) 0x00040001 = 0xFF;
在main的while(1)中的代码如下
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* Toggle LD2 */
BSP_LED_Toggle(LD2);
/* Insert 990 ms delay */
HAL_Delay(990);
/* Refresh IWDG: reload counter */
if(HAL_IWDG_Refresh(&hiwdg) != HAL_OK)
{
/* Refresh Error */
Error_Handler();
}
若没有触发中断的话,程序会一直执行while(1)中的代码,即每990ms翻转一下LED2引脚的输出状态,让其不停地闪烁;也会进行喂狗。
整体实现的效果是绿灯一直在闪烁,若按下B1按键,则会触发看门狗,即蓝灯亮4秒后熄灭,绿灯会继续闪烁。效果如下。
|