1. 硬件电路设计与选型要点搞过嵌入式开发的朋友都知道ADC采集看似简单但要做到高精度可不容易。我去年做电池管理系统时就踩过坑当时直接用STM32的ADC测12V电池电压结果误差大到离谱。后来才发现分压电路和运放的选型才是高精度采集的关键。先说分压电阻的选择。假设我们要测0-30V的直流电压常见的做法是用两个电阻串联分压。这里有个经验公式分压后的电压输入电压×R2/(R1R2)。但要注意三点电阻精度至少1%最好0.1%阻值建议在10kΩ-100kΩ之间太小会耗电太大会引入噪声功率要足够按PV²/R计算以实际案例来说我用的是10kΩ和100Ω电阻组合这样30V输入时Vout 30V × (100Ω / (10kΩ 100Ω)) ≈ 0.297V接下来是运放电路。LM2904这颗芯片我用了不下20次性价比超高。它有两个特点特别适合电压采集输入偏置电流仅45nA工作电压范围宽3V-32V典型电路可以这样搭// 非反相放大器配置 Rf 10kΩ // 反馈电阻 Rg 10kΩ // 接地电阻 增益 1 (Rf/Rg) 2倍这样之前0.297V的信号放大到0.594V正好在STM32的ADC量程内0-3.3V。2. STM32CubeMX配置详解打开CubeMX时新手常犯的错误就是时钟树配置不对。我建议先搞定时钟再弄外设否则ADC采样率会出问题。具体步骤2.1 时钟配置在Pinout界面使能HSE外部晶振转到Clock Configuration标签页按这个参数设置HCLK 168MHzAPB2 Prescaler /2ADC Prescaler /4 这样ADC时钟就是21MHz168/2/4符合手册要求。2.2 ADC参数设置ADC3的配置要特别注意这几个参数Resolution选12位4096级Scan Conversion ModeDisable单通道Continuous Conversion ModeEnableEnd Of Conversion SelectionEOC flag at the end of single conversionLow Power Auto WaitDisableSampling Time建议480 cycles这里有个坑采样时间不是越长越好。我实测发现对于LM2904输出的信号480 cycles能在速度和精度间取得最佳平衡。2.3 串口配置USART1的配置要点ModeAsynchronousBaud Rate115200Word Length8bitParityNoneStop Bits1Over Sampling16 Samples记得在Project Manager里勾选Generate peripheral initialization as a pair of .c/.h files这样代码结构更清晰。3. 代码实现关键技巧移植代码时最容易出问题的就是ADC校准和DMA配置。分享下我的实战经验3.1 ADC初始化优化在main.c的MX_ADC3_Init函数后添加校准代码HAL_ADCEx_Calibration_Start(hadc3, ADC_SINGLE_ENDED);这个校准过程能消除零点误差我测试过能使精度提高约0.5%。3.2 电压采集逻辑采集部分的代码要这样写才稳定#define ADC_SAMPLES 32 // 采样次数 float Get_Voltage(void) { uint32_t sum 0; for(int i0; iADC_SAMPLES; i){ HAL_ADC_Start(hadc3); if(HAL_ADC_PollForConversion(hadc3, 10) HAL_OK){ sum HAL_ADC_GetValue(hadc3); } HAL_Delay(1); } float voltage (sum * 3.3f) / (ADC_SAMPLES * 4096.0f); return voltage * 100; // 补偿100倍分压 }这个算法有三点优势多次采样取平均抑制随机噪声每次采样间隔1ms避开电源纹波最后乘以100是补偿之前的分压比3.3 串口输出优化在usart.c里重定向printf后建议用这个格式输出printf([%.1f] ADC:%.3fV - Input:%.2fV\r\n, HAL_GetTick()/1000.0f, adc_voltage, input_voltage);这样打印的信息包含时间戳、原始ADC值和换算后的电压值调试时一目了然。4. 调试与性能优化烧录完程序发现数据跳变别急我教你几招实测有效的调试方法4.1 硬件排查步骤先用万用表测量运放输出端电压如果与预期不符检查电阻值是否焊错用示波器看ADC输入引脚波形应该有平滑的直流信号如果看到毛刺要加滤波电容检查接地模拟地和数字地之间要加0Ω电阻或磁珠4.2 软件滤波算法单纯的平均滤波有时不够可以试试这个复合滤波算法#define FILTER_DEPTH 10 typedef struct { float buf[FILTER_DEPTH]; uint8_t index; } Filter_t; float Moving_Average_Filter(Filter_t* filter, float new_val) { filter-buf[filter-index] new_val; if(filter-index FILTER_DEPTH) { filter-index 0; } float sum 0; for(int i0; iFILTER_DEPTH; i){ sum filter-buf[i]; } return sum / FILTER_DEPTH; }这个滑动平均滤波我用了三年能有效抑制突发干扰。4.3 精度提升技巧要想达到0.1%的精度还需要在ADC输入端加0.1uF陶瓷电容使用稳压基准源代替3.3V供电在软件里做温度补偿STM32内部有温度传感器实测下来这套方案在-20℃~60℃环境下能将温漂控制在±0.3%以内。