使用STM32CubeMX配置工程+MDKARM编写代码实现看门狗功能
说到看门狗,我首先想到的是这个
但是实际上我们说的不是这个看门狗
一、看门狗简介
看门狗是一个定时器电路,一般有一个输入和一个输出,输入叫做喂狗,输出一般连到复位端。 看门狗的功能是定期的查看芯片内部的情况,一旦发生错误就向芯片发出重启信号。看门狗命令在程序的中断中拥有最高的优先级。
在某些情况下,芯片由于受到外界环境的干扰(如电磁等)会导致寄存器和内存的数据混乱,程序指针错误,取指错误等情况。导致程序不正常运行,芯片无法继续正常工作。俗称“程序跑飞”。使用上看门狗的功能就可以自动复位芯片程序,使芯片继续重头工作。
看门狗是一个定时器电路。MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,给 WDT清零,如果超过规定的时间不喂狗(一般在程序跑飞时),WDT定时超过,就会给出一个复位信号到MCU,使MCU复位。防止MCU死机. 看门狗的作用就是防止程序跑飞。
STM32F4内部自带了 2 个看门狗:独立看门狗(IWDG)和窗口看门狗(WWDG)。
STM32F4 的独立看门狗由内部专门的 32Khz 低速时钟(LSI)驱动,即使主时钟发生故障它也仍有效。独立看门狗适合应用于需要看门狗作为一个在主程序之外能够完全独立工作,并且对时间精度要求低的场合。独立看门狗的时钟是一个内部 RC时钟,所以并不是准确的 32Khz,而是在 15~47Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 32Khz 的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。
窗口看门狗由从APB1时钟分频后得到时钟驱动。通过可配置的时间窗口来检测应用程序非正常的过迟或过早操作。窗口看门狗最适合那些要求看门狗在精确计时窗口起作用的程序。
二、独立看门狗
1.独立看门狗(IWDG)寄存器
1)键寄存器(IWDG_KR)
① 0xCCCC
启动操作:在关键字寄存器(IWDG_KR)中写入 0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值 0xFFF 递减计数。当计数器计数到末尾 0x000 时,会产生一个复位信号(IWDG_RESET)。
② 0xAAAA
喂狗操作:无论何时,只要关键字寄存器 IWDG_KR 中被写入 0xAAAA, IWDG_RLR 中的值就会被重新加载到计数器中从而避免产生看门狗复位 。
② 0x5555
去除写保护:要修改IWDG_PR 和 IWDG_RLR 这两个寄存器的值必须先向IWDG_KR 寄存器中写入 0x5555。
2)预分频寄存器(IWDG_PR)
预分频寄存器用来设置看门狗时钟的分频系数。只使用了其中最后三位。0-8不同的值对应不同的分频系数。最低4分频、最高256分频。
3)重装载寄存器(IWDG_RLR)
重装载寄存器用来保存重装载到计数器中的值。只使用了低12位。用来设置重装载值,也就是定时的时间,计数器开始递减的初始值。每次喂狗后,看门狗计数器就会从这个值开始递减计数。
要启动看门狗首先是对预分频寄存器和重装载寄存器取消写保护。在配置预分频系数和重装载系数后。启动看门狗。在程序运行时要不断进行喂狗。
2、独立看门狗(IWDG)STM32CubeMX配置
说了那么多,无非就是先配置预分频寄存器和重装载寄存器。这个在STM32CubeMX上只需要配置两个值。
计算独立看门狗IWDG的溢出时间有一个公式:
超时时间 Tout (s) = (4 * 2^prv) / LSI * rlv
其中:prv是预分频器寄存器的值,rlv是重装载寄存器的值。由时钟树可以知道LSI的值是32KHz。
需要注意的是这里将IWDG counter clock prescaler设置为64并不是64分频的意思。而是将 (4 * 2^prv) 这里的整个值设置为64,实际上也就是最小的4分频。如果直接操作寄存器的话就是往IWDG_PR寄存器里面写000
所以我上面设置的时间是Tout=64/32*500=1000ms。
3、独立看门狗(IWDG)代码实现
选择合适的时间喂狗就可以了。
HAL_IWDG_Refresh(&hiwdg);
举个例子:开机后,先输出初始化信息串口,然后LED灯闪一下关闭。IWDG的时间是1S。在一秒内按下按键喂狗以后LED则不会再亮起。如果没有及时喂狗,会造成单片机复位重启后LED再一次闪烁。
//喂独立看门狗
void IWDG_Feed(void)
{
HAL_IWDG_Refresh(&hiwdg); //喂狗
}
void IWDG_Fun(void)
{
if(KEY_Scan(0)==WKUP_PRES)//按上键就喂狗
{
IWDG_Feed();
}
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_IWDG_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1,(uint8_t*)usart1_ReadBuffer,USART1_LENGTH);
printf("STM32F407 Init!\r\n");
Led0_Light_N(1,100);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
KeyEvent();
IWDG_Fun();
}
/* USER CODE END 3 */
}
三、窗口看门狗
1、窗口看门狗(WWDG)原理
窗口看门狗(WWDG)通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序
背离正常的运行序列而产生的软件故障。
写入 WWDG_CR 寄存器时,始终将 1 写入 T6 位,以避免生成立即复位。
同时只要T6位是1,则可以保证CNT的值大于等于0x40
当T6位是1,T[5:0]递减,当T[5:0]递减至0后再递减,就需要向更高位T6借位,这时候T6位变为0,触发中断进行复位。
所以配置的时候只需要设置T[5:0],用T[5:0]的值就可以计算出窗口看门狗的定时时间。
窗口看门狗公式:
Twwdg=(4096×2^WDGTB×(T[5:0]+1)) /Fpclk1;
其中:
Twwdg:WWDG 超时时间(单位为 ms)
Fpclk1:APB1 的时钟频率(单位为 Khz)
WDGTB: 预分频寄存器的值(2^WWDG 等于预分频系数)
T[5:0]:窗口看门狗的计数器低 6 位
查看时钟树,可以知道APB1的时钟频率是42Mhz=42000Khz
根据公式可以计算出窗口定时的上下限时间
2、窗口看门狗(WWDG)寄存器
控制寄存器 (WWDG_CR)
配置寄存器(WWDG_CFR)
状态寄存器(WWDG_SR)
用来记录当前是否有提前唤醒的标志。
仅有位 0 有效,当计数器值达到0x40 时,此位由硬件置 1。
必须通过软件写 0 来清除。对此位写 1 无效。
即使中断未被使能,在计数器的值达到 0X40的时候,此位也会被置 1。
此处这个提前唤醒中断(EWI)是用来使能窗口看门狗中断
如果系统出现问题,喂狗没有生效,那么在CNT减到0x3f之前一个值 的时候,先进入中断,可以在中断中喂狗,之后才会复位。
3、窗口看门狗(WWDG)STM32CubeMX配置
打个比方,我想要定时一个40ms左右的窗口定时器(20ms后可以喂狗),采用8的预分频系数,由上述公式反推。
T[5:0]=(40*4200)/(4096*8)-1 = 50.2695 ≈ 50
T[6:0]=0011 0010 B + 0100 0000 B = 114
回头计算定时时间
T = 4096*8*51/42000 ≈ 39.7897ms
点击GENERATE CODE 生成代码
4、窗口看门狗(WWDG)代码实现
编写窗口看门狗回调函数
int i=0;
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
i++;
if(i>100)//每隔4秒左右LED翻转
{
i=0;
Led0_Toggle;
}
HAL_WWDG_Refresh(hwwdg); //喂狗
}
下载程序上电运行就可以了。
四、HAL库常用函数
独立看门狗
//喂狗函数
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
窗口看门狗
//喂狗函数
HAL_StatusTypeDef HAL_WWDG_Refresh(WWDG_HandleTypeDef *hwwdg)
//回调函数
__weak void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
五、独立看门狗与窗口看门狗的差异
独立看门狗
由LSI驱动,独立时钟即使主时钟发生故障它仍有效,可以用于监测硬件故障。
独立程序之外运行,任何情况下只要不喂狗就会复位。
可用于程序跑飞、死循环、以及各种硬件故障。
无法触发中断
窗口看门狗
由APB1时钟分频后得到的时钟驱动。与系统时钟相同,系统时钟故障则该看门狗失效,主要用于监测软件故障。
用于软件逻辑错误,或不按预期效果执行。也可用于死循环等情况。
时间精度要求高,喂狗太慢或者太快都会复位
可以触发窗口看门狗中断,可以在中断中喂狗,或者保存数据到外存等。
六、参考资料
《STM32F4xx中文参考手册》
《STM32F4开发指南-HAL库版本_V1.2》