IWDG和WWDG的主要区别
对比点 | 独立看门狗 | 窗口看门狗 |
---|---|---|
时钟源 | LSI(40KHz或32KHz) | PCLK1或PLCK3 |
复位条件 | 递减计数到0 | 计数值大于W[6:0]值喂狗或减到0x3F |
中断 | 没有中断 | 计数值减到0x40可产生中断 |
递减计数器位数 | 12位(最大计数范围:4096~0) | 7位(最大计数范围:127~63) |
应用场合 | 防止跑飞、死循环、死机 | 检测程序时效,防止软件异常 |
IWDG-独立看门狗
IWDG本质是能产生系统复位信号的计数器。
IWDG的特性:
- 递减的计数器
- 时钟由独立的RC振荡器提供(可在待机和停止模式下运行)
- 看门狗被激活后,当递减计数器计数到0x000时产生复位
IWDG工作原理
在递减计数器减到0之前进行喂狗,也就是把重装载寄存器的值赋给递减计数器CNT,防止复位。
IWDG溢出时间计算
IWDG最短最长超时时间(F1):
预分频系数 | PR[2:0] | 最短时间(ms)/RL[11:0]=0x000 | 最长时间(ms)/RL[11:0]=0xFFF |
---|---|---|---|
/4 | 0 | 0.1 | 409.6 |
/8 | 1 | 0.2 | 819.2 |
/16 | 2 | 0.4 | 1638.4 |
/32 | 3 | 0.8 | 3276.8 |
/64 | 4 | 1.6 | 6553.6 |
/128 | 5 | 3.2 | 13107.2 |
/256 | 6 | 6.4 | 26214.4 |
以256预分频系数为例计算最长超时时间:
4*2^6*4096/40000=26.2144s=26214.4ms
最长就是可以计数4096个然后复位,所以里面乘以4096
IWDG配置步骤
- 取消PR/RLR寄存器写保护,设置IWDG预分频系数和重装载值,启动IWDG,HAL_IWDG_Init()
- 及时喂狗,即写入0xAAAA 到IWDG_KR,HAL_IWDG_Refresh()
其中寄存器的配置步骤:
- 通过在键寄存器 (IWDG_KR) 中写入 0xCCCC 来使能 IWDG。
- 通过在键寄存器 (IWDG_KR) 中写1入 0x5555 来使能寄存器访问。
3. 通过将预分频器寄存器 (IWDG_PR) 编程为 0~7 中的数值来配置预分频器。
4. 对重载寄存器 (IWDG_RLR) 进行写操作。
5. 等待寄存器更新 (IWDG_SR = 0x0000 0000)。
6. 刷新计数器值为 IWDG_RLR 的值 (IWDG_KR = 0xAAAA)。
代码实现:
IWDG_HandleTypeDef g_iwdg_handle; /* 独立看门狗句柄 */
/**
* @brief 初始化独立看门狗
* @param prer: IWDG_PRESCALER_4~IWDG_PRESCALER_256,对应4~256分频
* @arg 分频因子 = 4 * 2^prer. 但最大值只能是256!
* @param rlr: 自动重装载值,0~0XFFF.
* @note 时间计算(大概):Tout=((4 * 2^prer) * rlr) / 40 (ms).
* @retval 无
*/
void iwdg_init(uint8_t prer, uint16_t rlr)
{
g_iwdg_handle.Instance = IWDG;
g_iwdg_handle.Init.Prescaler = prer; /* 设置IWDG分频系数 */
g_iwdg_handle.Init.Reload = rlr; /* 重装载值 */
HAL_IWDG_Init(&g_iwdg_handle); /* 初始化IWDG并启动 */
}
HAL_IWDG_Init()流程:
/* 喂狗函数 */
void iwdg_feed(void)
{
HAL_IWDG_Refresh(&g_iwdg_handle);
}
HAL_IWDG_Refresh()流程:
WWDG-窗口看门狗
WWDG本质是能产生系统复位信号和提前唤醒中断的计数器。
WWDG的特性:
- 递减的计数器
- 当递减计数器值从 0x40减到0x3F时复位(即T6位跳变到0)
- 计数器的值大于W[6:0]值时喂狗会复位
- 提前唤醒中断 (EWI):当递减计数器等于 0x40 时可产生
WWDG工作原理
从最大计数值到窗口上限制值之间喂狗会复位,到了窗口下限值也会复位,所以要在窗口期喂狗防止复位,最大计数值T[6:0]和窗口上限值W[6:0]可自己设置。
WWDG框图
- 这里为什么是6位递减计数器CNT: T6是用来判断是否要复位的。上面说到计数到0x3f(63)就自动复位,就是这。一开始设置计数值为1111111(127)递减到64时变成1000000,可产生中断,到63变成0111111,复位,T6正好变成0,所以用着一位来判断是否复位。
- 递减复位流程:如果递减到63,则T6位为0,a处就为0,取反后是1,前面是或门,有一个1就输出1,所以b处是1,并且激活位置c处为1,与门输出1,产生复位。
- 非窗口期喂狗产生复位流程:d处是判断比较器,判断T6: 0是否大于W6: 0,也就是判断是否在非窗口期内,如果是,则比较器输出1.说明此时是非窗口期,如果此时再进行喂狗(写WWDG CR),前面的与门就会输出1,前面的或门也直接输出1所以b处是1,c处是1,产生复位。
WWDG超时时间计算
以1分频也就是WDGTB为0计算最小最大超时时间:
最小:4096*2^0*1/36000000=0.000113777s=113us
最大:4096*2^0*64/36000000=0.007281777=7.28ms
最大计数值是127,递减到63就复位,所以最多计数64个,最少计数1个,以此来计算最小最大超时时间。
WWDG配置步骤
代码实现:
- 工作参数初始化
WWDG_HandleTypeDef g_wwdg_handle; /* WWDG句柄 */
/**
* @brief 初始化窗口看门狗
* @param tr: T[6:0],计数器值
* @param tw: W[6:0],窗口值
* @note fprer:分频系数(WDGTB),范围:WWDG_PRESCALER_1~WWDG_PRESCALER_8,表示2^WDGTB分频
* Fwwdg=PCLK1/(4096*2^fprer). 一般PCLK1=36Mhz
最大-最小超时时间参考 RM0008或者《STM32F10xxx参考手册》P321
* @retval 无
*/
void wwdg_init(uint8_t tr, uint8_t wr, uint32_t fprer)
{
g_wwdg_handle.Instance = WWDG;
g_wwdg_handle.Init.Prescaler = fprer; /* 设置分频系数 */
g_wwdg_handle.Init.Window = wr; /* 设置窗口值 */
g_wwdg_handle.Init.Counter = tr; /* 设置计数器值 */
g_wwdg_handle.Init.EWIMode = WWDG_EWI_ENABLE; /* 使能窗口看门狗提前唤醒中断 */
HAL_WWDG_Init(&g_wwdg_handle); /* 初始化WWDG */
}
- WWDG-MSP回调
void HAL_WWDG_MspInit(WWDG_HandleTypeDef *hwwdg)
{
__HAL_RCC_WWDG_CLK_ENABLE(); /* 使能窗口看门狗时钟 */
HAL_NVIC_SetPriority(WWDG_IRQn, 2, 3); /* 抢占优先级2,子优先级为3 */
HAL_NVIC_EnableIRQ(WWDG_IRQn); /* 使能窗口看门狗中断 */
}
- 窗口看门狗中断服务程序
递减计数到0x40时可产生中断,调用公共中断处理函数,HAL库会自动调用中断服务回调函数
void WWDG_IRQHandler(void)
{
HAL_WWDG_IRQHandler(&g_wwdg_handle); /* 调用WWDG共用中断处理函数 */
}
- 窗口看门狗喂狗提醒中断服务回调函数
中断时进行喂狗,如果窗口期没有进行喂狗,在中断内可设置喂狗,防止复位。
void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
HAL_WWDG_Refresh(&g_wwdg_handle); /* 更新窗口看门狗值 */
}