一、独立看门狗是什么😖
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界的电磁波干扰,造成程序的跑飞,从而陷入到死循环,程序的正常运行被打断,由单片机控制的系统无法继续正常工作,会造成整个系统陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”。
STM32板载了两种嵌入式看门狗外设,具有安全性高、定时精准及使用灵活的优点。看门狗分为独立看门狗和窗户看门狗。均可用于检测并解决由于软件错误导致的故障。本章我们着重讲解独立看门狗。
二、独立看门狗 IWDG简介
看门狗的作用就是在一定的时间内 (这段时间通过定时器去实现) ,如果超过这段时间还没有被喂养信号(表示MCU已经挂了),便启动处理器的自动复位重启(发送复位信号)。
- 独立看门狗由其专用的低速内部时钟LSI驱动,通过对时钟的学习,我们知道LSI低速内部时钟是专门用来驱动看门狗的,独立看门狗由内部专门的32Khz低速时钟驱动,即使主时钟发生故障,它也仍然有效。独立看门狗的时钟是一个内部RC时钟,所以并不是准确的32Khz,而是一个在15~47Khz之间的可变化的时钟。
- 独立看门狗最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。
- 硬件看门狗:如果通过器件选项位使能 “硬件看门狗” 功能,上电时将自动使能看门狗;如果在计数器计数结束前,若软件没有向关键字寄存器写入相应的值,则系统会产生复位。
三、独立看门狗的主要特性
🍋1. 自由运行的递减计数器 用于给定一段确定的时间,如果程序运行超过这段时间,表明MCU已经挂了
🍋2. 时钟由独立RC振荡器提供(可在待机和停止模式下运行) 低速内部时钟LSI,主时钟发生故障时,LSI 仍然保持工作状态
🍋3. 当递减计数器达到0x000时产生复位(前提是看门狗已激活) 递减定时器递减到0时,复位为初始值,循环工作
四、独立看门狗功能
4.1 独立看门狗功能框图
4.2IWDG寄存器
🍉4.2.1 关键字寄存器 IWDG_KR
关键字寄存器 IWDG_KR(Key register)32位寄存器
位31:16 保留,必须保持复位值
位15:0 KEY[15:0]:键值,只写位,读为0000h;
- 必须每隔一段时间便通过软件对这些位写入键值AAAAh,否则当计数器计数到0时,看门狗会产生复位。
- 写入键值5555h可使能对IWDG_PR和IWDG_RLR寄存器的访问。
- 写入键值CCCCh可启动看门狗 该寄存器的15:0位再一次强调了上述框图中的情况
- 在关键字寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。
- 无论何时,只要关键字寄存器IWDG_KR中被写入0xAAAA, IWDG_RLR中的值就会被重新加载到计数器中从而避免产生看门狗复位 。
🍊4.2.2 预分频器寄存器 IWDG_PR
预分频器寄存器 IWDG_PR(Prescaler register) 32位寄存器
位31:3 保留,必须保持复位值
位2:0 PR[2:0]:预分频器
这些值受写访问保护。通过软件设置这些位来选择计数器时钟的预分频因子。若要更改预分频的分频系数,IWDG_SR的PVU位必须为0;
000:4分频 001:8分频 010:16分频 011:32分频 100:64分频 101:128分频 110:256分频 111:256分频
注意:读取该寄存器会返回VDD电压域的预分频值。如果正在对该寄存器执行写操作,则读取的值可能不是最新的/有效的。因此,只有在IWDG_SR寄存器中的PVU位为0时,从寄存器中读取的值才有效。
🔮4.2.3 重载寄存器 IWDG_RLR
重载寄存器 IWDG_RLR(Reload register)32位寄存器
位32:12 保留,必须保持复位值
位11:0 RL[11:0]:看门狗计数器重载值
这些值受写访问保护,每次对IWDG_KR寄存器写入值AAAAh时,这个值就会重装载到看门狗计数器中,之后便会从重装载以后的值开始递减计数。若要更改重装载值,IWDG_SR中的RVU位必须为0;该寄存器用来保存重装载到计数器中的值。
🔮4.2.4 状态寄存器 IWDG_SR
状态寄存器 IWDG_SR(Status register)32位寄存器
位31:2 保留,必须保持复位值
位1 RVU:看门狗计数器重装载更新
- 可通过硬件将该位置1以指示重装载值正在更新。当在VDD电压域下完成重装载更新操作后,会通过硬件将该位复位。
- 重载值只有在RVU位为0时才可更新。
- 位0 PVU:看门狗预分频器值更新
- 可通过硬件将该位置1以指示预分频器值正在更新。当在VDD电压域下完成预分频器值更新操作后,会通过硬件将该位复位。
- 重载值只有在PVU位为0时才可更新。
五、库函数配置独立看门狗
库函数配置独立看门狗的步骤:
🍜1. 取消寄存器写保护(向IWDG_KR写入0x5555)
取消写保护的实质其实是取消IWDG_PR和IWDG_RLR的写保护;首先取消写保护的目的是为了后续可以设置IWDG_PR和IWDG_RLR寄存器的值。
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
🍜2. 设置独立看门狗的预分频系数和重装载值
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//设置IWDG的预分频值
void IWDG_SetReload(uint16_t Reload); //设置IWDG重装载值
通过对以上两个寄存器设置可以计算出看门狗的喂狗时间(也就是看门狗溢出时间):
Tout=((4*2^prer)*rlr)/32
Tout:看门狗溢出时间 prer:预分频值 0~7 rlr:重装载值
单位ms 4*2^prer=称为分频因子最大值256 分母=看门狗时钟(并不固定)看使用的芯片
具体来说就是:比如通过计算得到看门狗的溢出时间是1000ms,也就是1s,只要你在1s之内,有一次写入0xAAAA到IWDG_KR,就不会导致看门狗复位。
🍜3. 重载计数器喂狗(向IWDG_KR写入0xAAAA)
IWDG_ReloadCounter(); //重载计数器的值到IWDG计数器中,避免其复位 这一步骤就是看门狗喂狗
🍜4. 启动看门狗(向IWDG_KR写入0xCCCC)
IWDG_Enable(); //使能IWDG
注意:IWDG一旦启动,就不能再关闭,想要关闭,只能重启;一般不使用IWDG,就不要启动看门狗;启动看门狗以后必须间隔一段时间去喂狗,否则就会导致程序复位。
六、实例程序
这里使用的是F4的芯片,所以看门狗的时钟为32---所以计算公式为:
分频因子=4*2^prer.但最大值只能是256!
时间计算(大概):Tout=((4*2^prer)*rlr)/32 (ms).
IWDG.C
#include "iwdg.h"
/*******************************************
*@函数名 : IWDG_Init
*@函数功能 : 初始化独立看门狗
*@函数参数 : prer: 分频数:0~7(只有低3位有效!)
** rlr: 重装载寄存器值:低11位有效.
*@Data 2023-09-20
*@函数返回值: None
*@函数描述 :分频因子=4*2^prer.但最大值只能是256!
时间计算(大概):Tout=((4*2^prer)*rlr)/32 (ms).
*********************************************/
void IWDG_Init(u8 prer,u16 rlr)
{
//启用或禁用对IWDG_PR和IWDG_RLR寄存器的写访问
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
//设置IWDG预调值。
IWDG_SetPrescaler(prer);
//重装载的值
IWDG_SetReload(rlr);//最大4096
//用重新加载寄存器中定义的值重新加载IWDG计数器
//*(禁止对IWDG_PR和IWDG_RLR寄存器的写访问)。
IWDG_ReloadCounter();
//使能
IWDG_Enable();
}
//喂独立看门狗
void IWDG_Feed(void)
{
IWDG_ReloadCounter();//reload
}
主函数调用这个,就启动了看门狗,要定期喂狗,不然程序就会复位
IWDG_Init(6,1000); //分频数为256,重载值为1000,溢出时间为8s--重装载最大为4096
分频系数可以是以下值
@arg IWDG_Prescaler_4: IWDG prescaler set to 4
* @arg IWDG_Prescaler_8: IWDG prescaler set to 8
* @arg IWDG_Prescaler_16: IWDG prescaler set to 16
* @arg IWDG_Prescaler_32: IWDG prescaler set to 32
* @arg IWDG_Prescaler_64: IWDG prescaler set to 64
* @arg IWDG_Prescaler_128: IWDG prescaler set to 128
* @arg IWDG_Prescaler_256: IWDG prescaler set to 256因为宏定义了,所以可以是以下值---同样的效果
#define IWDG_Prescaler_4 ((uint8_t)0x00)
#define IWDG_Prescaler_8 ((uint8_t)0x01)
#define IWDG_Prescaler_16 ((uint8_t)0x02)
#define IWDG_Prescaler_32 ((uint8_t)0x03)
#define IWDG_Prescaler_64 ((uint8_t)0x04)
#define IWDG_Prescaler_128 ((uint8_t)0x05)
#define IWDG_Prescaler_256 ((uint8_t)0x06)