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寄存器的写访问,允许配置IWDG
  • IWDG_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);
}

注意事项

  1. 独立时钟源:IWDG使用LSI时钟,不依赖于系统时钟
  2. 写访问控制:配置IWDG前必须使能写访问
  3. 不可禁用:IWDG一旦使能后无法禁用,只能通过系统复位禁用
  4. 超时时间:超时时间 = (重装载值 + 1) × 预分频器 / LSI频率
  5. 定期喂狗:必须在超时时间到达前调用IWDG_ReloadCounter()
  6. 寄存器更新:修改预分频器或重装载值后需要等待更新完成
  7. LSI精度:LSI时钟精度较低,超时时间可能有偏差
  8. 调试影响:在调试模式下,IWDG可能影响调试功能

总结

STM32F10x IWDG外设提供了可靠的系统监控功能,通过独立的时钟源确保在系统出现故障时能够自动复位。IWDG外设广泛应用于需要高可靠性的嵌入式系统中,如工业控制、汽车电子、医疗设备等领域。在使用时需要注意正确的初始化顺序、超时时间计算和定期喂狗,确保看门狗功能的正常使用。IWDG一旦使能后无法禁用,这确保了系统监控的可靠性,但也要求开发者必须正确实现喂狗机制。