stm32f10x_iwdg
IWDG(Independent Watchdog)外设是STM32F10x系列微控制器中的独立看门狗模块,提供系统监控和自动复位功能。该外设具有独立的时钟源,不依赖于系统时钟,能够在系统出现故障时自动复位系统,提高系统可靠性。
数据类型定义
IWDG写访问定义
#define IWDG_WriteAccess_Enable ((uint16_t)0x5555) /* 使能写访问 */
#define IWDG_WriteAccess_Disable ((uint16_t)0x0000) /* 禁用写访问 */说明:
IWDG_WriteAccess_Enable:使能对IWDG寄存器的写访问,允许配置IWDGIWDG_WriteAccess_Disable:禁用对IWDG寄存器的写访问,保护IWDG配置
IWDG预分频器定义
#define IWDG_Prescaler_4 ((uint8_t)0x00) /* 预分频器4 */
#define IWDG_Prescaler_8 ((uint8_t)0x01) /* 预分频器8 */
#define IWDG_Prescaler_16 ((uint8_t)0x02) /* 预分频器16 */
#define IWDG_Prescaler_32 ((uint8_t)0x03) /* 预分频器32 */
#define IWDG_Prescaler_64 ((uint8_t)0x04) /* 预分频器64 */
#define IWDG_Prescaler_128 ((uint8_t)0x05) /* 预分频器128 */
#define IWDG_Prescaler_256 ((uint8_t)0x06) /* 预分频器256 */说明:
IWDG_Prescaler_4:LSI时钟4分频,超时时间最短IWDG_Prescaler_8:LSI时钟8分频IWDG_Prescaler_16:LSI时钟16分频IWDG_Prescaler_32:LSI时钟32分频IWDG_Prescaler_64:LSI时钟64分频IWDG_Prescaler_128:LSI时钟128分频IWDG_Prescaler_256:LSI时钟256分频,超时时间最长
IWDG标志位定义
#define IWDG_FLAG_PVU ((uint16_t)0x0001) /* 预分频器更新标志 */
#define IWDG_FLAG_RVU ((uint16_t)0x0002) /* 重装载值更新标志 */说明:
IWDG_FLAG_PVU:预分频器更新标志,表示预分频器正在更新IWDG_FLAG_RVU:重装载值更新标志,表示重装载值正在更新
IWDG寄存器定义
STM32F10x IWDG外设包含以下主要寄存器:
// IWDG键寄存器
#define IWDG_KR ((uint16_t)0x0000) /* IWDG键寄存器 */
// IWDG预分频器寄存器
#define IWDG_PR ((uint16_t)0x0001) /* IWDG预分频器寄存器 */
// IWDG重装载寄存器
#define IWDG_RLR ((uint16_t)0x0002) /* IWDG重装载寄存器 */
// IWDG状态寄存器
#define IWDG_SR ((uint16_t)0x0003) /* IWDG状态寄存器 */标准库函数详解
1. IWDG_WriteAccessCmd
/**
* @brief 解锁/锁定 IWDG 寄存器写保护,配置前须先使能写访问
* @param IWDG_WriteAccess: 写访问状态
* 该参数可以是以下值之一:
* @arg IWDG_WriteAccess_Enable: 使能写访问
* @arg IWDG_WriteAccess_Disable: 禁用写访问
* @retval 无
* @example
* IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
*/
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);功能说明:
- 向键寄存器写入 0x5555 解锁,写入 0x0000 重新锁定
- 修改预分频器或重装载值前必须先 Enable
- 配置完成并 IWDG_Enable 后可 Disable 防止误写
2. IWDG_SetPrescaler
/**
* @brief 设置 IWDG 预分频系数(4~256),与重装载值共同决定超时时间
* @param IWDG_Prescaler: IWDG预分频器值
* 该参数可以是以下值之一:
* @arg IWDG_Prescaler_4: 预分频器4
* @arg IWDG_Prescaler_8: 预分频器8
* @arg IWDG_Prescaler_16: 预分频器16
* @arg IWDG_Prescaler_32: 预分频器32
* @arg IWDG_Prescaler_64: 预分频器64
* @arg IWDG_Prescaler_128: 预分频器128
* @arg IWDG_Prescaler_256: 预分频器256
* @retval 无
* @example
* IWDG_SetPrescaler(IWDG_Prescaler_64);
*/
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);功能说明:
- 须在写访问使能后、IWDG_Enable 之前调用
- 超时时间 = (Reload+1) × Prescaler / LSI_FREQ(LSI 约 40 kHz)
- 写入后应等待 IWDG_FLAG_PVU 清零确认更新完成
3. IWDG_SetReload
/**
* @brief 设置 IWDG 重装载值(0~0xFFF),决定计数器递减到 0 前的计数值
* @param Reload: IWDG重装载值,范围0-0xFFF
* @retval 无
* @example
* IWDG_SetReload(0xFFF);
*/
void IWDG_SetReload(uint16_t Reload);功能说明:
- 与预分频器配合计算超时:值越大超时越长,最大约 26 s(Prescaler=256, Reload=0xFFF)
- 须在写访问使能后调用,写入后等待 IWDG_FLAG_RVU 清零
- IWDG_ReloadCounter 喂狗时计数器重新加载为此值
4. IWDG_ReloadCounter
/**
* @brief 喂狗:向键寄存器写入 0xAAAA,重装载计数器防止超时复位
* @param 无
* @retval 无
* @example
* IWDG_ReloadCounter();
*/
void IWDG_ReloadCounter(void);功能说明:
- 必须在超时到达前周期性调用,否则系统将硬件复位
- 可在主循环、定时器中断或 RTOS 任务中调用
- 写入键值 0xAAAA 即可,无需解锁写访问
5. IWDG_Enable
/**
* @brief 启动独立看门狗,向键寄存器写入 0xCCCC 开始倒计时
* @param 无
* @retval 无
* @example
* IWDG_Enable();
*/
void IWDG_Enable(void);功能说明:
- 一旦启动无法软件关闭,仅硬件复位可停止
- 应在预分频器和重装载值配置完毕后再调用
- 使用 LSI 独立时钟,主时钟故障时仍能复位系统
6. IWDG_GetFlagStatus
/**
* @brief 查询 IWDG 寄存器更新状态(预分频器/重装载值是否写入完成)
* @param IWDG_FLAG: 要检查的IWDG标志
* 该参数可以是以下值之一:
* @arg IWDG_FLAG_PVU: 预分频器更新标志
* @arg IWDG_FLAG_RVU: 重装载值更新标志
* @retval 标志状态
* 该返回值可以是以下值之一:
* @arg SET: 标志已设置
* @arg RESET: 标志已清除
* @example
* FlagStatus flag = IWDG_GetFlagStatus(IWDG_FLAG_PVU);
*/
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);功能说明:
- SET 表示寄存器正在更新,应等待变为 RESET 后再继续配置
- 典型用法:while(IWDG_GetFlagStatus(IWDG_FLAG_PVU) == SET);
- 确保预分频器和重装载值已生效后再 IWDG_Enable
使用示例
基本IWDG初始化示例
#include "stm32f10x.h"
void IWDG_Init_Example(void)
{
// 使能IWDG写访问
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
// 设置IWDG预分频器为64
IWDG_SetPrescaler(IWDG_Prescaler_64);
// 设置IWDG重装载值为0xFFF(最大值)
IWDG_SetReload(0xFFF);
// 使能IWDG
IWDG_Enable();
// 禁用IWDG写访问
IWDG_WriteAccessCmd(IWDG_WriteAccess_Disable);
}IWDG超时时间计算示例
#include "stm32f10x.h"
// LSI时钟频率约为40kHz
#define LSI_FREQ 40000
// 计算IWDG超时时间(毫秒)
uint32_t IWDG_CalculateTimeout(uint8_t prescaler, uint16_t reload)
{
uint32_t timeout_ms;
switch(prescaler)
{
case IWDG_Prescaler_4:
timeout_ms = (reload + 1) * 4 * 1000 / LSI_FREQ;
break;
case IWDG_Prescaler_8:
timeout_ms = (reload + 1) * 8 * 1000 / LSI_FREQ;
break;
case IWDG_Prescaler_16:
timeout_ms = (reload + 1) * 16 * 1000 / LSI_FREQ;
break;
case IWDG_Prescaler_32:
timeout_ms = (reload + 1) * 32 * 1000 / LSI_FREQ;
break;
case IWDG_Prescaler_64:
timeout_ms = (reload + 1) * 64 * 1000 / LSI_FREQ;
break;
case IWDG_Prescaler_128:
timeout_ms = (reload + 1) * 128 * 1000 / LSI_FREQ;
break;
case IWDG_Prescaler_256:
timeout_ms = (reload + 1) * 256 * 1000 / LSI_FREQ;
break;
default:
timeout_ms = 0;
break;
}
return timeout_ms;
}
void IWDG_TimeoutExample(void)
{
// 初始化IWDG
IWDG_Init_Example();
// 计算超时时间
uint32_t timeout = IWDG_CalculateTimeout(IWDG_Prescaler_64, 0xFFF);
// timeout约为26.2秒
while(1)
{
// 定期喂狗,防止系统复位
IWDG_ReloadCounter();
// 延时一段时间
for(volatile uint32_t i = 0; i < 1000000; i++);
}
}IWDG在中断中喂狗示例
#include "stm32f10x.h"
volatile uint8_t watchdog_feed_flag = 0;
void IWDG_InterruptFeed_Example(void)
{
// 初始化IWDG
IWDG_Init_Example();
// 配置定时器中断,定期喂狗
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 999; // 1秒中断
TIM_TimeBaseStructure.TIM_Prescaler = 71999; // 72MHz / 72000 = 1kHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 使能定时器中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// 使能NVIC中断
NVIC_EnableIRQ(TIM2_IRQn);
// 启动定时器
TIM_Cmd(TIM2, ENABLE);
while(1)
{
// 主循环中的其他任务
if(watchdog_feed_flag)
{
IWDG_ReloadCounter();
watchdog_feed_flag = 0;
}
}
}
// TIM2中断服务程序
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
// 清除中断标志
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
// 设置喂狗标志
watchdog_feed_flag = 1;
}
}IWDG配置检查示例
#include "stm32f10x.h"
void IWDG_ConfigCheck_Example(void)
{
// 使能IWDG写访问
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
// 设置IWDG预分频器
IWDG_SetPrescaler(IWDG_Prescaler_64);
// 等待预分频器更新完成
while(IWDG_GetFlagStatus(IWDG_FLAG_PVU) == SET);
// 设置IWDG重装载值
IWDG_SetReload(0xFFF);
// 等待重装载值更新完成
while(IWDG_GetFlagStatus(IWDG_FLAG_RVU) == SET);
// 使能IWDG
IWDG_Enable();
// 禁用IWDG写访问
IWDG_WriteAccessCmd(IWDG_WriteAccess_Disable);
}注意事项
- 独立时钟源:IWDG使用LSI时钟,不依赖于系统时钟
- 写访问控制:配置IWDG前必须使能写访问
- 不可禁用:IWDG一旦使能后无法禁用,只能通过系统复位禁用
- 超时时间:超时时间 = (重装载值 + 1) × 预分频器 / LSI频率
- 定期喂狗:必须在超时时间到达前调用
IWDG_ReloadCounter() - 寄存器更新:修改预分频器或重装载值后需要等待更新完成
- LSI精度:LSI时钟精度较低,超时时间可能有偏差
- 调试影响:在调试模式下,IWDG可能影响调试功能
总结
STM32F10x IWDG外设提供了可靠的系统监控功能,通过独立的时钟源确保在系统出现故障时能够自动复位。IWDG外设广泛应用于需要高可靠性的嵌入式系统中,如工业控制、汽车电子、医疗设备等领域。在使用时需要注意正确的初始化顺序、超时时间计算和定期喂狗,确保看门狗功能的正常使用。IWDG一旦使能后无法禁用,这确保了系统监控的可靠性,但也要求开发者必须正确实现喂狗机制。