MM32F0144芯片ADC电压采样策略详解

MM32F0144 芯片 ADC 电压采样策略详解

目录

  1. 引言

  2. [MM32F0144 ADC 模块特性](#MM32F0144 ADC 模块特性)

  3. [ADC 电压采样基础原理](#ADC 电压采样基础原理)

  4. 采样时间配置策略

  5. 输入信号调理电路

  6. 软件采样算法

  7. 抗干扰设计

  8. 多通道采样管理

  9. 低功耗采样策略

  10. 实战案例分析

  11. 调试与验证方法

  12. 最佳实践与优化建议

  13. 总结与展望


引言

在嵌入式系统开发中,ADC(模数转换器)是连接模拟世界与数字世界的关键桥梁。MM32F0144 作为灵动微电子推出的高性能 32 位微控制器,集成了 12 位精度的 ADC 模块,能够满足各种模拟信号采集需求。

ADC 电压采样的准确性直接影响到系统的测量精度和控制效果。不同的应用场景对 ADC 采样有不同的要求:工业控制需要高精度和稳定性,消费电子注重低功耗和成本,医疗设备则要求极高的精度和可靠性。

本文将深入探讨 MM32F0144 芯片 ADC 模块的工作原理,详细介绍各种电压采样策略,包括采样时间配置、信号调理、软件算法、抗干扰设计等方面,并通过实际案例展示如何在不同应用场景中优化 ADC 采样性能。


MM32F0144 ADC 模块特性

2.1 ADC 核心参数

2.1.1 基本特性

MM32F0144 集成了一个 12 位逐次逼近型 ADC,具有以下主要特性:

特性 规格
分辨率 12 位(4096 个量化级别)
转换速度 最高 1MHz(1μs 转换时间)
输入电压范围 0V ~ VREF(2.4V ~ 3.6V)
供电电压 VDDA: 2.4V ~ 3.6V, VSSA: 0V
通道数量 8 个外部通道 + 2 个内部通道
转换模式 单次转换、连续转换、扫描模式
数据对齐 左对齐或右对齐
触发方式 软件触发、定时器触发
2.1.2 性能指标
复制代码
/**

* @brief MM32F0144 ADC性能参数

*/

typedef struct {

   float resolution;         // 分辨率:0.8mV/LSB (@3.3V)

   float max_sample_rate;    // 最大采样率:1MHz

   float conversion_time;    // 转换时间:1μs

   float inl_error;          // 积分非线性误差:±2LSB

   float dnl_error;          // 微分非线性误差:±1LSB

   float signal_noise_ratio; // 信噪比:≥68dB

   float power_consumption;  // 功耗:约2.5mA (@1MHz)

} ADC_PerformanceTypeDef;

2.2 ADC 架构与工作原理

2.2.1 内部架构
复制代码
模拟输入 → 多路开关 → 采样保持电路 → 逐次逼近寄存器 → 数据寄存器

                   ↓

               参考电压

                   ↓

                 时钟电路
2.2.2 转换过程
  1. 采样阶段:模拟开关闭合,采样电容充电到输入电压

  2. 保持阶段:模拟开关断开,保持电容电压

  3. 量化阶段:逐次逼近寄存器通过比较器确定数字代码

  4. 编码阶段:将量化结果转换为二进制代码存储

2.3 ADC 寄存器配置

2.3.1 控制寄存器
复制代码
/**

* @brief ADC控制寄存器定义

*/

typedef struct {

   __IO uint32_t CR;         // 控制寄存器

   __IO uint32_t CFGR1;      // 配置寄存器1

   __IO uint32_t CFGR2;      // 配置寄存器2

   __IO uint32_t SAMPR;      // 采样时间寄存器

   __IO uint32_t RESERVED1;  // 保留

   __IO uint32_t TR;         // 阈值寄存器

   __IO uint32_t CHSELR;     // 通道选择寄存器

   __IO uint32_t RESERVED2;  // 保留

   __IO uint32_t DR;         // 数据寄存器

   __IO uint32_t RESERVED3[2];// 保留

   __IO uint32_t SR;         // 状态寄存器

   __IO uint32_t RESERVED4[5];// 保留

   __IO uint32_t CCR;        // 通用控制寄存器

} ADC_TypeDef;
2.3.2 初始化配置
复制代码
/**

* @brief ADC初始化配置

*/

void ADC_InitConfig(void)

{

   // 使能ADC时钟

   RCC->APB2ENR |= RCC_APB2ENR_ADCEN;

  

   // 复位ADC

   RCC->APB2RSTR |= RCC_APB2RSTR_ADCRST;

   RCC->APB2RSTR &= ~RCC_APB2RSTR_ADCRST;

  

   // 配置ADC参数

   ADC1->CFGR1 = 0;

   ADC1->CFGR1 |= ADC_CFGR1_RES_1;        // 12位分辨率

   ADC1->CFGR1 |= ADC_CFGR1_ALIGN;        // 左对齐

   ADC1->CFGR1 |= ADC_CFGR1_CONT;         // 连续转换模式

  

   // 配置采样时间:1.5个ADC时钟周期

   ADC1->SAMPR = ADC_SAMPR_SMP_0;

  

   // 使能ADC

   ADC1->CR |= ADC_CR_ADEN;

  

   // 等待ADC就绪

   while (!(ADC1->SR & ADC_SR_ADRDY));

}

ADC 电压采样基础原理

3.1 采样定理与频率

3.1.1 奈奎斯特采样定理

根据奈奎斯特采样定理,要准确重建一个模拟信号,采样频率必须至少是信号最高频率成分的 2 倍:

复制代码
fs ≥ 2 × fmax

在实际应用中,为了保证采样质量,通常采用更高的采样频率:

复制代码
fs ≥ 5 × fmax  // 工业控制应用

fs ≥ 10 × fmax // 高精度测量应用
3.1.2 采样频率计算
复制代码
/**

* @brief 根据信号频率计算最小采样频率

* @param signal_freq: 信号最高频率(Hz)

* @param application_type: 应用类型

* @return 推荐采样频率(Hz)

*/

uint32_t ADC_CalculateSampleFrequency(uint32_t signal_freq, ADC_ApplicationTypeDef application_type)

{

   switch (application_type)

   {

       case ADC_APPLICATION_GENERAL:

           return signal_freq * 5;

       case ADC_APPLICATION_PRECISE:

           return signal_freq * 10;

       case ADC_APPLICATION_FAST:

           return signal_freq * 3;

       default:

           return signal_freq * 5;

   }

}

3.2 分辨率与精度

3.2.1 分辨率计算

ADC 的分辨率决定了能够区分的最小电压变化:

复制代码
LSB = VREF / (2^N - 1)

其中:

  • N 为 ADC 位数(MM32F0144 为 12 位)

  • VREF 为参考电压(通常为 3.3V)

    /**

    • @brief 计算ADC分辨率

    • @param vref: 参考电压(V)

    • @param bits: ADC位数

    • @return 分辨率(mV/LSB)

    */

    float ADC_CalculateResolution(float vref, uint8_t bits)

    {

    复制代码
     return (vref * 1000.0f) / ((1 << bits) - 1);

    }

    // 示例:MM32F0144在3.3V参考电压下的分辨率

    float resolution = ADC_CalculateResolution(3.3f, 12);

    // resolution = 3300 / 4095 ≈ 0.806 mV/LSB

3.2.2 精度与误差

实际 ADC 的精度受到多种因素影响:

  • 量化误差:±0.5LSB 的固有误差

  • 积分非线性 (INL):±2LSB

  • 微分非线性 (DNL):±1LSB

  • 温度漂移:随温度变化的误差

  • 电源噪声:供电电压波动引起的误差

3.3 输入阻抗匹配

3.3.1 输入阻抗要求

MM32F0144 ADC 的输入阻抗典型值为 10kΩ,为了保证采样精度,信号源阻抗应满足:

复制代码
Rs ≤ 10kΩ / 10 = 1kΩ
3.3.2 阻抗匹配电路
复制代码
/**

* @brief 检查信号源阻抗是否合适

* @param source_impedance: 信号源阻抗(Ω)

* @return 是否合适

*/

bool ADC_CheckSourceImpedance(uint32_t source_impedance)

{

   const uint32_t MAX_ALLOWED_IMPEDANCE = 1000; // 1kΩ

   return (source_impedance <= MAX_ALLOWED_IMPEDANCE);

}

/**

* @brief 计算需要的缓冲电路增益

* @param source_impedance: 信号源阻抗(Ω)

* @return 建议的缓冲电路增益

*/

float ADC_CalculateBufferGain(uint32_t source_impedance)

{

   const uint32_t TARGET_IMPEDANCE = 1000; // 1kΩ

  

   if (source_impedance <= TARGET_IMPEDANCE)

   {

       return 1.0f; // 无需缓冲

   }

   else

   {

       // 需要电压跟随器缓冲

       return 1.0f;

   }

}

采样时间配置策略

4.1 采样时间计算

4.1.1 采样时间公式

MM32F0144 ADC 的采样时间可通过 SAMPR 寄存器配置,支持多种采样时间:

SAMPR 配置 采样时间 适用场景
000 1.5 个 ADC 时钟周期 快速采样,信号源阻抗低
001 7.5 个 ADC 时钟周期 一般应用
010 13.5 个 ADC 时钟周期 信号源阻抗较高
011 28.5 个 ADC 时钟周期 高阻抗信号源
100 41.5 个 ADC 时钟周期 极高阻抗信号源
101 55.5 个 ADC 时钟周期 电容性负载
110 71.5 个 ADC 时钟周期 特殊应用
111 239.5 个 ADC 时钟周期 最高精度要求
4.1.2 采样时间配置函数
复制代码
/**

* @brief 根据信号源阻抗配置采样时间

* @param source_impedance: 信号源阻抗(Ω)

*/

void ADC_ConfigSampleTimeByImpedance(uint32_t source_impedance)

{

   uint32_t sampr_value = 0;

  

   if (source_impedance <= 100)

   {

       sampr_value = 0x00; // 1.5周期

   }

   else if (source_impedance <= 1000)

   {

       sampr_value = 0x01; // 7.5周期

   }

   else if (source_impedance <= 10000)

   {

       sampr_value = 0x02; // 13.5周期

   }

   else

   {

       sampr_value = 0x03; // 28.5周期

   }

  

   ADC1->SAMPR = sampr_value;

}

/**

* @brief 根据信号频率配置采样时间

* @param signal_frequency: 信号频率(Hz)

*/

void ADC_ConfigSampleTimeByFrequency(uint32_t signal_frequency)

{

   uint32_t adc_clock = 12000000; // ADC时钟12MHz

   uint32_t min_sample_time = 1000000 / (signal_frequency * 10); // 最小采样时间

  

   uint32_t sample_cycles = (min_sample_time * adc_clock) / 1000000;

  

   uint32_t sampr_value;

   if (sample_cycles <= 1.5)

       sampr_value = 0x00;

   else if (sample_cycles <= 7.5)

       sampr_value = 0x01;

   else if (sample_cycles <= 13.5)

       sampr_value = 0x02;

   else if (sample_cycles <= 28.5)

       sampr_value = 0x03;

   else if (sample_cycles <= 41.5)

       sampr_value = 0x04;

   else if (sample_cycles <= 55.5)

       sampr_value = 0x05;

   else if (sample_cycles <= 71.5)

       sampr_value = 0x06;

   else

       sampr_value = 0x07;

  

   ADC1->SAMPR = sampr_value;

}

4.2 动态采样时间调整

4.2.1 自适应采样时间
复制代码
/**

* @brief 自适应调整采样时间

* @param channel: ADC通道

*/

void ADC_AdaptiveSampleTimeConfig(uint8_t channel)

{

   // 先使用最短采样时间测试

   ADC1->SAMPR = 0x00;

  

   // 连续采样多次

   uint32_t samples[10];

   for (int i = 0; i < 10; i++)

   {

       samples[i] = ADC_ReadChannel(channel);

       HAL_Delay(1);

   }

  

   // 计算采样值的标准差

   float std_dev = ADC_CalculateStandardDeviation(samples, 10);

  

   // 根据标准差调整采样时间

   if (std_dev > 5.0f) // 噪声较大

   {

       ADC1->SAMPR = 0x03; // 增加采样时间

   }

   else if (std_dev > 2.0f) // 噪声适中

   {

       ADC1->SAMPR = 0x01; // 中等采样时间

   }

   else // 噪声较小

   {

       ADC1->SAMPR = 0x00; // 保持最短采样时间

   }

}

/**

* @brief 计算采样数据的标准差

*/

float ADC_CalculateStandardDeviation(uint32_t *data, uint32_t count)

{

   if (count == 0) return 0.0f;

  

   // 计算平均值

   uint64_t sum = 0;

   for (uint32_t i = 0; i < count; i++)

   {

       sum += data[i];

   }

   float mean = (float)sum / count;

  

   // 计算方差

   float variance = 0.0f;

   for (uint32_t i = 0; i < count; i++)

   {

       float diff = data[i] - mean;

       variance += diff * diff;

   }

   variance /= count;

  

   // 计算标准差

   return sqrt(variance);

}
4.2.2 实时采样时间优化
复制代码
/**

* @brief 实时优化采样时间

*/

void ADC_RealTimeSampleTimeOptimization(void)

{

   static uint32_t last_optimization_time = 0;

   static uint32_t sample_time_config = 0x00;

  

   // 每100ms优化一次

   if (HAL_GetTick() - last_optimization_time < 100)

   {

       return;

   }

  

   last_optimization_time = HAL_GetTick();

  

   // 获取当前ADC配置

   uint32_t current_sampr = ADC1->SAMPR;

  

   // 测量当前配置下的噪声水平

   float noise_level = ADC_MeasureNoiseLevel();

  

   // 根据噪声水平调整采样时间

   if (noise_level > 10.0f) // 高噪声

   {

       if (current_sampr < 0x07)

       {

           sample_time_config = current_sampr + 1;

           ADC1->SAMPR = sample_time_config;

           ADC_LogInfo("Increased sample time to reduce noise");

       }

   }

   else if (noise_level < 2.0f) // 低噪声,可以加快采样

   {

       if (current_sampr > 0x00)

       {

           sample_time_config = current_sampr - 1;

           ADC1->SAMPR = sample_time_config;

           ADC_LogInfo("Decreased sample time for faster sampling");

       }

   }

}

输入信号调理电路

5.1 信号范围匹配

5.1.1 电压分压电路

当输入信号电压超出 ADC 的输入范围时,需要使用分压电路:

复制代码
/**

* @brief 计算分压电路参数

* @param input_voltage_range: 输入电压范围(V)

* @param vref: ADC参考电压(V)

* @param r1: 上拉电阻(Ω)

* @param r2: 下拉电阻(Ω)

*/

void ADC_CalculateVoltageDivider(float input_voltage_range, float vref,

                              uint32_t *r1, uint32_t *r2)

{

   // 分压比 = Vref / 输入电压范围

   float divider_ratio = vref / input_voltage_range;

  

   // 选择标准电阻值

   const uint32_t R2_STANDARD = 10000; // 10kΩ

   *r2 = R2_STANDARD;

  

   // R1 = R2 * (1/分压比 - 1)

   *r1 = (uint32_t)(R2_STANDARD * (1.0f / divider_ratio - 1.0f));

  

   // 调整到最接近的标准电阻值

   *r1 = ADC_GetNearestStandardResistor(*r1);

}

/**

* @brief 获取最接近的标准电阻值

*/

uint32_t ADC_GetNearestStandardResistor(uint32_t target)

{

   // E24系列标准电阻值

   const uint32_t standard_resistors[] = {

       100, 110, 120, 130, 150, 160, 180, 200, 220, 240, 270, 300,

       330, 360, 390, 430, 470, 510, 560, 620, 680, 750, 820, 910,

       1000, 1100, 1200, 1300, 1500, 1600, 1800, 2000, 2200, 2400, 2700, 3000,

       3300, 3600, 3900, 4300, 4700, 5100, 5600, 6200, 6800, 7500, 8200, 9100,

       10000, 11000, 12000, 13000, 15000, 16000, 18000, 20000, 22000, 24000, 27000, 30000,

       33000, 36000, 39000, 43000, 47000, 51000, 56000, 62000, 68000, 75000, 82000, 91000,

       100000, 110000, 120000, 130000, 150000, 160000, 180000, 200000, 220000, 240000, 270000, 300000

   };

  

   uint32_t nearest = standard_resistors[0];

   uint32_t min_diff = abs((int32_t)target - (int32_t)standard_resistors[0]);

  

   for (uint32_t i = 1; i < sizeof(standard_resistors)/sizeof(standard_resistors[0]); i++)

   {

       uint32_t diff = abs((int32_t)target - (int32_t)standard_resistors[i]);

       if (diff < min_diff)

       {

           min_diff = diff;

           nearest = standard_resistors[i];

       }

   }

  

   return nearest;

}
5.1.2 信号放大电路

对于小信号输入,需要使用运算放大器进行信号放大:

复制代码
/**

* @brief 计算信号放大电路参数

* @param input_signal_range: 输入信号范围(mV)

* @param target_range: 目标范围(mV)

* @param gain: 放大增益

*/

void ADC_CalculateAmplifierGain(float input_signal_range, float target_range, float *gain)

{

   *gain = target_range / input_signal_range;

  

   // 限制最大增益为100倍

   if (*gain > 100.0f)

   {

       *gain = 100.0f;

   }

   else if (*gain < 1.0f)

   {

       *gain = 1.0f;

   }

}

5.2 滤波电路设计

5.2.1 RC 低通滤波
复制代码
/**

* @brief 计算RC低通滤波器参数

* @param cutoff_frequency: 截止频率(Hz)

* @param r: 电阻值(Ω)

* @param c: 电容值(F)

*/

void ADC_CalculateRCFilter(float cutoff_frequency, float *r, float *c)

{

   // 选择标准电阻值

   const float R_STANDARD = 10000.0f; // 10kΩ

   *r = R_STANDARD;

  

   // 计算电容值:C = 1/(2πRC)

   *c = 1.0f / (2 * M_PI * cutoff_frequency * *r);

  

   // 转换为微法

   *c *= 1e6;

}

/**

* @brief 根据信号频率计算推荐截止频率

* @param signal_frequency: 信号频率(Hz)

* @return 推荐截止频率(Hz)

*/

float ADC_RecommendCutoffFrequency(float signal_frequency)

{

   // 截止频率 = 信号频率 * 2.5

   return signal_frequency * 2.5f;

}
5.2.2 有源滤波电路

对于要求较高的应用,建议使用有源滤波器:

复制代码
/**

* @brief 设计有源低通滤波器

* @param cutoff_frequency: 截止频率(Hz)

* @param q_factor: Q值

* @param filter_type: 滤波器类型

*/

void ADC_DesignActiveFilter(float cutoff_frequency, float q_factor, ADC_FilterTypeDef filter_type)

{

   float r1, r2, c1, c2;

  

   switch (filter_type)

   {

       case ADC_FILTER_SALLEN_KEY:

           // Sallen-Key低通滤波器设计

           r1 = 10000.0f; // 10kΩ

           r2 = 10000.0f; // 10kΩ

          

           // 计算电容值

           float wc = 2 * M_PI * cutoff_frequency;

           c1 = 1.0f / (wc * r1 * sqrt(2));

           c2 = 1.0f / (wc * r2 * sqrt(2));

          

           break;

          

       case ADC_FILTER_MULTISTAGE:

           // 多级滤波器设计

           // ...

           break;

          

       default:

           // 默认使用RC滤波器

           ADC_CalculateRCFilter(cutoff_frequency, &r1, &c1);

           break;

   }

  

   ADC_LogInfo("Filter design: R1=%.0fΩ, R2=%.0fΩ, C1=%.2fμF, C2=%.2fμF",

              r1, r2, c1*1e6, c2*1e6);

}

5.3 保护电路

5.3.1 过压保护
复制代码
/**

* @brief 设计过压保护电路

* @param max_input_voltage: 最大输入电压(V)

* @param clamp_voltage: 钳位电压(V)

*/

void ADC_DesignOvervoltageProtection(float max_input_voltage, float clamp_voltage)

{

   // 根据钳位电压选择TVS管

   float tvs_voltage = clamp_voltage + 0.5f; // 留出0.5V余量

  

   ADC_LogInfo("Overvoltage protection design:");

   ADC_LogInfo("TVS diode voltage: %.1fV", tvs_voltage);

   ADC_LogInfo("Series resistor: 100Ω (current limiting)");

   ADC_LogInfo("Input capacitance: <100pF");

}
5.3.2 静电防护
复制代码
/**

* @brief ESD防护设计

*/

void ADC_DesignESDProtection(void)

{

   ADC_LogInfo("ESD protection design:");

   ADC_LogInfo("ESD protection level: ±15kV (air discharge)");

   ADC_LogInfo("Recommended TVS: SMAJ6.5CA (bidirectional)");

   ADC_LogInfo("Series resistor: 50-100Ω");

   ADC_LogInfo("PCB layout: Keep protection components close to input connector");

}

软件采样算法

6.1 基础采样算法

6.1.1 单次采样
复制代码
/**

* @brief 单次ADC采样

* @param channel: ADC通道

* @return 采样值(12位)

*/

uint16_t ADC_SingleSample(uint8_t channel)

{

   // 选择ADC通道

   ADC1->CHSELR = 1 << channel;

  

   // 启动ADC转换

   ADC1->CR |= ADC_CR_ADSTART;

  

   // 等待转换完成

   while (!(ADC1->SR & ADC_SR_EOC));

  

   // 读取转换结果

   uint16_t adc_value = ADC1->DR;

  

   // 清除EOC标志

   ADC1->SR &= ~ADC_SR_EOC;

  

   return adc_value;

}

/**

* @brief 单次电压采样

* @param channel: ADC通道

* @return 电压值(V)

*/

float ADC_SingleVoltageSample(uint8_t channel)

{

   uint16_t adc_value = ADC_SingleSample(channel);

  

   // 转换为电压值

   float voltage = (adc_value * 3.3f) / 4095.0f;

  

   return voltage;

}
6.1.2 连续采样
复制代码
/**

* @brief 连续ADC采样

* @param channel: ADC通道

* @param samples: 采样次数

* @param buffer: 采样数据缓冲区

*/

void ADC_ContinuousSample(uint8_t channel, uint32_t samples, uint16_t *buffer)

{

   // 选择ADC通道

   ADC1->CHSELR = 1 << channel;

  

   // 启动连续转换

   ADC1->CR |= ADC_CR_ADSTART;

  

   for (uint32_t i = 0; i < samples; i++)

   {

       // 等待转换完成

       while (!(ADC1->SR & ADC_SR_EOC));

      

       // 读取转换结果

       buffer[i] = ADC1->DR;

      

       // 清除EOC标志

       ADC1->SR &= ~ADC_SR_EOC;

   }

  

   // 停止连续转换

   ADC1->CR &= ~ADC_CR_ADSTART;

}

6.2 滤波算法

6.2.1 平均值滤波
复制代码
/**

* @brief 平均值滤波

* @param channel: ADC通道

* @param samples: 采样次数

* @return 滤波后的电压值(V)

*/

float ADC_AverageFilter(uint8_t channel, uint32_t samples)

{

   uint64_t sum = 0;

  

   for (uint32_t i = 0; i < samples; i++)

   {

       sum += ADC_SingleSample(channel);

       HAL_Delay(1); // 简单的采样间隔

   }

  

   uint16_t average_value = sum / samples;

   float voltage = (average_value * 3.3f) / 4095.0f;

  

   return voltage;

}

/**

* @brief 滑动平均滤波

* @param channel: ADC通道

* @param window_size: 窗口大小

* @return 滤波后的电压值(V)

*/

float ADC_MovingAverageFilter(uint8_t channel, uint32_t window_size)

{

   static uint16_t sample_buffer[128];

   static uint32_t buffer_index = 0;

   static uint64_t sum = 0;

  

   // 读取新采样值

   uint16_t new_sample = ADC_SingleSample(channel);

  

   // 更新缓冲区和总和

   sum -= sample_buffer[buffer_index];

   sum += new_sample;

   sample_buffer[buffer_index] = new_sample;

  

   buffer_index = (buffer_index + 1) % window_size;

  

   // 计算平均值

   uint16_t average_value = sum / window_size;

   float voltage = (average_value * 3.3f) / 4095.0f;

  

   return voltage;

}
6.2.2 中值滤波
复制代码
/**

* @brief 中值滤波

* @param channel: ADC通道

* @param samples: 采样次数(建议为奇数)

* @return 滤波后的电压值(V)

*/

float ADC_MedianFilter(uint8_t channel, uint32_t samples)

{

   uint16_t *sample_buffer = (uint16_t *)malloc(samples * sizeof(uint16_t));

   if (sample_buffer == NULL)

   {

       return 0.0f;

   }

  

   // 采集数据

   for (uint32_t i = 0; i < samples; i++)

   {

       sample_buffer[i] = ADC_SingleSample(channel);

       HAL_Delay(1);

   }

  

   // 冒泡排序

   for (uint32_t i = 0; i < samples - 1; i++)

   {

       for (uint32_t j = 0; j < samples - i - 1; j++)

       {

           if (sample_buffer[j] > sample_buffer[j + 1])

           {

               uint16_t temp = sample_buffer[j];

               sample_buffer[j] = sample_buffer[j + 1];

               sample_buffer[j + 1] = temp;

           }

       }

   }

  

   // 取中值

   uint16_t median_value = sample_buffer[samples / 2];

   float voltage = (median_value * 3.3f) / 4095.0f;

  

   free(sample_buffer);

   return voltage;

}
6.2.3 加权平均滤波
复制代码
/**

* @brief 加权平均滤波

* @param channel: ADC通道

* @param weights: 权重数组

* @param weight_count: 权重数量

* @return 滤波后的电压值(V)

*/

float ADC_WeightedAverageFilter(uint8_t channel, const float *weights, uint32_t weight_count)

{

   uint16_t *samples = (uint16_t *)malloc(weight_count * sizeof(uint16_t));

   if (samples == NULL)

   {

       return 0.0f;

   }

  

   // 采集数据

   for (uint32_t i = 0; i < weight_count; i++)

   {

       samples[i] = ADC_SingleSample(channel);

       HAL_Delay(1);

   }

  

   // 计算加权平均值

   float weighted_sum = 0.0f;

   float total_weight = 0.0f;

  

   for (uint32_t i = 0; i < weight_count; i++)

   {

       weighted_sum += samples[i] * weights[i];

       total_weight += weights[i];

   }

  

   uint16_t weighted_average = weighted_sum / total_weight;

   float voltage = (weighted_average * 3.3f) / 4095.0f;

  

   free(samples);

   return voltage;

}

/**

* @brief 指数加权移动平均滤波

* @param channel: ADC通道

* @param alpha: 平滑系数(0-1)

* @return 滤波后的电压值(V)

*/

float ADC_ExponentialMovingAverage(uint8_t channel, float alpha)

{

   static float filtered_value = 0.0f;

   static bool first_sample = true;

  

   // 读取新采样值

   uint16_t new_sample = ADC_SingleSample(channel);

   float new_voltage = (new_sample * 3.3f) / 4095.0f;

  

   if (first_sample)

   {

       filtered_value = new_voltage;

       first_sample = false;

   }

   else

   {

       // EMA公式:filtered = alpha * new + (1 - alpha) * old

       filtered_value = alpha * new_voltage + (1.0f - alpha) * filtered_value;

   }

  

   return filtered_value;

}

6.3 高级采样算法

6.3.1 有效值采样
复制代码
/**

* @brief 有效值(RMS)采样

* @param channel: ADC通道

* @param sample_count: 采样次数

* @return 有效值(V)

*/

float ADC_RMSSample(uint8_t channel, uint32_t sample_count)

{

   uint64_t sum_of_squares = 0;

  

   for (uint32_t i = 0; i < sample_count; i++)

   {

       uint16_t sample = ADC_SingleSample(channel);

       sum_of_squares += (uint64_t)sample * sample;

       HAL_Delay(1);

   }

  

   // 计算平均值

   float mean_of_squares = (float)sum_of_squares / sample_count;

  

   // 计算平方根(RMS)

   float rms_value = sqrt(mean_of_squares);

  

   // 转换为电压

   float rms_voltage = (rms_value * 3.3f) / 4095.0f;

  

   return rms_voltage;

}
6.3.2 峰值检测
复制代码
/**

* @brief 峰值检测

* @param channel: ADC通道

* @param sample_count: 采样次数

* @param max_voltage: 最大值输出

* @param min_voltage: 最小值输出

*/

void ADC_PeakDetection(uint8_t channel, uint32_t sample_count,

                     float *max_voltage, float *min_voltage)

{

   uint16_t max_sample = 0;

   uint16_t min_sample = 4095;

  

   for (uint32_t i = 0; i < sample_count; i++)

   {

       uint16_t sample = ADC_SingleSample(channel);

      

       if (sample > max_sample)

       {

           max_sample = sample;

       }

      

       if (sample < min_sample)

       {

           min_sample = sample;

       }

      

       HAL_Delay(1);

   }

  

   *max_voltage = (max_sample * 3.3f) / 4095.0f;

   *min_voltage = (min_sample * 3.3f) / 4095.0f;

}
6.3.3 自适应滤波
复制代码
/**

* @brief 自适应滤波算法

* @param channel: ADC通道

* @param noise_threshold: 噪声阈值

* @return 滤波后的电压值(V)

*/

float ADC_AdaptiveFilter(uint8_t channel, float noise_threshold)

{

   static float previous_value = 0.0f;

   static uint32_t stable_count = 0;

  

   // 读取新采样值

   uint16_t new_sample = ADC_SingleSample(channel);

   float new_voltage = (new_sample * 3.3f) / 4095.0f;

  

   // 计算变化量

   float delta = fabs(new_voltage - previous_value);

  

   float filtered_value;

  

   if (delta > noise_threshold)

   {

       // 变化较大,可能是信号变化

       filtered_value = new_voltage;

       stable_count = 0;

   }

   else

   {

       // 变化较小,可能是噪声

       stable_count++;

      

       if (stable_count < 5)

       {

           // 不稳定,使用加权平均

           filtered_value = 0.3f * new_voltage + 0.7f * previous_value;

       }

       else

       {

           // 稳定,使用更强的滤波

           filtered_value = 0.1f * new_voltage + 0.9f * previous_value;

       }

   }

  

   previous_value = filtered_value;

   return filtered_value;

}

抗干扰设计

7.1 硬件抗干扰

7.1.1 电源滤波
复制代码
/**

* @brief 电源滤波设计

*/

void ADC_DesignPowerFilter(void)

{

   ADC_LogInfo("ADC power supply filter design:");

   ADC_LogInfo("VDDA filter: 10μF + 0.1μF capacitor parallel");

   ADC_LogInfo("VREF filter: 1μF + 0.01μF capacitor parallel");

   ADC_LogInfo("Power supply rejection ratio: ≥60dB");

   ADC_LogInfo("Recommended LDO: Low noise LDO with ≤10μV rms noise");

}
7.1.2 接地设计
复制代码
/**

* @brief ADC接地设计建议

*/

void ADC_DesignGrounding(void)

{

   ADC_LogInfo("ADC grounding design recommendations:");

   ADC_LogInfo("Separate analog and digital ground planes");

   ADC_LogInfo("Single point grounding for analog circuit");

   ADC_LogInfo("Keep analog ground traces short and wide");

   ADC_LogInfo("Avoid ground loops in analog section");

   ADC_LogInfo("Connect AGND to DGND at single point near power supply");

}

7.2 软件抗干扰

7.2.1 数字滤波
复制代码
/**

* @brief 软件数字滤波

* @param raw_data: 原始数据

* @param filter_type: 滤波器类型

* @param filter_param: 滤波器参数

* @return 滤波后的数据

*/

uint16_t ADC_DigitalFilter(uint16_t raw_data, ADC_FilterTypeDef filter_type, void *filter_param)

{

   static uint16_t filter_buffer[64];

   static uint32_t buffer_index = 0;

   static uint64_t sum = 0;

  

   switch (filter_type)

   {

       case ADC_FILTER_AVERAGE:

       {

           uint32_t sample_count = *(uint32_t *)filter_param;

          

           sum -= filter_buffer[buffer_index];

           sum += raw_data;

           filter_buffer[buffer_index] = raw_data;

          

           buffer_index = (buffer_index + 1) % sample_count;

          

           return sum / sample_count;

       }

      

       case ADC_FILTER_MEDIAN:

       {

           uint32_t sample_count = *(uint32_t *)filter_param;

           static uint16_t median_buffer[64];

          

           // 添加新数据

           for (uint32_t i = sample_count - 1; i > 0; i--)

           {

               median_buffer[i] = median_buffer[i - 1];

           }

           median_buffer[0] = raw_data;

          

           // 简单排序取中值

           uint16_t sorted_buffer[64];

           memcpy(sorted_buffer, median_buffer, sample_count * sizeof(uint16_t));

          

           for (uint32_t i = 0; i < sample_count - 1; i++)

           {

               for (uint32_t j = 0; j < sample_count - i - 1; j++)

               {

                   if (sorted_buffer[j] > sorted_buffer[j + 1])

                   {

                       uint16_t temp = sorted_buffer[j];

                       sorted_buffer[j] = sorted_buffer[j + 1];

                       sorted_buffer[j + 1] = temp;

                   }

               }

           }

          

           return sorted_buffer[sample_count / 2];

       }

      

       default:

           return raw_data;

   }

}
7.2.2 异常值检测
复制代码
/**

* @brief 异常值检测和处理

* @param sample_value: 采样值

* @param threshold: 异常阈值

* @return 处理后的值

*/

uint16_t ADC_OutlierDetection(uint16_t sample_value, uint16_t threshold)

{

   static uint16_t previous_values[10];

   static uint32_t value_index = 0;

   static uint16_t valid_value = 0;

  

   // 计算历史平均值

   uint64_t sum = 0;

   for (uint32_t i = 0; i < 10; i++)

   {

       sum += previous_values[i];

   }

   uint16_t average = sum / 10;

  

   // 检查是否为异常值

   if (abs((int32_t)sample_value - (int32_t)average) > threshold)

   {

       // 异常值,使用历史值

       ADC_LogWarning("Outlier detected: %d, using average: %d", sample_value, average);

       return valid_value;

   }

   else

   {

       // 正常值,更新历史记录

       previous_values[value_index] = sample_value;

       value_index = (value_index + 1) % 10;

       valid_value = sample_value;

       return sample_value;

   }

}

7.3 时序抗干扰

7.3.1 采样时序优化
复制代码
/**

* @brief 采样时序优化

* @param channel: ADC通道

* @param sample_interval: 采样间隔(ms)

* @return 采样值

*/

uint16_t ADC_OptimizedSample(uint8_t channel, uint32_t sample_interval)

{

   static uint32_t last_sample_time = 0;

  

   // 等待采样间隔

   while (HAL_GetTick() - last_sample_time < sample_interval);

  

   // 启动ADC转换

   uint16_t sample_value = ADC_SingleSample(channel);

  

   last_sample_time = HAL_GetTick();

  

   return sample_value;

}
7.3.2 同步采样
复制代码
/**

* @brief 同步采样

* @param channels: 通道数组

* @param channel_count: 通道数量

* @param samples: 采样结果数组

*/

void ADC_SynchronizedSample(uint8_t *channels, uint32_t channel_count, uint16_t *samples)

{

   // 配置ADC为扫描模式

   ADC1->CFGR1 |= ADC_CFGR1_SCAN;

   ADC1->CHSELR = 0;

  

   // 配置通道

   for (uint32_t i = 0; i < channel_count; i++)

   {

       ADC1->CHSELR |= 1 << channels[i];

   }

  

   // 启动ADC转换

   ADC1->CR |= ADC_CR_ADSTART;

  

   // 等待所有通道转换完成

   while (!(ADC1->SR & ADC_SR_EOC));

  

   // 读取转换结果

   for (uint32_t i = 0; i < channel_count; i++)

   {

       samples[i] = ADC1->DR;

   }

  

   // 清除EOC标志

   ADC1->SR &= ~ADC_SR_EOC;

  

   // 恢复单次模式

   ADC1->CFGR1 &= ~ADC_CFGR1_SCAN;

}

多通道采样管理

8.1 通道切换策略

8.1.1 扫描模式配置
复制代码
/**

* @brief 配置ADC扫描模式

* @param channels: 通道数组

* @param channel_count: 通道数量

*/

void ADC_ConfigScanMode(uint8_t *channels, uint32_t channel_count)

{

   // 使能扫描模式

   ADC1->CFGR1 |= ADC_CFGR1_SCAN;

  

   // 配置通道序列

   ADC1->CHSELR = 0;

   for (uint32_t i = 0; i < channel_count; i++)

   {

       ADC1->CHSELR |= 1 << channels[i];

   }

  

   // 配置连续转换

   ADC1->CFGR1 |= ADC_CFGR1_CONT;

  

   // 启动ADC

   ADC1->CR |= ADC_CR_ADSTART;

}

/**

* @brief 读取扫描模式数据

* @param channel_count: 通道数量

* @param data: 数据缓冲区

*/

void ADC_ReadScanData(uint32_t channel_count, uint16_t *data)

{

   // 等待转换完成

   while (!(ADC1->SR & ADC_SR_EOC));

  

   // 读取所有通道数据

   for (uint32_t i = 0; i < channel_count; i++)

   {

       data[i] = ADC1->DR;

   }

  

   // 清除EOC标志

   ADC1->SR &= ~ADC_SR_EOC;

}
8.1.2 轮询采样
复制代码
/**

* @brief 多通道轮询采样

* @param channels: 通道数组

* @param channel_count: 通道数量

* @param samples: 采样次数

* @param data: 数据缓冲区

*/

void ADC_MultiChannelPollingSample(uint8_t *channels, uint32_t channel_count,

                                uint32_t samples, uint16_t *data)

{

   for (uint32_t s = 0; s < samples; s++)

   {

       for (uint32_t c = 0; c < channel_count; c++)

       {

           uint32_t index = s * channel_count + c;

           data[index] = ADC_SingleSample(channels[c]);

       }

       HAL_Delay(1);

   }

}

8.2 优先级管理

8.2.1 通道优先级配置
复制代码
/**

* @brief ADC通道优先级管理

*/

typedef struct {

   uint8_t channel;

   uint8_t priority;

   bool enabled;

   uint32_t sample_interval;

   uint32_t last_sample_time;

} ADC_ChannelConfigTypeDef;

ADC_ChannelConfigTypeDef adc_channels[] = {

   {0, 1, true, 10},   // 通道0,高优先级,10ms采样间隔

   {1, 2, true, 50},   // 通道1,中优先级,50ms采样间隔

   {2, 3, true, 100},  // 通道2,低优先级,100ms采样间隔

};

/**

* @brief 优先级驱动的采样调度

*/

void ADC_PriorityScheduledSampling(void)

{

   uint32_t current_time = HAL_GetTick();

  

   // 按优先级排序采样

   for (int priority = 1; priority <= 3; priority++)

   {

       for (uint32_t i = 0; i < sizeof(adc_channels)/sizeof(adc_channels[0]); i++)

       {

           ADC_ChannelConfigTypeDef *channel = &adc_channels[i];

          

           if (channel->enabled && channel->priority == priority)

           {

               if (current_time - channel->last_sample_time >= channel->sample_interval)

               {

                   uint16_t sample_value = ADC_SingleSample(channel->channel);

                   ADC_ProcessSampleData(channel->channel, sample_value);

                   channel->last_sample_time = current_time;

               }

           }

       }

   }

}
8.2.2 动态优先级调整
复制代码
/**

* @brief 动态调整通道优先级

* @param channel: 通道号

* @param new_priority: 新优先级

*/

void ADC_DynamicPriorityAdjust(uint8_t channel, uint8_t new_priority)

{

   for (uint32_t i = 0; i < sizeof(adc_channels)/sizeof(adc_channels[0]); i++)

   {

       if (adc_channels[i].channel == channel)

       {

           adc_channels[i].priority = new_priority;

           ADC_LogInfo("Channel %d priority changed to %d", channel, new_priority);

           break;

       }

   }

}

/**

* @brief 根据信号变化调整采样频率

* @param channel: 通道号

* @param signal_change: 信号变化量

*/

void ADC_AdjustSampleRateBySignalChange(uint8_t channel, float signal_change)

{

   const float HIGH_CHANGE_THRESHOLD = 0.1f;  // 100mV

   const float LOW_CHANGE_THRESHOLD = 0.01f;   // 10mV

  

   for (uint32_t i = 0; i < sizeof(adc_channels)/sizeof(adc_channels[0]); i++)

   {

       if (adc_channels[i].channel == channel)

       {

           if (signal_change > HIGH_CHANGE_THRESHOLD)

           {

               // 信号变化大,提高采样频率

               adc_channels[i].sample_interval = 10; // 10ms

               ADC_DynamicPriorityAdjust(channel, 1);

           }

           else if (signal_change < LOW_CHANGE_THRESHOLD)

           {

               // 信号稳定,降低采样频率

               adc_channels[i].sample_interval = 100; // 100ms

               ADC_DynamicPriorityAdjust(channel, 3);

           }

           break;

       }

   }

}

8.3 数据同步

8.3.1 多通道数据同步
复制代码
/**

* @brief 多通道数据同步采集

* @param channels: 通道数组

* @param channel_count: 通道数量

* @param sync_data: 同步数据缓冲区

*/

void ADC_SynchronizedMultiChannelSample(uint8_t *channels, uint32_t channel_count,

                                      ADC_SyncData_TypeDef *sync_data)

{

   sync_data->timestamp = HAL_GetTick();

  

   // 使用定时器触发同步采样

   TIM2->CR2 |= TIM_CR2_MMS_1; // 定时器更新事件作为ADC触发源

  

   // 配置ADC外部触发

   ADC1->CFGR1 |= ADC_CFGR1_EXTSEL_0 | ADC_CFGR1_EXTSEL_1; // 选择TIM2触发

   ADC1->CFGR1 |= ADC_CFGR1_EXTTRIG;

  

   // 配置扫描模式

   ADC1->CFGR1 |= ADC_CFGR1_SCAN;

   ADC1->CHSELR = 0;

  

   for (uint32_t i = 0; i < channel_count; i++)

   {

       ADC1->CHSELR |= 1 << channels[i];

   }

  

   // 启动定时器

   TIM2->CR1 |= TIM_CR1_CEN;

  

   // 等待转换完成

   while (!(ADC1->SR & ADC_SR_EOC));

  

   // 读取数据

   for (uint32_t i = 0; i < channel_count; i++)

   {

       sync_data->channels[i].channel = channels[i];

       sync_data->channels[i].value = ADC1->DR;

       sync_data->channels[i].voltage = (sync_data->channels[i].value * 3.3f) / 4095.0f;

   }

  

   // 停止定时器

   TIM2->CR1 &= ~TIM_CR1_CEN;

  

   sync_data->channel_count = channel_count;

}

低功耗采样策略

9.1 低功耗模式配置

9.1.1 ADC 低功耗模式
复制代码
/**

* @brief 配置ADC低功耗模式

*/

void ADC_ConfigLowPowerMode(void)

{

   // 降低ADC时钟频率

   RCC->CFGR2 |= RCC_CFGR2_ADCPRE_0 | RCC_CFGR2_ADCPRE_1; // ADC时钟 = PCLK2 / 8

  

   // 配置采样时间为最长

   ADC1->SAMPR = 0x07; // 239.5个ADC时钟周期

  

   // 关闭ADC自动校准

   ADC1->CR &= ~ADC_CR_ADCAL;

  

   // 配置单次转换模式

   ADC1->CFGR1 &= ~ADC_CFGR1_CONT;

  

   ADC_LogInfo("ADC low power mode configured");

   ADC_LogInfo("ADC clock: 1.5MHz");

   ADC_LogInfo("Sample time: 239.5 cycles");

   ADC_LogInfo("Expected power consumption: <1mA");

}
9.1.2 休眠模式采样
复制代码
/**

* @brief 休眠模式下ADC采样

* @param channel: ADC通道

* @param sample_interval: 采样间隔(ms)

* @return 采样电压值(V)

*/

float ADC_SleepModeSample(uint8_t channel, uint32_t sample_interval)

{

   static uint32_t last_sample_time = 0;

   float voltage = 0.0f;

  

   uint32_t current_time = HAL_GetTick();

  

   if (current_time - last_sample_time >= sample_interval)

   {

       // 唤醒ADC

       ADC1->CR |= ADC_CR_ADEN;

       while (!(ADC1->SR & ADC_SR_ADRDY));

      

       // 执行采样

       uint16_t sample_value = ADC_SingleSample(channel);

       voltage = (sample_value * 3.3f) / 4095.0f;

      

       // 关闭ADC以节省功耗

       ADC1->CR |= ADC_CR_ADDIS;

       while (ADC1->CR & ADC_CR_ADDIS);

      

       last_sample_time = current_time;

   }

  

   // 进入休眠模式

   HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

  

   return voltage;

}

9.2 智能采样调度

9.2.1 基于阈值的采样
复制代码
/**

* @brief 基于阈值的智能采样

* @param channel: ADC通道

* @param threshold: 变化阈值(V)

* @return 采样值(V)

*/

float ADC_ThresholdBasedSampling(uint8_t channel, float threshold)

{

   static float previous_voltage = 0.0f;

   static bool first_sample = true;

  

   if (first_sample)

   {

       // 首次采样

       previous_voltage = ADC_SingleVoltageSample(channel);

       first_sample = false;

       return previous_voltage;

   }

  

   // 快速采样检查

   float current_voltage = ADC_SingleVoltageSample(channel);

  

   // 检查变化是否超过阈值

   if (fabs(current_voltage - previous_voltage) > threshold)

   {

       // 变化超过阈值,进行精确采样

       float accurate_voltage = ADC_AverageFilter(channel, 10);

       previous_voltage = accurate_voltage;

       return accurate_voltage;

   }

   else

   {

       // 变化较小,返回上次值

       return previous_voltage;

   }

}
9.2.2 自适应采样频率
复制代码
/**

* @brief 自适应采样频率调整

* @param channel: ADC通道

* @param min_interval: 最小间隔(ms)

* @param max_interval: 最大间隔(ms)

* @return 采样值(V)

*/

float ADC_AdaptiveRateSampling(uint8_t channel, uint32_t min_interval, uint32_t max_interval)

{

   static uint32_t sample_interval = 100; // 初始100ms

   static uint32_t last_sample_time = 0;

   static float previous_voltage = 0.0f;

  

   uint32_t current_time = HAL_GetTick();

  

   if (current_time - last_sample_time >= sample_interval)

   {

       float current_voltage = ADC_SingleVoltageSample(channel);

      

       // 计算变化率

       float delta = fabs(current_voltage - previous_voltage);

       float change_rate = delta / (sample_interval / 1000.0f); // V/s

      

       // 根据变化率调整采样间隔

       if (change_rate > 1.0f) // 变化较快

       {

           sample_interval = min_interval;

       }

       else if (change_rate < 0.1f) // 变化较慢

       {

           sample_interval = max_interval;

       }

       else // 线性调整

       {

           float ratio = (change_rate - 0.1f) / (1.0f - 0.1f);

           sample_interval = min_interval + (uint32_t)(ratio * (max_interval - min_interval));

       }

      

       previous_voltage = current_voltage;

       last_sample_time = current_time;

      

       return current_voltage;

   }

  

   return previous_voltage;

}

9.3 批量采样优化

9.3.1 批量采样策略
复制代码
/**

* @brief 批量采样优化

* @param channels: 通道数组

* @param channel_count: 通道数量

* @param batch_size: 批量大小

* @param batch_data: 批量数据缓冲区

*/

void ADC_BatchSampling(uint8_t *channels, uint32_t channel_count,

                     uint32_t batch_size, ADC_BatchData_TypeDef *batch_data)

{

   // 配置ADC为连续扫描模式

   ADC1->CFGR1 |= ADC_CFGR1_SCAN | ADC_CFGR1_CONT;

   ADC1->CHSELR = 0;

  

   for (uint32_t i = 0; i < channel_count; i++)

   {

       ADC1->CHSELR |= 1 << channels[i];

   }

  

   batch_data->timestamp = HAL_GetTick();

   batch_data->channel_count = channel_count;

   batch_data->sample_count = batch_size;

  

   // 启动ADC转换

   ADC1->CR |= ADC_CR_ADSTART;

  

   // 批量采集数据

   for (uint32_t s = 0; s < batch_size; s++)

   {

       for (uint32_t c = 0; c < channel_count; c++)

       {

           while (!(ADC1->SR & ADC_SR_EOC));

          

           uint32_t index = s * channel_count + c;

           batch_data->samples[index].channel = channels[c];

           batch_data->samples[index].value = ADC1->DR;

           batch_data->samples[index].voltage = (batch_data->samples[index].value * 3.3f) / 4095.0f;

       }

   }

  

   // 停止ADC转换

   ADC1->CR &= ~ADC_CR_ADSTART;

}

实战案例分析

10.1 电池电压监测案例

10.1.1 项目背景

某便携式设备需要监测锂电池电压(3.0V~4.2V),要求精度 ±1%,采样频率 1Hz,低功耗运行。

10.1.2 硬件设计
复制代码
/**

* @brief 电池电压监测硬件设计

*/

void BatteryMonitor_HWDesign(void)

{

   ADC_LogInfo("=== Battery Voltage Monitor Hardware Design ===");

  

   // 分压电路设计

   float input_voltage_range = 4.2f;

   float vref = 3.3f;

   uint32_t r1, r2;

  

   ADC_CalculateVoltageDivider(input_voltage_range, vref, &r1, &r2);

  

   ADC_LogInfo("Voltage divider: R1=%.0fΩ, R2=%.0fΩ", r1, r2);

   ADC_LogInfo("Divider ratio: %.2f", vref / input_voltage_range);

   ADC_LogInfo("Input impedance: %.0fΩ", r1 + r2);

  

   // 滤波电路设计

   float cutoff_frequency = 10.0f; // 10Hz

   float r, c;

   ADC_CalculateRCFilter(cutoff_frequency, &r, &c);

  

   ADC_LogInfo("RC filter: R=%.0fΩ, C=%.2fμF", r, c*1e6);

  

   // 保护电路设计

   ADC_DesignOvervoltageProtection(5.0f, 3.6f);

}
10.1.3 软件实现
复制代码
/**

* @brief 电池电压监测软件实现

*/

typedef struct {

   float voltage;

   float percentage;

   uint8_t status;

   uint32_t timestamp;

} BatteryStatus_TypeDef;

/**

* @brief 读取电池电压

* @return 电池状态

*/

BatteryStatus_TypeDef BatteryMonitor_ReadVoltage(void)

{

   BatteryStatus_TypeDef status;

   static float filtered_voltage = 3.7f; // 初始值

  

   // 分压系数(考虑10kΩ和8.2kΩ分压)

   const float divider_ratio = 8200.0f / (10000.0f + 8200.0f);

  

   // 多次采样求平均

   float raw_voltage = ADC_AverageFilter(ADC_CHANNEL_0, 20);

  

   // 计算实际电池电压

   float battery_voltage = raw_voltage / divider_ratio;

  

   // 应用低通滤波

   filtered_voltage = 0.1f * battery_voltage + 0.9f * filtered_voltage;

  

   // 计算电量百分比

   if (filtered_voltage >= 4.2f)

   {

       status.percentage = 100.0f;

       status.status = BATTERY_STATUS_FULL;

   }

   else if (filtered_voltage >= 3.7f)

   {

       // 3.7V到4.2V对应70%到100%

       status.percentage = 70.0f + (filtered_voltage - 3.7f) / (4.2f - 3.7f) * 30.0f;

       status.status = BATTERY_STATUS_NORMAL;

   }

   else if (filtered_voltage >= 3.3f)

   {

       // 3.3V到3.7V对应20%到70%

       status.percentage = 20.0f + (filtered_voltage - 3.3f) / (3.7f - 3.3f) * 50.0f;

       status.status = BATTERY_STATUS_LOW;

   }

   else

   {

       status.percentage = 0.0f;

       status.status = BATTERY_STATUS_EMPTY;

   }

  

   status.voltage = filtered_voltage;

   status.timestamp = HAL_GetTick();

  

   return status;

}

/**

* @brief 电池监测任务

*/

void BatteryMonitor_Task(void *pvParameters)

{

   ADC_ConfigLowPowerMode();

  

   for (;;)

   {

       BatteryStatus_TypeDef battery_status = BatteryMonitor_ReadVoltage();

      

       ADC_LogInfo("Battery Voltage: %.2fV (%.0f%%), Status: %d",

                  battery_status.voltage,

                  battery_status.percentage,

                  battery_status.status);

      

       // 根据电池状态调整系统行为

       if (battery_status.status == BATTERY_STATUS_LOW)

       {

           System_EnterLowPowerMode();

       }

       else if (battery_status.status == BATTERY_STATUS_EMPTY)

       {

           System_EnterPowerOffMode();

       }

      

       // 低功耗延时

       vTaskDelay(pdMS_TO_TICKS(1000));

   }

}

10.2 温度采集案例

10.2.1 项目背景

某工业设备需要监测环境温度(-40°C~+85°C),使用 NTC 热敏电阻,要求精度 ±0.5°C。

10.2.2 硬件设计
复制代码
/**

* @brief 温度采集硬件设计

*/

void TemperatureSensor_HWDesign(void)

{

   ADC_LogInfo("=== Temperature Sensor Hardware Design ===");

  

   // NTC热敏电阻电路设计

   float vcc = 3.3f;

   float r_ntc_nominal = 10000.0f; // 10kΩ @25°C

   float r_ref = 10000.0f; // 10kΩ参考电阻

  

   ADC_LogInfo("NTC circuit: VCC=%.1fV, R_NTC=%.0fΩ, R_REF=%.0fΩ",

              vcc, r_ntc_nominal, r_ref);

  

   // 计算温度系数

   float beta = 3950.0f; // B值

   float t0 = 25.0f + 273.15f; // 25°C in Kelvin

  

   ADC_LogInfo("NTC parameters: Beta=%.0fK, T0=%.2fK", beta, t0);

}
10.2.3 软件实现
复制代码
/**

* @brief NTC温度计算

* @param adc_value: ADC采样值

* @return 温度值(°C)

*/

float TemperatureSensor_CalculateTemperature(uint16_t adc_value)

{

   // NTC参数

   const float R_NTC_NOMINAL = 10000.0f; // 10kΩ @25°C

   const float R_REF = 10000.0f; // 10kΩ

   const float BETA = 3950.0f; // B值

   const float T0 = 25.0f + 273.15f; // 25°C in Kelvin

   const float VCC = 3.3f;

  

   // 转换为电压值

   float voltage = (adc_value * VCC) / 4095.0f;

  

   // 计算NTC电阻值

   float r_ntc = R_REF * (voltage / (VCC - voltage));

  

   // Steinhart-Hart方程计算温度

   float inv_t = 1.0f / T0 + (1.0f / BETA) * log(r_ntc / R_NTC_NOMINAL);

   float temperature_k = 1.0f / inv_t;

   float temperature_c = temperature_k - 273.15f;

  

   return temperature_c;

}

/**

* @brief 温度采集任务

*/

void TemperatureSensor_Task(void *pvParameters)

{

   static float temperature_history[10];

   static uint32_t history_index = 0;

  

   for (;;)

   {

       // 多次采样提高精度

       uint16_t adc_values[5];

       for (int i = 0; i < 5; i++)

       {

           adc_values[i] = ADC_SingleSample(ADC_CHANNEL_1);

           HAL_Delay(10);

       }

      

       // 中值滤波

       uint16_t median_value = ADC_CalculateMedian(adc_values, 5);

      

       // 计算温度

       float temperature = TemperatureSensor_CalculateTemperature(median_value);

      

       // 移动平均滤波

       temperature_history[history_index] = temperature;

       history_index = (history_index + 1) % 10;

      

       float avg_temperature = 0.0f;

       for (int i = 0; i < 10; i++)

       {

           avg_temperature += temperature_history[i];

       }

       avg_temperature /= 10;

      

       ADC_LogInfo("Temperature: %.2f°C (filtered: %.2f°C)",

                  temperature, avg_temperature);

      

       // 温度异常检测

       if (avg_temperature > 60.0f)

       {

           ADC_LogWarning("High temperature warning: %.2f°C", avg_temperature);

           Alarm_Activate(ALARM_HIGH_TEMPERATURE);

       }

       else if (avg_temperature < -20.0f)

       {

           ADC_LogWarning("Low temperature warning: %.2f°C", avg_temperature);

           Alarm_Activate(ALARM_LOW_TEMPERATURE);

       }

      

       vTaskDelay(pdMS_TO_TICKS(500));

   }

}

10.3 电流监测案例

10.3.1 项目背景

某电源设备需要监测输出电流(0~5A),使用分流电阻 + 运算放大器方案。

10.3.2 硬件设计
复制代码
/**

* @brief 电流监测硬件设计

*/

void CurrentSensor_HWDesign(void)

{

   ADC_LogInfo("=== Current Sensor Hardware Design ===");

  

   // 分流电阻设计

   float max_current = 5.0f; // 5A

   float v_ref = 3.3f;

   float r_shunt = 0.01f; // 10mΩ

  

   // 计算分流电压

   float v_shunt_max = max_current * r_shunt;

   ADC_LogInfo("Shunt resistor: %.3fΩ, Max voltage: %.3fV", r_shunt, v_shunt_max);

  

   // 放大器增益计算

   float gain = v_ref / (2 * v_shunt_max); // 单电源供电,需要偏置

   ADC_LogInfo("Amplifier gain: %.1f", gain);

  

   // 偏置电压

   float bias_voltage = v_ref / 2.0f;

   ADC_LogInfo("Bias voltage: %.2fV", bias_voltage);

}
10.3.3 软件实现
复制代码
/**

* @brief 电流计算

* @param adc_value: ADC采样值

* @return 电流值(A)

*/

float CurrentSensor_CalculateCurrent(uint16_t adc_value)

{

   // 硬件参数

   const float R_SHUNT = 0.01f; // 10mΩ

   const float AMPLIFIER_GAIN = 33.0f;

   const float BIAS_VOLTAGE = 1.65f; // 3.3V/2

   const float V_REF = 3.3f;

  

   // 转换为电压值

   float adc_voltage = (adc_value * V_REF) / 4095.0f;

  

   // 减去偏置电压

   float amplified_voltage = adc_voltage - BIAS_VOLTAGE;

  

   // 计算分流电压

   float shunt_voltage = amplified_voltage / AMPLIFIER_GAIN;

  

   // 计算电流

   float current = shunt_voltage / R_SHUNT;

  

   // 电流不能为负

   return (current < 0.0f) ? 0.0f : current;

}

/**

* @brief 有效值电流计算

* @return 有效值电流(A)

*/

float CurrentSensor_CalculateRMSCurrent(void)

{

   const uint32_t SAMPLE_COUNT = 100;

   uint16_t samples[SAMPLE_COUNT];

  

   // 采集数据

   for (uint32_t i = 0; i < SAMPLE_COUNT; i++)

   {

       samples[i] = ADC_SingleSample(ADC_CHANNEL_2);

       HAL_Delay(1);

   }

  

   // 计算RMS

   uint64_t sum_of_squares = 0;

   for (uint32_t i = 0; i < SAMPLE_COUNT; i++)

   {

       float current = CurrentSensor_CalculateCurrent(samples[i]);

       sum_of_squares += (uint64_t)(current * current * 1000000); // 放大避免精度损失

   }

  

   float mean_of_squares = (float)sum_of_squares / SAMPLE_COUNT / 1000000;

   float rms_current = sqrt(mean_of_squares);

  

   return rms_current;

}

/**

* @brief 电流监测任务

*/

void CurrentSensor_Task(void *pvParameters)

{

   for (;;)

   {

       float rms_current = CurrentSensor_CalculateRMSCurrent();

      

       ADC_LogInfo("RMS Current: %.2fA", rms_current);

      

       // 过流保护

       if (rms_current > 4.5f) // 4.5A过流阈值

       {

           ADC_LogError("Overcurrent detected: %.2fA", rms_current);

           Power_ShutdownOutput();

           Alarm_Activate(ALARM_OVERCURRENT);

       }

      

       vTaskDelay(pdMS_TO_TICKS(100));

   }

}

调试与验证方法

11.1 硬件调试

11.1.1 信号完整性测试
复制代码
/**

* @brief ADC信号完整性测试

*/

void ADC_SignalIntegrityTest(void)

{

   ADC_LogInfo("=== ADC Signal Integrity Test ===");

  

   // 测试点1:短路ADC输入到GND

   ADC_LogInfo("Test 1: ADC input shorted to GND");

   uint16_t gnd_samples[100];

   ADC_ContinuousSample(ADC_CHANNEL_0, 100, gnd_samples);

  

   uint16_t gnd_min = 4095, gnd_max = 0;

   for (int i = 0; i < 100; i++)

   {

       if (gnd_samples[i] < gnd_min) gnd_min = gnd_samples[i];

       if (gnd_samples[i] > gnd_max) gnd_max = gnd_samples[i];

   }

  

   ADC_LogInfo("GND input: min=%d, max=%d, range=%d", gnd_min, gnd_max, gnd_max - gnd_min);

  

   // 测试点2:短路ADC输入到VREF

   ADC_LogInfo("Test 2: ADC input shorted to VREF");

   uint16_t vref_samples[100];

   ADC_ContinuousSample(ADC_CHANNEL_0, 100, vref_samples);

  

   uint16_t vref_min = 4095, vref_max = 0;

   for (int i = 0; i < 100; i++)

   {

       if (vref_samples[i] < vref_min) vref_min = vref_samples[i];

       if (vref_samples[i] > vref_max) vref_max = vref_samples[i];

   }

  

   ADC_LogInfo("VREF input: min=%d, max=%d, range=%d", vref_min, vref_max, vref_max - vref_min);

  

   // 测试点3:测试线性度

   ADC_LogInfo("Test 3: Linearity test (connect potentiometer)");

   // 这里需要用户手动调节电位器

}
11.1.2 噪声水平测试
复制代码
/**

* @brief ADC噪声水平测试

* @param channel: ADC通道

* @return 噪声水平(mV)

*/

float ADC_MeasureNoiseLevel(uint8_t channel)

{

   const uint32_t SAMPLE_COUNT = 1000;

   uint16_t samples[SAMPLE_COUNT];

  

   // 采集数据

   ADC_ContinuousSample(channel, SAMPLE_COUNT, samples);

  

   // 计算统计信息

   uint64_t sum = 0;

   uint16_t min_val = 4095;

   uint16_t max_val = 0;

  

   for (uint32_t i = 0; i < SAMPLE_COUNT; i++)

   {

       sum += samples[i];

       if (samples[i] < min_val) min_val = samples[i];

       if (samples[i] > max_val) max_val = samples[i];

   }

  

   float mean = (float)sum / SAMPLE_COUNT;

  

   // 计算标准差

   float variance = 0.0f;

   for (uint32_t i = 0; i < SAMPLE_COUNT; i++)

   {

       float diff = samples[i] - mean;

       variance += diff * diff;

   }

   variance /= SAMPLE_COUNT;

   float std_dev = sqrt(variance);

  

   // 转换为电压

   float noise_level = std_dev * (3.3f / 4095.0f) * 1000.0f; // mV

  

   ADC_LogInfo("Noise level test results:");

   ADC_LogInfo("Samples: %d, Min: %d, Max: %d", SAMPLE_COUNT, min_val, max_val);

   ADC_LogInfo("Mean: %.1f, Std Dev: %.1f", mean, std_dev);

   ADC_LogInfo("Noise level: %.2f mV", noise_level);

  

   return noise_level;

}

11.2 软件调试

11.2.1 校准程序
复制代码
/**

* @brief ADC校准程序

*/

void ADC_CalibrationProcedure(void)

{

   ADC_LogInfo("=== ADC Calibration Procedure ===");

  

   // 内部校准

   ADC1->CR |= ADC_CR_ADCAL;

   while (ADC1->CR & ADC_CR_ADCAL);

  

   ADC_LogInfo("Internal calibration completed");

  

   // 外部校准(需要校准源)

   ADC_LogInfo("External calibration requires precision voltage source");

   ADC_LogInfo("Please connect 0V, 1.65V, and 3.3V to ADC input");

  

   // 等待用户确认

   HAL_Delay(5000);

  

   // 零点校准

   ADC_LogInfo("Calibrating zero point...");

   float zero_offset = ADC_AverageFilter(ADC_CHANNEL_0, 100);

  

   // 满量程校准

   ADC_LogInfo("Calibrating full scale...");

   float full_scale = ADC_AverageFilter(ADC_CHANNEL_0, 100);

  

   ADC_LogInfo("Zero offset: %.2f, Full scale: %.2f", zero_offset, full_scale);

  

   // 保存校准数据

   ADC_SaveCalibrationData(zero_offset, full_scale);

}
11.2.2 数据记录
复制代码
/**

* @brief ADC数据记录器

* @param channel: ADC通道

* @param duration: 记录时长(秒)

* @param filename: 文件名

*/

void ADC_DataLogger(uint8_t channel, uint32_t duration, const char *filename)

{

   FILE *file = fopen(filename, "w");

   if (file == NULL)

   {

       ADC_LogError("Failed to open data log file");

       return;

   }

  

   ADC_LogInfo("Starting data logging for %d seconds", duration);

  

   uint32_t start_time = HAL_GetTick();

  

   while (HAL_GetTick() - start_time < duration * 1000)

   {

       uint16_t adc_value = ADC_SingleSample(channel);

       float voltage = (adc_value * 3.3f) / 4095.0f;

       uint32_t timestamp = HAL_GetTick() - start_time;

      

       fprintf(file, "%d, %d, %.3fn", timestamp, adc_value, voltage);

      

       // 1ms采样间隔

       HAL_Delay(1);

   }

  

   fclose(file);

   ADC_LogInfo("Data logging completed. File: %s", filename);

}

11.3 性能验证

11.3.1 精度测试
复制代码
/**

* @brief ADC精度测试

* @param test_voltages: 测试电压数组

* @param voltage_count: 电压数量

* @return 最大误差

*/

float ADC_PrecisionTest(float *test_voltages, uint32_t voltage_count)

{

   ADC_LogInfo("=== ADC Precision Test ===");

  

   float max_error = 0.0f;

  

   for (uint32_t i = 0; i < voltage_count; i++)

   {

       float target_voltage = test_voltages[i];

      

       ADC_LogInfo("Testing %.2fV...", target_voltage);

      

       // 多次采样

       float measured_voltage = 0.0f;

       for (int j = 0; j < 50; j++)

       {

           measured_voltage += ADC_SingleVoltageSample(ADC_CHANNEL_0);

           HAL_Delay(10);

       }

       measured_voltage /= 50;

      

       // 计算误差

       float error = fabs(measured_voltage - target_voltage);

       float error_percent = (error / target_voltage) * 100.0f;

      

       ADC_LogInfo("Measured: %.3fV, Error: %.3fV (%.2f%%)",

                  measured_voltage, error, error_percent);

      

       if (error > max_error)

       {

           max_error = error;

       }

   }

  

   ADC_LogInfo("Maximum error: %.3fV", max_error);

  

   return max_error;

}
11.3.2 动态响应测试
复制代码
/**

* @brief ADC动态响应测试

* @param frequency: 信号频率(Hz)

* @return 响应时间(ms)

*/

float ADC_DynamicResponseTest(float frequency)

{

   ADC_LogInfo("=== ADC Dynamic Response Test ===");

   ADC_LogInfo("Testing response to %.1fHz signal", frequency);

  

   const uint32_t SAMPLE_COUNT = 1000;

   uint16_t samples[SAMPLE_COUNT];

  

   // 采集数据

   ADC_ContinuousSample(ADC_CHANNEL_0, SAMPLE_COUNT, samples);

  

   // 寻找上升沿

   uint32_t rising_edges[10];

   uint32_t edge_count = 0;

  

   for (uint32_t i = 1; i < SAMPLE_COUNT; i++)

   {

       if (samples[i] > 2048 && samples[i-1] <= 2048)

       {

           rising_edges[edge_count++] = i;

           if (edge_count >= 10) break;

       }

   }

  

   // 计算周期

   float avg_period = 0.0f;

   for (uint32_t i = 1; i < edge_count; i++)

   {

       avg_period += (rising_edges[i] - rising_edges[i-1]);

   }

   avg_period /= (edge_count - 1);

  

   float measured_frequency = 1000.0f / (avg_period * 1.0f); // 假设1ms采样间隔

  

   ADC_LogInfo("Measured frequency: %.1fHz", measured_frequency);

  

   // 计算相位延迟(需要参考信号)

   float phase_delay = 0.0f;

   // ...

  

   return phase_delay;

}

最佳实践与优化建议

12.1 硬件设计最佳实践

12.1.1 PCB 布局建议
复制代码
/**

* @brief ADC PCB布局建议

*/

void ADC_PCBLayoutGuidelines(void)

{

   ADC_LogInfo("=== ADC PCB Layout Guidelines ===");

  

   ADC_LogInfo("1. Analog Signal Routing:");

   ADC_LogInfo("   - Keep analog traces short and direct");

   ADC_LogInfo("   - Avoid running analog traces under digital components");

   ADC_LogInfo("   - Use wide traces (≥10mil) for analog signals");

   ADC_LogInfo("   - Maintain proper clearance from digital signals");

  

   ADC_LogInfo("n2. Grounding:");

   ADC_LogInfo("   - Separate analog and digital ground planes");

   ADC_LogInfo("   - Single point grounding for analog section");

   ADC_LogInfo("   - Connect AGND to DGND at power supply");

   ADC_LogInfo("   - Avoid ground loops in analog circuit");

  

   ADC_LogInfo("n3. Power Supply:");

   ADC_LogInfo("   - Place VDDA filters close to ADC");

   ADC_LogInfo("   - Use separate LDO for analog supply if possible");

   ADC_LogInfo("   - Keep power traces short and wide");

  

   ADC_LogInfo("n4. Component Placement:");

   ADC_LogInfo("   - Place signal conditioning components close to ADC");

   ADC_LogInfo("   - Keep protection components near input connector");

   ADC_LogInfo("   - Avoid placing high-speed digital components near ADC");

}
12.1.2 元件选型建议
复制代码
/**

* @brief ADC电路元件选型建议

*/

void ADC_ComponentSelectionGuidelines(void)

{

   ADC_LogInfo("=== ADC Component Selection Guidelines ===");

  

   ADC_LogInfo("1. Operational Amplifiers:");

   ADC_LogInfo("   - Low noise: ≤10nV/√Hz");

   ADC_LogInfo("   - High input impedance: ≥10MΩ");

   ADC_LogInfo("   - Bandwidth: ≥10MHz for signals up to 1MHz");

   ADC_LogInfo("   - Recommended: OP07, AD8605, MCP6001");

  

   ADC_LogInfo("n2. Resistors:");

   ADC_LogInfo("   - Precision: ±1% or better");

   ADC_LogInfo("   - Temperature coefficient: ≤100ppm/°C");

   ADC_LogInfo("   - Power rating: ≥1/8W for signal paths");

   ADC_LogInfo("   - Type: Metal film resistors preferred");

  

   ADC_LogInfo("n3. Capacitors:");

   ADC_LogInfo("   - Ceramic capacitors for decoupling (X7R/X5R)");

   ADC_LogInfo("   - Polypropylene for precision applications");

   ADC_LogInfo("   - Voltage rating: ≥2× working voltage");

  

   ADC_LogInfo("n4. Protection Devices:");

   ADC_LogInfo("   - TVS diodes: SMAJ6.5CA for 3.3V systems");

   ADC_LogInfo("   - ESD protection: ≥±15kV air discharge");

   ADC_LogInfo("   - Current limiting resistors: 50-100Ω");

}

12.2 软件设计最佳实践

12.2.1 初始化最佳实践
复制代码
/**

* @brief ADC初始化最佳实践

*/

void ADC_InitBestPractices(void)

{

   // 1. 时钟配置

   RCC->APB2ENR |= RCC_APB2ENR_ADCEN;

   RCC->CFGR2 &= ~RCC_CFGR2_ADCPRE;

   RCC->CFGR2 |= RCC_CFGR2_ADCPRE_0; // ADC时钟 = PCLK2 / 2

  

   // 2. GPIO配置

   GPIO_InitTypeDef GPIO_InitStruct;

   GPIO_InitStruct.Pin = GPIO_PIN_0;

   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;

   GPIO_InitStruct.Pull = GPIO_NOPULL;

   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  

   // 3. ADC校准

   ADC1->CR |= ADC_CR_ADCAL;

   while (ADC1->CR & ADC_CR_ADCAL);

  

   // 4. ADC配置

   ADC1->CFGR1 = 0;

   ADC1->CFGR1 |= ADC_CFGR1_RES_1;        // 12位分辨率

   ADC1->CFGR1 |= ADC_CFGR1_ALIGN;        // 左对齐

   ADC1->CFGR1 |= ADC_CFGR1_CONT;         // 连续转换模式

  

   // 5. 采样时间配置

   ADC1->SAMPR = ADC_SAMPR_SMP_1;         // 7.5个ADC时钟周期

  

   // 6. 通道配置

   ADC1->CHSELR = ADC_CHSELR_CHSEL0;      // 选择通道0

  

   // 7. 使能ADC

   ADC1->CR |= ADC_CR_ADEN;

   while (!(ADC1->SR & ADC_SR_ADRDY));

  

   ADC_LogInfo("ADC initialized with best practices");

}
12.2.2 数据处理最佳实践
复制代码
/**

* @brief ADC数据处理最佳实践

* @param raw_data: 原始ADC数据

* @return 处理后的电压值

*/

float ADC_DataProcessingBestPractice(uint16_t raw_data)

{

   static uint16_t calibration_data[3] = {0};

   static bool calibrated = false;

  

   if (!calibrated)

   {

       // 应用校准数据(从非易失性存储器读取)

       ADC_LoadCalibrationData(calibration_data);

       calibrated = true;

   }

  

   // 1. 应用零点校准

   int32_t calibrated_data = (int32_t)raw_data - calibration_data[0];

  

   // 2. 应用增益校准

   float gain_corrected = (float)calibrated_data * calibration_data[1] / calibration_data[2];

  

   // 3. 限制范围

   if (gain_corrected < 0) gain_corrected = 0;

   if (gain_corrected > 4095) gain_corrected = 4095;

  

   // 4. 转换为电压

   float voltage = (gain_corrected * 3.3f) / 4095.0f;

  

   return voltage;

}

12.3 性能优化建议

12.3.1 采样率优化
复制代码
/**

* @brief ADC采样率优化

* @param signal_frequency: 信号频率(Hz)

* @param required_precision: 要求精度(位)

* @return 优化后的采样率

*/

uint32_t ADC_OptimizeSampleRate(float signal_frequency, uint8_t required_precision)

{

   // 根据奈奎斯特定理计算最小采样率

   uint32_t min_sample_rate = (uint32_t)(signal_frequency * 2.5f);

  

   // 根据精度要求调整

   if (required_precision > 10)

   {

       min_sample_rate *= 2; // 高精度需要更高采样率

   }

  

   // 考虑ADC性能限制

   const uint32_t MAX_ADC_RATE = 1000000; // 1MHz

   if (min_sample_rate > MAX_ADC_RATE)

   {

       min_sample_rate = MAX_ADC_RATE;

   }

  

   ADC_LogInfo("Optimized sample rate: %d Hz for %.1f Hz signal, %d-bit precision",

              min_sample_rate, signal_frequency, required_precision);

  

   return min_sample_rate;

}
12.3.2 内存优化
复制代码
/**

* @brief ADC数据处理内存优化

* @param samples: 采样数据

* @param sample_count: 采样数量

* @param result: 处理结果

*/

void ADC_MemoryOptimizedProcessing(uint16_t *samples, uint32_t sample_count, float *result)

{

   // 使用单精度浮点减少内存占用

   float sum = 0.0f;

   float sum_squares = 0.0f;

  

   for (uint32_t i = 0; i < sample_count; i++)

   {

       float voltage = (samples[i] * 3.3f) / 4095.0f;

       sum += voltage;

       sum_squares += voltage * voltage;

   }

  

   result[0] = sum / sample_count; // 平均值

   result[1] = sqrt(sum_squares / sample_count); // RMS值

  

   // 复用内存,避免额外分配

   for (uint32_t i = 0; i < sample_count - 1; i++)

   {

       samples[i] = samples[i + 1];

   }

}
相关推荐
aini_lovee3 小时前
基于MATLAB/Simulink实现异步电机直接转矩控制(DTC)仿真
单片机·嵌入式硬件
oioihoii7 小时前
现代C++:一场静默的革命,告别“C with Classes”
c语言·jvm·c++
p66666666689 小时前
【☀Linux驱动开发笔记☀】新字符设备驱动开发_02
linux·嵌入式硬件·学习
q***99410 小时前
SocketTool、串口调试助手、MQTT中间件基础
单片机·嵌入式硬件·中间件
菜鸟-0111 小时前
IAP二级启动系统
单片机·嵌入式硬件
red watchma11 小时前
向量表偏移寄存器(Vector Table Offset Register,VTOR)
单片机·嵌入式硬件
万事可爱^11 小时前
GitHub爆火开源项目——RustScan深度拆解
c语言·开发语言·rust·开源·github·rustscan
NEU-UUN12 小时前
3.4.STM32-按键控制LED&光敏传感器控制蜂鸣器
stm32·单片机·嵌入式硬件
冉佳驹12 小时前
数据结构 ——— 八大排序算法的思想及其实现
c语言·数据结构·排序算法·归并排序·希尔排序·快速排序·计数排序