uint16_t ADC_IN_1(void) //ADC采集程序 { HAL_ADC_Start(hadc1);//开始ADC采集 HAL_ADC_PollForConversion(hadc1,500);//等待采集结束 if(HAL_IS_BIT_SET(HAL_ADC_GetState(hadc1), HAL_ADC_STATE_REG_EOC))//读取ADC完成标志位 { return HAL_ADC_GetValue(hadc1);//读出ADC数值 } return 0; } uint16_t ADC_IN_2(void) //ADC采集程序 { HAL_ADC_Start(hadc2);//开始ADC采集 HAL_ADC_PollForConversion(hadc2,500);//等待采集结束 if(HAL_IS_BIT_SET(HAL_ADC_GetState(hadc2), HAL_ADC_STATE_REG_EOC))//读取ADC完成标志位 { return HAL_ADC_GetValue(hadc2);//读出ADC数值 } return 0; }滤波/******************************************************************************************************************************************** *------------------------------------------------------ADC数字滤波案例程序-----下 *******************************************************************************************************************************************/ /* *一、方案 1滑动平均滤波抑制随机噪声 *适用场景ADC 值存在小幅随机波动如原始值跳动 10-20LSB无明显脉冲干扰。 *原理采集 N 次数据保存最近 N 个值计算它们的平均值每次更新时剔除最旧值加入最新值平滑波动。 * */ // 1. 定义滤波参数可根据需求调整 #define FILTER_SAMPLE_NUM 5 // 滤波采集次数建议5/7/9奇数偶数均可 #define ADC_MAX_VALUE 4095// ADC最大量程12位ADC // 2. ADC1滑动平均滤波函数 uint16_t ADC_IN_1_Filtered(void) { //静态变量的使用滑动平均滤波中的数组用 static 修饰确保每次调用函数时保留历史数据不被重新初始化。 static uint16_t adc_buf[FILTER_SAMPLE_NUM] {0}; // 静态数组保存最近N次ADC值不丢失数据 static uint8_t buf_idx 0; // 静态索引标记当前要更新的数组位置 uint32_t sum 0; // 总和用32位避免溢出 uint8_t i; // 步骤1采集1次新值存入数组替换最旧值 adc_buf[buf_idx] ADC_IN_1(); // 调用原有的ADC_IN_1获取单次值 //adc_buf[buf_idx] adc_val[0]; buf_idx (buf_idx 1) % FILTER_SAMPLE_NUM; // 索引循环0→1→...→N-1→0 // 步骤2计算数组中所有值的总和 for (i 0; i FILTER_SAMPLE_NUM; i) { sum adc_buf[i]; } // 步骤3返回平均值总和/次数 return (uint16_t)(sum / FILTER_SAMPLE_NUM); } // 3. ADC2滑动平均滤波函数与ADC1逻辑完全一致仅替换ADC_IN_2 uint16_t ADC_IN_2_Filtered(void) { static uint16_t adc_buf[FILTER_SAMPLE_NUM] {0}; static uint8_t buf_idx 0; uint32_t sum 0; uint8_t i; adc_buf[buf_idx] ADC_IN_2(); //adc_buf[buf_idx] adc_val[1]; buf_idx (buf_idx 1) % FILTER_SAMPLE_NUM; for (i 0; i FILTER_SAMPLE_NUM; i) { sum adc_buf[i]; } return (uint16_t)(sum / FILTER_SAMPLE_NUM); } /* *二、方案 2中值滤波抑制脉冲干扰 *适用场景ADC 值偶尔出现大幅跳变如突然从 2000 跳到 3000或降到 0即脉冲干扰。 *原理采集 N 次数据N 为奇数排序后取中间值可直接剔除最大 / 最小值这类异常值。 * */ // 1. 定义滤波参数N必须为奇数如5/7/9 #define MEDIAN_SAMPLE_NUM 5 // 中值滤波采集次数奇数 // 2. 辅助函数对数组排序冒泡排序简单高效适合小数组 static void Array_Sort(uint16_t arr[], uint8_t len) { uint8_t i, j; uint16_t temp; for (i 0; i len - 1; i) { for (j 0; j len - 1 - i; j) { if (arr[j] arr[j 1]) { // 交换值从小到大排序 temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } } // 3. ADC1中值滤波函数 uint16_t ADC_IN_1_MedianFilter(void) { uint16_t adc_buf[MEDIAN_SAMPLE_NUM] {0}; uint8_t i; // 步骤1采集N次数据存入数组 for (i 0; i MEDIAN_SAMPLE_NUM; i) { adc_buf[i] ADC_IN_1(); //adc_buf[i] adc_val[0]; // 可选添加短延时避免ADC连续采集过快导致的误差 HAL_Delay(1); } // 步骤2对数组排序 Array_Sort(adc_buf, MEDIAN_SAMPLE_NUM); // 步骤3返回中间值索引为 len/2整数除法自动取整 return adc_buf[MEDIAN_SAMPLE_NUM / 2]; } // 4. ADC2中值滤波函数替换ADC_IN_2即可 uint16_t ADC_IN_2_MedianFilter(void) { uint16_t adc_buf[MEDIAN_SAMPLE_NUM] {0}; uint8_t i; for (i 0; i MEDIAN_SAMPLE_NUM; i) { adc_buf[i] ADC_IN_2(); //adc_buf[i] adc_val[1]; HAL_Delay(1); } Array_Sort(adc_buf, MEDIAN_SAMPLE_NUM); return adc_buf[MEDIAN_SAMPLE_NUM / 2]; } /* *三、方案 3复合滤波先中值后平均兼顾两种干扰 *适用场景ADC 同时存在随机噪声和脉冲干扰最常见场景。 *原理先通过中值滤波剔除脉冲异常值再对中值滤波后的结果进行滑动平均兼顾 “抗脉冲” 和 “平滑随机噪声” 的需求。 * */ // 1. 复用前两种方案的参数和辅助函数Array_Sort、FILTER_SAMPLE_NUM、MEDIAN_SAMPLE_NUM // 建议参数MEDIAN_SAMPLE_NUM5FILTER_SAMPLE_NUM5 // 2. ADC1复合滤波函数先中值后滑动平均 uint16_t ADC_IN_1_CompositeFilter(void) { static uint16_t avg_buf[FILTER_SAMPLE_NUM] {0}; // 保存中值滤波后的结果 static uint8_t avg_idx 0; uint32_t sum 0; uint8_t i; uint16_t median_val; // 中值滤波结果 // 步骤1先做1次中值滤波得到1个稳定值 median_val ADC_IN_1_MedianFilter(); // 步骤2将中值结果存入滑动平均数组 avg_buf[avg_idx] median_val; avg_idx (avg_idx 1) % FILTER_SAMPLE_NUM; // 步骤3计算滑动平均 for (i 0; i FILTER_SAMPLE_NUM; i) { sum avg_buf[i]; } return (uint16_t)(sum / FILTER_SAMPLE_NUM); } // 3. ADC2复合滤波函数 uint16_t ADC_IN_2_CompositeFilter(void) { static uint16_t avg_buf[FILTER_SAMPLE_NUM] {0}; static uint8_t avg_idx 0; uint32_t sum 0; uint8_t i; uint16_t median_val; median_val ADC_IN_2_MedianFilter(); avg_buf[avg_idx] median_val; avg_idx (avg_idx 1) % FILTER_SAMPLE_NUM; for (i 0; i FILTER_SAMPLE_NUM; i) { sum avg_buf[i]; } return (uint16_t)(sum / FILTER_SAMPLE_NUM); } /******************************************************************************************************************************************** *------------------------------------------------------ADC数字滤波案例程序-----上 *******************************************************************************************************************************************/显示void WU_ADC_TestDisplay(void) { LED_GREEN_TogglePin; WU_OLED_U8G2_ClearBuffer(); WU_OLED_U8G2_Printf(0,15,CHINA,原始值1号: %d,ADC_IN_1_CompositeFilter()); WU_OLED_U8G2_Printf(0,30,CHINA,原始值2号: %d,ADC_IN_2_CompositeFilter()); WU_OLED_U8G2_Printf(0,45,CHINA,电压值: %.3f V,ADC_IN_2_CompositeFilter() * 3.3f / 4095); WU_OLED_U8G2_SendBuffer(); }参考资料1. STM32 ADC外设开发手册2. 数字滤波算法相关教程本文为个人STM32开发实践笔记仅供学习交流使用。