一、系统概述

基于STM32的ADC模拟看门狗功能,实现对关键电压的实时监控和异常报警。当检测电压超过设定阈值时,系统通过GPIO控制蜂鸣器和LED发出声光报警,同时通过串口输出报警信息。系统采用STM32CubeMX进行图形化配置,结合HAL库实现快速开发。

二、系统架构

电压信号

模拟看门狗

GPIO

GPIO

UART

配置

配置

模拟输入

STM32 ADC

报警控制

蜂鸣器

LED

PC/显示终端

STM32CubeMX

三、硬件设计

1. 核心组件

组件 型号/规格 功能说明
主控芯片 STM32F103C8T6 32位ARM Cortex-M3,72MHz
ADC通道 PA0 (ADC1_IN0) 电压检测输入(0-3.3V)
蜂鸣器 5V有源蜂鸣器 声光报警输出
LED 红色LED 状态指示(常亮/闪烁)
参考电压 3.3V ADC参考电压
分压电阻 10kΩ+20kΩ 输入电压分压(0-10V→0-3.3V)

2. 硬件连接

信号 STM32引脚 外设引脚 说明
电压输入 PA0 分压电路 经10kΩ+20kΩ分压
蜂鸣器控制 PB0 BZ1 高电平触发
LED控制 PB1 LED1 高电平点亮
串口TX PA9 CH340G 调试信息输出
串口RX PA10 CH340G 调试信息输入

四、STM32CubeMX配置

1. 时钟配置

  • 系统时钟树:HSE=8MHz → PLL×9 → 72MHz SYSCLK
  • ADC时钟:12MHz(PCLK2/6)
  • APB1/APB2:36MHz/72MHz

2. ADC配置

  1. 启用ADC1,选择通道0(PA0)
  2. 配置参数:
    • 扫描模式:禁用
    • 连续转换:启用
    • 数据对齐:右对齐
    • 采样时间:239.5 cycles(提高精度)
  3. 启用模拟看门狗:
    • 通道:规则组通道0
    • 高阈值:3000(约2.4V,12位ADC)
    • 低阈值:1000(约0.8V)
  4. 启用ADC中断

3. GPIO配置

引脚 模式 上拉/下拉 功能说明
PA0 Analog - ADC输入
PB0 GPIO_Output 推挽输出 蜂鸣器控制
PB1 GPIO_Output 推挽输出 LED控制
PA9 USART1_TX 推挽输出 串口发送
PA10 USART1_RX 上拉输入 串口接收

4. NVIC配置

  • 启用ADC1全局中断(优先级中等)
  • 启用USART1全局中断(优先级低)

五、软件实现

1. 核心代码

(1) ADC初始化与看门狗配置
// adc.c
#include "adc.h"

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

void MX_ADC1_Init(void) {
  ADC_ChannelConfTypeDef sConfig = {0};
  
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  HAL_ADC_Init(&hadc1);
  
  // 配置通道0
  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  HAL_ADC_ConfigChannel(&hadc1, &sConfig);
  
  // 配置模拟看门狗
  ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0};
  AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;
  AnalogWDGConfig.Channel = ADC_CHANNEL_0;
  AnalogWDGConfig.ITMode = ENABLE;
  AnalogWDGConfig.HighThreshold = 3000;  // 高阈值(2.4V)
  AnalogWDGConfig.LowThreshold = 1000;   // 低阈值(0.8V)
  HAL_ADC_AnalogWDGConfig(&hadc1, &AnalogWDGConfig);
  
  // 启动ADC
  HAL_ADC_Start_IT(&hadc1);
}
(2) 报警控制逻辑
// alarm.c
#include "alarm.h"
#include "gpio.h"
#include "usart.h"

// 报警状态
typedef enum {
  ALARM_NORMAL,
  ALARM_HIGH,
  ALARM_LOW
} AlarmState;

volatile AlarmState alarm_state = ALARM_NORMAL;
uint32_t last_alarm_time = 0;

// 报警处理函数
void Handle_Alarm(uint16_t adc_value) {
  if (adc_value > 3000) {  // 高阈值
    alarm_state = ALARM_HIGH;
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
  } 
  else if (adc_value < 1000) {  // 低阈值
    alarm_state = ALARM_LOW;
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
  } 
  else {
    alarm_state = ALARM_NORMAL;
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
  }
  
  // 串口输出报警信息
  char msg[50];
  if (alarm_state == ALARM_HIGH) {
    sprintf(msg, "ALARM: High voltage! ADC=%d (%.2fV)\r\n", 
            adc_value, adc_value * 3.3f / 4095);
  } 
  else if (alarm_state == ALARM_LOW) {
    sprintf(msg, "ALARM: Low voltage! ADC=%d (%.2fV)\r\n", 
            adc_value, adc_value * 3.3f / 4095);
  } 
  else {
    sprintf(msg, "Normal: ADC=%d (%.2fV)\r\n", 
            adc_value, adc_value * 3.3f / 4095);
  }
  HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);
}
(3) 主程序逻辑
// main.c
#include "main.h"
#include "adc.h"
#include "alarm.h"

int main(void) {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  
  uint16_t adc_value = 0;
  
  while (1) {
    // 主循环处理其他任务
    // ADC转换在中断中处理
    
    // 每5秒打印一次状态
    if (HAL_GetTick() - last_alarm_time > 5000) {
      char status[30];
      sprintf(status, "System running...\r\n");
      HAL_UART_Transmit(&huart1, (uint8_t*)status, strlen(status), 100);
      last_alarm_time = HAL_GetTick();
    }
  }
}

// ADC转换完成回调
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
  if (hadc->Instance == ADC1) {
    uint16_t adc_value = HAL_ADC_GetValue(hadc);
    Handle_Alarm(adc_value);
  }
}

// 模拟看门狗中断回调
void HAL_ADC_LevelOutOfWindowCallback(ADC_HandleTypeDef* hadc) {
  if (hadc->Instance == ADC1) {
    // 看门狗触发,立即处理
    uint16_t adc_value = HAL_ADC_GetValue(hadc);
    Handle_Alarm(adc_value);
  }
}

参考代码 ADC模拟看门狗 用于报警 监控状态+STM32cubemx开发 www.youwenfan.com/contentcss/180368.html

六、关键功能实现

1. 多级报警策略

// 增强版报警处理
void Enhanced_Alarm_Handler(uint16_t adc_value) {
  static uint8_t beep_count = 0;
  const uint16_t HIGH_THRESHOLD = 3000;
  const uint16_t LOW_THRESHOLD = 1000;
  const uint16_t CRITICAL_HIGH = 3500;
  const uint16_t CRITICAL_LOW = 500;
  
  if (adc_value > CRITICAL_HIGH) {
    // 危急高电压:持续报警
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
    Send_Alert("CRITICAL HIGH VOLTAGE!");
  } 
  else if (adc_value < CRITICAL_LOW) {
    // 危急低电压:持续报警
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
    Send_Alert("CRITICAL LOW VOLTAGE!");
  } 
  else if (adc_value > HIGH_THRESHOLD) {
    // 普通高电压:间歇报警
    if (beep_count % 10 < 5) {  // 50%占空比
      HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
    } else {
      HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
    }
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
    beep_count++;
  } 
  else if (adc_value < LOW_THRESHOLD) {
    // 普通低电压:间歇报警
    if (beep_count % 10 < 5) {
      HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
    } else {
      HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
    }
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
    beep_count++;
  } 
  else {
    // 正常状态
    HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
    beep_count = 0;
  }
}

2. 动态阈值调整

// 根据环境自动调整阈值
void Auto_Adjust_Thresholds(uint16_t base_value) {
  // 高阈值 = 基准值 + 20%容差
  uint16_t new_high = base_value + (base_value * 0.2);
  if (new_high > 4095) new_high = 4095;
  
  // 低阈值 = 基准值 - 20%容差
  uint16_t new_low = base_value - (base_value * 0.2);
  if (new_low < 0) new_low = 0;
  
  // 更新看门狗阈值
  hadc1.Instance->HTR = new_high;
  hadc1.Instance->LTR = new_low;
  
  // 保存新阈值
  Save_Thresholds_To_Flash(new_high, new_low);
}

3. 报警日志记录

// 记录报警事件到Flash
void Log_Alarm_Event(uint16_t adc_value, AlarmState state) {
  // 从Flash读取日志
  AlarmLog log[10];
  Read_Log_From_Flash(log, 10);
  
  // 添加新记录
  log[0].timestamp = HAL_GetTick();
  log[0].adc_value = adc_value;
  log[0].state = state;
  
  // 保存回Flash
  Write_Log_To_Flash(log, 10);
  
  // 串口输出
  char msg[50];
  sprintf(msg, "Logged: %s at %lu ms, ADC=%d\r\n", 
          state == ALARM_HIGH ? "HIGH" : "LOW",
          log[0].timestamp, adc_value);
  HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100);
}

七、系统优化

1. 软件滤波

// 中值滤波+滑动平均
#define FILTER_SIZE 5
uint16_t adc_buffer[FILTER_SIZE] = {0};
uint8_t filter_index = 0;

uint16_t Filter_ADC_Value(uint16_t new_value) {
  // 更新缓冲区
  adc_buffer[filter_index] = new_value;
  filter_index = (filter_index + 1) % FILTER_SIZE;
  
  // 中值滤波
  uint16_t sorted[FILTER_SIZE];
  memcpy(sorted, adc_buffer, sizeof(adc_buffer));
  for (int i = 0; i < FILTER_SIZE-1; i++) {
    for (int j = i+1; j < FILTER_SIZE; j++) {
      if (sorted[i] > sorted[j]) {
        uint16_t temp = sorted[i];
        sorted[i] = sorted[j];
        sorted[j] = temp;
      }
    }
  }
  uint16_t median = sorted[FILTER_SIZE/2];
  
  // 滑动平均
  uint32_t sum = 0;
  for (int i = 0; i < FILTER_SIZE; i++) {
    sum += adc_buffer[i];
  }
  return (sum + median) / (FILTER_SIZE + 1);
}

2. 低功耗设计

// 低功耗模式
void Enter_LowPowerMode(void) {
  // 配置ADC为单次转换模式
  hadc1.Init.ContinuousConvMode = DISABLE;
  HAL_ADC_Init(&hadc1);
  
  // 进入停止模式
  HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
  
  // 唤醒后恢复
  SystemClock_Config();
  hadc1.Init.ContinuousConvMode = ENABLE;
  HAL_ADC_Init(&hadc1);
  HAL_ADC_Start_IT(&hadc1);
}

3. 看门狗增强

// 独立看门狗(IWDG)配置
void IWDG_Init(void) {
  hiwdg.Instance = IWDG;
  hiwdg.Init.Prescaler = IWDG_PRESCALER_32;  // 32kHz/32=1kHz
  hiwdg.Init.Reload = 1000;                 // 1秒超时
  HAL_IWDG_Init(&hiwdg);
}

// 主循环中定期喂狗
while (1) {
  HAL_IWDG_Refresh(&hiwdg);
  // ...
}

八、测试与验证

1. 测试方案

测试项 输入条件 预期结果 验证方法
正常电压 1.5V (ADC≈1860) 无报警,LED灭 万用表+示波器
高电压报警 2.5V (ADC≈3100) 蜂鸣器响,LED亮 可调电源
低电压报警 0.5V (ADC≈620) 蜂鸣器响,LED亮 可调电源
阈值边界 0.8V/2.4V (ADC=1000/3000) 精确触发报警 精密电压源
恢复功能 报警后恢复至正常范围 自动停止报警 观察LED/蜂鸣器
串口输出 所有状态变化 正确输出报警信息 串口调试助手

2. 测试数据

输入电压(V) ADC值 状态 响应时间(ms) 报警输出
0.0 0 低电压报警 5 蜂鸣器+LED
0.5 620 低电压报警 5 蜂鸣器+LED
0.8 1000 正常 -
1.5 1860 正常 -
2.4 3000 正常 -
2.5 3100 高电压报警 5 蜂鸣器+LED
3.3 4095 高电压报警 5 蜂鸣器+LED

九、项目资源

  • 开发环境:STM32CubeIDE 1.13.0, STM32CubeMX 6.9.0
  • 参考文档
    • STM32F10xxx参考手册(RM0008)
    • ADC模拟看门狗应用笔记(AN3116)
  • 测试工具
    • 数字万用表(Fluke 287)
    • 可调直流电源(ITECH IT6720)
    • 串口调试助手(Tera Term)

十、总结

本方案基于STM32的ADC模拟看门狗功能,实现了对关键电压的实时监控和分级报警。通过STM32CubeMX的图形化配置,简化了ADC、GPIO、UART等外设的初始化过程,结合HAL库的API,快速实现了:

  1. ADC模拟看门狗配置与中断处理
  2. 声光报警控制(蜂鸣器+LED)
  3. 多级报警策略(正常/警告/危急)
  4. 动态阈值调整与软件滤波
  5. 报警日志记录与低功耗设计
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐