基于STM32的ADC采样与滤波实现教程(含HAL库及VOFA)
/* USER CODE BEGIN 1 /
float t1 = 0;
float t2 = 0;
/ USER CODE END 1 */
…
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
t1 += 0.1;
t2 += 0.5;
printf("simples:%f, %f\n", sin(t1), sin(t2));
HAL_Delay(100);
}
/* USER CODE END 3 */
}
**1、选择串口通讯、端口号、波特率等参数设置;**

**2、去控件中选择波形图,拉入tab中,右键选择Y轴将2个输入I0与I1都选中,之后开启串口连接;**

**3、运行上位机,使用波形图控件读取下位机参数;**

>
> **补充:**
>
>
> 不难看出VOFA+的使用是非常简单快捷的,其自由度也是相当的高,关键还是**免费的**。**PID调参**,**无人机的姿态3D**显示等等都可以借助VOFA+实现, 希望该软件可以给读者朋友的日常嵌入式开发提供便捷与帮助。
>
>
>
## 三、CubeMX配置
**1、RCC配置外部高速晶振(精度更高)——HSE;**

**2、SYS配置:Debug设置成Serial Wire**(**否则可能导致芯片自锁**);

**3、UART1配置:使用串口通讯UART1与VOFA+上位机进行通讯显示;**

**4、ADC1配置:利用ADC1的通道IN1进行AD采样,保持独立模式;**

**5、时钟树配置:**

**6、工程配置:**

## 四、滤波算法与效果
>
> **受限于MCU自身的ADC外设缺陷,其精度和稳定性通常较差,很多场景下需要采取滤波补偿。**
> **滤波的作用就是减少噪声与干扰对数据测量的影响。**
>
>
>
### 4.1 未添加滤波算法
**重写printf函数:**
#include “stdio.h”
//重定义
int fputc(int c,FILE *stream)
{
uint8_t ch[1]={c};
HAL_UART_Transmit(&huart1,ch,1,0xFFFF);
return c;
}
**main函数:**
while(1){
HAL_ADC_Start(&hadc1); //开启ADC1,放置在while循环中
ADC_value=HAL_ADC_GetValue(&hadc1); //获取ADC1的数值
HAL_Delay(10); //延迟函数,防止采样失效
printf(“ADC_value:%d\n”, ADC_value);
}
**VOFA+读取到的数据:**

上图借助VOFA+上位机可以清楚看出未使用滤波的ADC采样波动还是比较明显的,但是作者主观干啥F1系列的ADC确实好像比F4系列的ADC稳定些。(**之所以不是4096可能是因为电源未达到3.3v**)
### 4.2 一阶互补滤波
>
> 方法:取a=0~1,本次滤波结果=(1-a)本次采样值+a上次滤波结果
> 优点:对周期性干扰具有良好的抑制作用适用于波动频率较高的场合
> 缺点:相位滞后,灵敏度低滞后程度取决于a值大小不能消除滤波频率高于采样频率的1/2的干扰信号
>
>
>
//一阶互补滤波
int firstOrderFilter(int newValue, int oldValue, float a)
{
return a * newValue + (1-a) * oldValue;
}
ADC_value=HAL_ADC_GetValue(&hadc1); //获取ADC1的数值
//主函数
while(1){
HAL_ADC_Start(&hadc1); //开启ADC1,放置在while循环中
Filtering_Value = firstOrderFilter(HAL_ADC_GetValue(&hadc1),ADC_value,0.3); //滤波算法
HAL_Delay(10); //延迟函数,防止采样失效
printf(“ADC_value:%d\n”, ADC_value);
}
**VOFA+软件的效果图:**

>
> 一阶互补滤波的局限性还是很大的,效果非常一般。
>
>
>
### 4.3 中位值滤波
>
> 方法:连续采样N次(N取奇数)把N次采样值按大小排列取中间值为本次有效值
> 优点:能有效克服因偶然因素引起的波动干扰;对温度、液位等变化缓慢的被测参数有良好的滤波效果
> 缺点:对流量,速度等快速变化的参数不宜
>
>
>
//中值滤波算法
int middleValueFilter(int N)
{
int value_buf[N];
int i,j,k,temp;
for( i = 0; i < N; ++i)
{
value_buf[i] = HAL_ADC_GetValue(&hadc1);
}
for(j = 0 ; j < N-1; ++j)
{
for(k = 0; k < N-j-1; ++k)
{
//从小到大排序,冒泡法排序
if(value_buf[k] > value_buf[k+1])
{
temp = value_buf[k];
value_buf[k] = value_buf[k+1];
value_buf[k+1] = temp;
}
}
}
return value_buf[(N-1)/2];
}
**VOFA+软件的效果图:**

>
> 中值滤波对消除异常值和平稳化AD采样都具有十分有效的结果。
>
>
>
### 4.4 算术平均滤波
>
> 方法:连续取N个采样值进行算术平均运算;
> N值较大时:信号平滑度较高,但灵敏度较低
> N值较小时:信号平滑度较低,但灵敏度较高
> N值的选取:一般流量,N=12;压力:N=4
> 优点:试用于对一般具有随机干扰的信号进行滤波。这种信号的特点是有一个平均值,信号在某一数值范围附近上下波动。
> 缺点:测量速度较慢或要求数据计算较快的实时控制不适用。
>
>
>
//算术平均值滤波
int averageFilter(int N)
{
int sum = 0;
short i;
for(i = 0; i < N; ++i)
{
sum += HAL_ADC_GetValue(&hadc1);
}
return sum/N;
}
**VOFA+软件的效果图:**

>
> 算术平均滤波表现出了一定的平稳性,同时具有波动的伴随性(合理选择N值可能达到很好的效果)。
>
>
>
### 4.5 滑动平均滤波
>
> 方法:把连续取N个采样值看成一个队列,队列的长度固定为N。每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据(先进先出原则)。把队列中的N个数据进行算术平均运算,就可获得新的滤波结果。
> N值的选取:流量,N=12;压力:N=4;液面,N=4~12;温度,N=1~4
> 优点:对周期性干扰有良好的抑制作用,平滑度高;试用于高频振荡的系统
> 缺点:灵敏度低;对偶然出现的脉冲性干扰的抑制作用较差,不适于脉冲干扰较严重的场合
> 比较浪费RAM(改进方法,减去的不是队首的值,而是上一次得到的平均值)
>
>
>
//平滑均值滤波
#define N 10
int value_buf[N];
int sum=0;
int curNum=0;
int moveAverageFilter()
{
if(curNum < N)
{
value_buf[curNum] = HAL_ADC_GetValue(&hadc1);
sum += value_buf[curNum];
curNum++;
return sum/curNum;
}
else
{
sum -= sum/N;
sum += HAL_ADC_GetValue(&hadc1);
return sum/N;
}
}
**VOFA+软件的效果图:**

>
> 平滑均值滤波相较于普通的算术平均滤波,突出一个平滑特性。可以从上述VOFA+的波形图看出,平滑滤波可以有效抵消AD采样的刺噪并稳定化采集(**据作者同门实战反应平滑滤波的效果还是非常好的,尤其在控制方面**)。
>
>
>
### 4.6 限幅平均滤波
>
> 方法:相当于“限幅滤波法”+“递推平均滤波法”
> 每次采样到的新数据先进行限幅处理再送入队列进行递推平均滤波处理
> 优点:对于偶然出现的脉冲性干扰,可消除有其引起的采样值偏差。
> 缺点:比较浪费RAM
>
>
>
//限幅平均滤波
#define A 50 //限制幅度阈值
#define M 12
int data[M];
int First_flag=0;
int LAverageFilter()
{
int i;
int temp,sum,flag=0;
data[0]=HAL_ADC_GetValue(&hadc1);
for(i=1;i<M;i++)
{
temp=HAL_ADC_GetValue(&hadc1);
if((temp-data[i-1])>A||((data[i-1]-temp)>A))
{
i–;flag++;
}
else
{
data[i]=temp;
}
}
for(i=0;i<M;i++)
{
sum+=data[i];
}
return sum/M;
}
**VOFA+软件的效果图:**

>
> 限幅平均滤波类似于缝合怪,但是效果是非常显著的,它有效的解决了实际场景下突变噪声对AD采样的影响,但是消耗内存。
>
>
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**



**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**


**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**
<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />
# 最后
**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**
**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**
[外链图片转存中...(img-bwgcLeoA-1712384043595)]
[外链图片转存中...(img-AB6daEP0-1712384043596)]
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**
<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />
# 最后
**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**
**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**
**[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
作者:2401_84010497