系统冗余设计:STM32F7双看门狗+电源监控,提高可靠性

文章目录

一、技术背景与设计思路

在工业控制、车载电子等对可靠性要求极高的场景中,STM32F7系列单片机的系统稳定性直接决定产品的可用性。单一的硬件保护机制难以应对复杂的现场环境(如电源波动、程序跑飞、电磁干扰等),因此本文设计基于STM32F7的双看门狗(独立看门狗IWDG + 窗口看门狗WWDG)+ 电源监控(PVD) 冗余保护方案,从程序运行监控、电源稳定性检测两个维度提升系统可靠性。

1.1 核心组件功能说明

  • 独立看门狗(IWDG):由内部低速时钟(LSI)驱动,不受主时钟故障影响,适用于监控主程序长时间卡死的场景,超时后强制复位系统。
  • 窗口看门狗(WWDG):由APB1时钟驱动,具有"窗口"特性,仅在指定时间窗口内喂狗有效,可监控程序是否出现死循环或执行速度异常。
  • 电源监控(PVD):通过配置电压检测阈值,实时监控VDD电源电压,当电压低于/高于阈值时触发中断或复位,防止系统在欠压/过压状态下运行导致数据损坏。

1.2 整体设计流程图







系统上电初始化
时钟配置

LSI/APB1/PWR时钟使能
IWDG初始化

设置预分频&重载值
WWDG初始化

设置窗口值&预分频&重载值
PVD初始化

配置电压阈值&中断模式
主程序循环
程序正常执行?
定时喂IWDG

在WWDG窗口内喂狗
IWDG/WWDG超时

系统复位
电源电压正常?
PVD中断触发

执行应急处理
故障恢复?
系统复位

二、硬件准备与开发环境搭建

2.1 硬件清单

  • 主控芯片:STM32F767IGT6(兼容其他F7系列)
  • 电源模块:5V转3.3V稳压电源(推荐LM1117-3.3)
  • 调试工具:ST-Link V2
  • 辅助工具:万用表、示波器(可选,用于电源电压检测)

2.2 开发环境配置

  1. 安装STM32CubeIDE(版本推荐1.15.0及以上):
  2. 安装STM32CubeMX(版本推荐6.9.0及以上):
    • 用于图形化配置引脚、时钟、外设等,生成初始化代码。
  3. 配置ST-Link调试器:
    • 连接ST-Link与开发板的SWD接口(SWDIO、SWCLK、GND),确保硬件连接正确。

三、分步实现:双看门狗+电源监控

3.1 第一步:STM32CubeMX初始化配置

3.1.1 新建工程
  1. 打开STM32CubeMX,点击"New Project",搜索"STM32F767IGT6"并选择对应芯片。
  2. 配置时钟树:
    • 外部晶振(HSE)设为25MHz,系统时钟(SYSCLK)配置为216MHz。
    • APB1时钟分频设为4,最终APB1时钟为54MHz(WWDG时钟源为APB1/4096)。
    • 启用LSI时钟(32kHz,IWDG时钟源)。
3.1.2 外设配置
(1)独立看门狗(IWDG)配置
  • 点击"Configuration" → "IWDG":
    • 勾选"IWDG enabled";
    • 预分频器(Prescaler)选择"32"(分频系数=32,LSI=32kHz → 计数时钟=1kHz);
    • 重载值(Reload Value)设为"1000"(超时时间=1000ms,即1秒喂狗一次);
    • 勾选"Enable write access to IWDG_PR and IWDG_RLR registers"。
(2)窗口看门狗(WWDG)配置
  • 点击"Configuration" → "WWDG":
    • 勾选"WWDG enabled";
    • 预分频器(Prescaler)选择"8"(分频系数=8,APB1=54MHz → WWDG时钟=54MHz/4096/8≈1640Hz);
    • 窗口值(Window Value)设为"0x70";
    • 重载值(Counter Value)设为"0x7F"(超时时间≈(0x7F-0x70)/1640≈5.48ms,窗口时间范围:5.48ms~(0x7F)/1640≈78.6ms);
    • 勾选"WWDG early wakeup interrupt"(启用早起唤醒中断,可选)。
(3)电源监控(PVD)配置
  • 点击"Configuration" → "Power Configuration":
    • 勾选"PVD Level",选择阈值(如"PVD Level 2",对应VDD=2.8V,即电压低于2.8V触发中断);
    • 勾选"PVD Mode"为"Interrupt mode"(中断模式,也可选择复位模式);
    • 启用PWR时钟(自动配置)。
3.1.3 生成代码
  • 点击"Project Manager",设置工程名称(如"STM32F7_WDG_PVD")、保存路径,选择"Toolchain/IDE"为"STM32CubeIDE";
  • 点击"GENERATE CODE",生成初始化代码。

3.2 第二步:代码编写与实现

3.2.1 代码文件结构

本次教程核心代码分布在以下文件:

  • main.c:主程序逻辑、喂狗操作、PVD中断处理
  • stm32f7xx_hal_msp.c:中断优先级配置
  • wdg_pvd.c/wdg_pvd.h:自定义看门狗和PVD驱动函数(新增文件)
3.2.2 新建自定义驱动文件

文件名:wdg_pvd.h

c 复制代码
#ifndef __WDG_PVD_H
#define __WDG_PVD_H

#include "stm32f7xx_hal.h"

/* 函数声明 */
// IWDG初始化与喂狗
void IWDG_Init_Config(void);
void IWDG_Feed_Dog(void);

// WWDG初始化与喂狗
void WWDG_Init_Config(void);
void WWDG_Feed_Dog(uint8_t counter);

// PVD初始化与中断处理
void PVD_Init_Config(void);
void PVD_Emergency_Handler(void);

#endif /* __WDG_PVD_H */

文件名:wdg_pvd.c

c 复制代码
#include "wdg_pvd.h"

/* 独立看门狗初始化
 * 时钟源:LSI(32kHz),预分频32 → 1kHz计数时钟
 * 重载值1000 → 超时时间1000ms
 */
void IWDG_Init_Config(void)
{
  // 解锁IWDG寄存器(写0x5555到KR寄存器)
  HAL_IWDG_Write(&hiwdg, IWDG_KR, 0x5555);
  
  // 设置预分频器:32
  if(HAL_IWDG_PrescalerConfig(&hiwdg, IWDG_PRESCALER_32) != HAL_OK)
  {
    Error_Handler(); // 初始化失败处理
  }
  
  // 设置重载值:1000
  if(HAL_IWDG_ReloadConfig(&hiwdg, 1000) != HAL_OK)
  {
    Error_Handler();
  }
  
  // 启动IWDG(写0xCCCC到KR寄存器)
  HAL_IWDG_Write(&hiwdg, IWDG_KR, 0xCCCC);
}

/* 独立看门狗喂狗
 * 写0xAAAA到KR寄存器,重载计数器
 */
void IWDG_Feed_Dog(void)
{
  HAL_IWDG_Write(&hiwdg, IWDG_KR, 0xAAAA);
}

/* 窗口看门狗初始化
 * 预分频8,窗口值0x70,计数器初始值0x7F
 */
void WWDG_Init_Config(void)
{
  hwwdg.Instance = WWDG;
  hwwdg.Init.Prescaler = WWDG_PRESCALER_8;    // 预分频8
  hwwdg.Init.Window = 0x70;                   // 窗口值
  hwwdg.Init.Counter = 0x7F;                  // 计数器初始值
  hwwdg.Init.EWIMode = WWDG_EWI_ENABLE;       // 启用早起唤醒中断
  if (HAL_WWDG_Init(&hwwdg) != HAL_OK)
  {
    Error_Handler();
  }
}

/* 窗口看门狗喂狗
 * 注意:counter必须大于窗口值且小于0x80,否则喂狗无效
 */
void WWDG_Feed_Dog(uint8_t counter)
{
  // 检查计数器值是否在有效范围
  if(counter > 0x70 && counter <= 0x7F)
  {
    HAL_WWDG_SetCounter(&hwwdg, counter);
  }
  else
  {
    // 喂狗值无效,触发错误处理
    Error_Handler();
  }
}

/* PVD电源监控初始化
 * 阈值:PVD Level 2 (2.8V),中断模式
 */
void PVD_Init_Config(void)
{
  PWR_PVDTypeDef sConfigPVD = {0};

  // 启用PWR时钟
  __HAL_RCC_PWR_CLK_ENABLE();

  // 配置PVD参数
  sConfigPVD.PVDLevel = PWR_PVDLEVEL_2;       // 2.8V阈值
  sConfigPVD.Mode = PWR_PVD_MODE_IT_RISING_FALLING; // 上升/下降沿都触发中断
  HAL_PWR_ConfigPVD(&sConfigPVD);

  // 启用PVD
  HAL_PWR_EnablePVD();

  // 配置PVD中断优先级并启用
  HAL_NVIC_SetPriority(PVD_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(PVD_IRQn);
}

/* PVD应急处理函数
 * 电压异常时执行:保存关键数据、关闭外设、提示故障等
 */
void PVD_Emergency_Handler(void)
{
  // 1. 关闭所有外设(如GPIO、UART、SPI等)
  __HAL_GPIO_EXTI_CLEAR_FLAG(GPIO_PIN_0); // 示例:清除GPIO中断标志
  HAL_UART_MspDeInit(&huart1);            // 示例:关闭UART1

  // 2. 保存关键数据到FLASH(示例:简化版)
  // 实际项目中需实现FLASH写入逻辑,此处仅为示例
  uint32_t critical_data = 0x12345678;
  // FLASH_Program(0x08080000, critical_data); // 需自行实现FLASH编程函数

  // 3. 触发故障提示(如点亮LED)
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // 假设PA5接LED

  // 4. 等待100ms后尝试复位(可选)
  HAL_Delay(100);
  NVIC_SystemReset();
}
3.2.3 修改main.c文件

文件名:main.c

c 复制代码
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "iwdg.h"
#include "wwdg.h"
#include "wdg_pvd.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);

/* Private user code ---------------------------------------------------------*/
int main(void)
{
  /* 1. 初始化HAL库 */
  HAL_Init();

  /* 2. 配置系统时钟 */
  SystemClock_Config();

  /* 3. 初始化外设 */
  MX_GPIO_Init();           // GPIO初始化(含LED、按键等)
  MX_IWDG_Init();           // IWDG底层初始化(CubeMX生成)
  MX_WWDG_Init();           // WWDG底层初始化(CubeMX生成)
  
  /* 4. 初始化自定义驱动 */
  IWDG_Init_Config();       // 配置IWDG参数并启动
  WWDG_Init_Config();       // 配置WWDG参数
  PVD_Init_Config();        // 配置PVD电源监控

  /* 5. 主循环 */
  while (1)
  {
    /* -------------------------- 喂狗操作 -------------------------- */
    // IWDG喂狗:每900ms一次(小于1000ms超时时间)
    IWDG_Feed_Dog();
    HAL_Delay(900);

    // WWDG喂狗:计数器设为0x75(在窗口0x70~0x7F范围内)
    WWDG_Feed_Dog(0x75);

    /* -------------------------- 业务逻辑 -------------------------- */
    // 示例:闪烁LED,指示系统正常运行
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // PA5接LED
    HAL_Delay(100);

    /* 注:实际项目中,此处添加你的业务代码(如数据采集、控制逻辑等)
     * 若业务代码执行时间过长或卡死,看门狗会超时复位
     */
  }
}

/* PVD中断服务函数 */
void PVD_IRQHandler(void)
{
  // 清除PVD中断标志
  HAL_PWR_ClearFlag(PWR_FLAG_PVDO);
  
  // 执行应急处理
  PVD_Emergency_Handler();
}

/* 系统时钟配置函数(CubeMX生成,略作注释) */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  // 配置电源电压缩放级别
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  // 配置HSE振荡器
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSI;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON; // 启用LSI,供IWDG使用
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 432;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  // 配置系统时钟
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1=54MHz
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
  {
    Error_Handler();
  }
}

/* GPIO初始化函数(示例:配置PA5为输出,接LED) */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  // 启用GPIOA时钟
  __HAL_RCC_GPIOA_CLK_ENABLE();

  // 配置PA5为推挽输出
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  // 初始状态:LED熄灭
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}

/* 错误处理函数 */
void Error_Handler(void)
{
  // 打印错误信息(若启用UART)
  // HAL_UART_Transmit(&huart1, (uint8_t*)"Error!", 6, 100);
  
  // 点亮LED,指示错误
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
  
  // 死循环,等待看门狗复位
  while(1)
  {
  }
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
  // 断言失败处理
}
#endif /* USE_FULL_ASSERT */

3.3 第三步:代码编译与下载

  1. 打开STM32CubeIDE,导入生成的工程;
  2. wdg_pvd.c/wdg_pvd.h添加到工程的Src/Inc目录下;
  3. 点击"Build Project"编译代码,确保无语法错误;
  4. 连接ST-Link与开发板,点击"Debug"下载代码到STM32F7芯片。

3.4 第四步:功能测试与验证

3.4.1 IWDG测试
  • 注释主循环中的IWDG_Feed_Dog()函数,重新下载代码;
  • 观察现象:系统运行1秒后自动复位,LED闪烁节奏被打断,证明IWDG生效。
3.4.2 WWDG测试
  • 修改WWDG_Feed_Dog()的参数为0x60(小于窗口值0x70),重新下载代码;
  • 观察现象:系统快速复位(约5ms),证明WWDG窗口机制生效。
3.4.3 PVD测试
  • 使用可调电源给开发板供电,逐步降低VDD电压至2.8V以下;
  • 观察现象:PVD中断触发,LED常亮,系统执行应急处理后复位,证明电源监控生效。

四、进阶优化建议

  1. 看门狗喂狗时机优化:将喂狗操作分散到关键业务逻辑节点,而非固定延时,避免程序跑飞但仍能喂狗的情况。
  2. PVD阈值分级:根据实际应用场景,配置多级PVD阈值(如2.8V、3.0V、3.2V),实现不同电压等级的差异化处理。
  3. 故障日志记录:在PVD中断或看门狗复位后,将故障信息写入FLASH,便于后期排查问题。
  4. 硬件冗余设计:在PCB层面增加电源滤波电容、TVS管等,减少电源波动和电磁干扰对系统的影响。

五、常见问题与解决

  1. 看门狗频繁复位
    • 检查喂狗频率是否低于超时时间;
    • 排查主程序是否存在长时间阻塞(如死循环、延时过长)。
  2. PVD中断不触发
    • 确认PWR时钟已启用;
    • 检查PVD中断优先级配置是否正确;
    • 验证电压检测阈值是否与实际电源电压匹配。
  3. LSI时钟不稳定
    • 在STM32CubeMX中启用LSI校准功能;
    • 硬件层面增加滤波电容,减少干扰。

总结

  1. 本次设计基于STM32F7实现了"独立看门狗+窗口看门狗+电源监控"的三重冗余保护,IWDG监控长周期程序异常,WWDG监控短周期执行异常,PVD监控电源电压波动,全方位提升系统可靠性。
  2. 核心代码包含完整的初始化、喂狗、中断处理逻辑,零基础用户可按照步骤在STM32CubeIDE中实现落地,关键需注意看门狗喂狗时机和PVD中断优先级配置。
  3. 测试验证需分别针对三个核心功能进行,通过人为制造异常(如停止喂狗、降低电源电压)验证保护机制是否生效,确保实际场景中系统稳定运行。
相关推荐
豆豆饿啦2 小时前
【瑞萨AI挑战赛】#01 快速开始
嵌入式硬件·mcu·物联网·iot
豆豆饿啦3 小时前
【瑞萨AI挑战赛】#02 DL任务说明及训练
人工智能·嵌入式硬件·mcu·物联网·iot
国科安芯3 小时前
抗辐照加固CAN FD芯片的商业航天与车规级应用解析
科技·嵌入式硬件·安全·fpga开发·安全威胁分析
GodKK老神灭4 小时前
CMSIS-DAP协议关键命令完整数据包示例详解
单片机·keil
XINVRY-FPGA4 小时前
XC7Z020-2CLG400I Xilinx AMDZynq-7000 FPGA
嵌入式硬件·fpga开发·arm·硬件工程·dsp开发·fpga
暮雪倾风5 小时前
【软件安装】VSPD(Virtual Serial Port Driver)虚拟串口软件安装及使用
单片机·串口
头发够用的程序员5 小时前
GPU 流水线底层探索:从 SIMT 前端到 SIMD 后端的全链路解析
arm开发·人工智能·嵌入式硬件·深度学习·硬件架构·边缘计算
SY师弟5 小时前
蓝桥杯单片机——安装芯片包
单片机·嵌入式硬件·职场和发展·蓝桥杯
7yewh5 小时前
MCU 卷积神经网络部署 · 深度技术指南
linux·嵌入式硬件·ai·嵌入式