STM32 CubeMx(四)ADC采样及简单的均值、中值、众数滤波方法

本文详细介绍了STM32F4的ADC采样原理,包括12位逐次逼近型ADC的特性,并通过STM32F4的ADC读取内部温度传感器和光敏传感器的实验,展示了不同滤波方法(均值、中值、众数)的应用。实验结果显示,众数滤波在消除噪声方面表现最佳。同时,文章还探讨了ADC精度问题以及卡尔曼滤波在后续实验中的潜在应用。
摘要由CSDN通过智能技术生成

1.ADC采样

1.1 ADC采样原理

我们知道单片机是数字芯片,只认识由0和1组成的逻辑序列,但是我们现实当中有很多模拟的物理量,如温度,这些模拟量该如何被单片机系统处理呢,这就会用到AD转换,AD转换的英文就是Analog to Digital ,由模拟量转化为数字量;而DA,则为Digital to Analog,数字量转化为模拟量。那单片机是如何实现转化的呢?

AD转换芯片上的数据手册上都会告诉你一个信息,这个芯片是8位的,这个芯片是10位,还有12位的,16的。这就代表着单片机AD采样后所能得到的最大值。如何AD采样时8位的那对应的值就为0-255,10位对应的值为0-1023,12位对应的值就为0-4095。对于一个12位AD转换芯片而言,如果输入电压为0,那单片机读到的就是0,如果输入电压是VCC,那单片机读到的就是4095,已经知道了这两个点(0,0),(VCC,4095),根据两点就可以确定一个公式,这时候你就可以求出任意电压值所对应的数字量是多少了

1.2 STM32F4 ADC简介

来自原子哥STM32开发指南HAL库版本。

STM32F4xx 系列一般都有 3 个 ADC,这些 ADC 可以独立使用,也可以使用双重/三重模式(提高采样率)。 STM32F4 的 ADC 是 12 位逐次逼近型的模拟数字转换器。 它有 19 个通道,可测量 16 个外部源、 2 个内部源和 Vbat 通道的信号。 这些通道的 A/D 转换可以单次、连续、扫描或间断模式执行。 ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。

ADC 电源要求:全速运行时为 2.4 V 到 3.6 V,慢速运行时为 1.8 V。但是一定别接到 5V 上面去,否则可能烧坏 ADC!
数电小知识: ADC 是12位逐次逼近型模数转换器,输出数值范围是 0 ~ 2^12 -1(0 ~ 4095),满量程是 3.3V ,分辨率就是最低有效位(LSB)的对应输入电压值。分辨率 =3300/4095 ≈ 0.806mV

STM32F407ZGT6 包含有 3 个 ADC。 STM32F4 的 ADC 最大的转换速率为 2.4Mhz,也就是转换时间为 0.41us (在 ADCCLK=36M,采样周期为 3 个 ADC 时钟下得到),不要让 ADC 的时钟超过 36M,否则将导致结果准确度下降。

STM32F4 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。
在这里插入图片描述
关于模式配置,过于复杂,而且平时基本的使用不会涉及到太多,所以没有做过多理解。

1.3 工程配置

配置工程读取摁键KEY_UP按下时的电压值。
1.开启ADC1的IN1
在这里插入图片描述
可以看ADC的IN1对应的IO口是PA1。
在这里插入图片描述

2.开启串口1来接收读取到的数据。
在这里插入图片描述
3.使能GPIO_PA0。
并将采样通道PA1,接入到PA0。
在这里插入图片描述

2. 滤波代码的编写

对于读取的模拟量肯定要进行滤波,不然模拟量变化过快无法使用。
滤波的作用就是减少噪声与干扰对数据测量的影响。

2.0 重写printf函数

#include "stdio.h"
int fputc(int c,FILE *stream)
{
	uint8_t ch[1]={c};
	HAL_UART_Transmit(&huart1,ch,1,0xFFFF);
	return c;
}

2.1 未添加滤波代码和现象

		uint16_t ADC_value;
		HAL_ADC_Start(&hadc1);//开启ADC1的采样,要放在while中,一直开启
		ADC_value=HAL_ADC_GetValue(&hadc1);//得到采样值
		HAL_Delay(10);//采完样之后加一个小段的延时,防止数据未被记录
		printf("ADC_value = %d\r\n", ADC_value);
		HAL_Delay(500);

串口助手读取到的数据:
在这里插入图片描述
可见没有按键摁下时,依然会读到较高电压值。可能是存在上拉电阻、电磁场干扰或者按键抖动之类的问题干扰读数。
在这里插入图片描述
特别注意: STM32F4 的 ADC 精度貌似不怎么好, ADC 引脚直接接 GND,都可以读到十几的数值,相比 STM32F103 来说,要差了一些,在使用的时候,请大家注意下这个问题。

在这里插入图片描述
摁下摁键后,也不全读数为4095,可见ADC采样精度一般。

2.2 添加均值滤波和现象

均值滤波的思路就是将一段时间内读取到的数据求和取平均,可以有效的消去抖动。

		uint16_t Last_ADC_Value;
		uint16_t ADC_Value;

		HAL_ADC_Start(&hadc1);//启动adc转化
		Last_ADC_Value = HAL_ADC_GetValue(&hadc1);	
		HAL_Delay(10);//采完样之后加一个小段的延时,防止数据未被记录		
		for(uint8_t i = 10;i>1;i--)
		{
			ADC_Value = HAL_ADC_GetValue(&hadc1);	
			HAL_Delay(10);
			Last_ADC_Value = ADC_Value + Last_ADC_Value;
		}
		Last_ADC_Value = Last_ADC_Value/10;
		printf("ADC_value = %d\r\n", Last_ADC_Value);
		HAL_Delay(500);

串口助手读取到的数据:
在这里插入图片描述
在这里插入图片描述
可以看到均值滤波对接地的情况并没有很好的处理效果。

2.3 添加中值滤波和现象

均值滤波的思路就是取一段时间内读取到的数据中间值,可以有效的消去异常值。

		uint16_t ADC_Value;
		HAL_ADC_Start(&hadc1);	                //启动ADC单次转换
        uint16_t buf[20]={0};
		for(uint8_t i=0;i<20;i++)
		{
			buf[i]=HAL_ADC_GetValue(&hadc1); //读取ADC转换数据
			HAL_Delay(10);
		}
		ADC_Value = buf[10];
		printf("ADC_value = %d\r\n", ADC_Value);
  		HAL_Delay(500);

串口助手读取到的数据:
在这里插入图片描述
在这里插入图片描述
其实看到这,很多人都想到了,无论是接高电平还是接地,这组数据都会有很多的波动,无论是均值滤波还是中值滤波的话,都不能有效的消除这些波动。但通过对这组数据的观察,我们发现接地时零出现的次数较多,接高电平时4095出现的次数较多。
由此,我们很容易想到通过重数滤波来实现效果。

2.4 添加众数滤波和现象

均值滤波的思路就是取一段时间内读取到的数据中出现次数最多的数。

/* USER CODE BEGIN PV */
uint16_t a=0;
uint16_t Most_num[4095]={0}; //数组太大,应该放在全局变量,防止堆栈段溢出
uint16_t i=0;
uint16_t max=0;
/* USER CODE END PV */
while中代码:
		for(i=0;i<20;i++)
		{
			HAL_ADC_Start(&hadc1);	    //启动ADC单次转换
			a=HAL_ADC_GetValue(&hadc1); //读取ADC转换数据 20个数据
			HAL_Delay(10);
			Most_num[a]++;              //读到的数据,其数组中对应的值+1
		}
		max = Most_num[0];						//查找数组中的最大数,并且最大数为出现的次数
		uint16_t k = 0;								//最大数对应的数组序号就是出现次数最多的数
		for(i=0;i<4096;i++)
		{		
			if(max<Most_num[i])
				k = i;		
		}
   	 	printf("ADC_value = %d\r\n", k);
    	HAL_Delay(500);
		for(i=0;i<4095;i++)	//清空数组,防止堆栈段溢出
		Most_num[i]=0;

串口助手读取到的数据:
在这里插入图片描述
在这里插入图片描述
可以看到滤波效果非常好

3.ADC采样的两个实验——基于STMF4

3.1 内部温度传感器实验

STM32F4 有一个内部的温度传感器,可以用来测量 CPU 及周围的温度(TA)。该温度传感器在内部和 ADC1_IN16(STM32F40xx/F41xx 系列)或 ADC1_IN18(STM32F42xx/F43xx系列) 输入通道相连接,此通道把传感器输出的电压转换成数字值。 STM32F4 的内部温度传感器支持的温度范围为: -40~125 度。精度为±1.5℃左右。

3.1.1 开启ADC1_IN16

在这里插入图片描述

3.1.2 转化公式

T(℃) ={(Vsense - V25) /Avg_Slope}+25

上式中: V25=Vsense 在 25 度时的数值(典型值为: 0.76)。
Avg_Slope=温度与 Vsense
曲线的平均斜率(单位为 mv/℃或 uv/℃)(典型值为2.5mV/℃)。
利用以上公式,我们就可以方便的计算出当前温度传感器的温度了。

3.1.3 代码编写

		float Tempture_Value;
		float ADC_Value;
		float Last_ADC_Value;
		HAL_ADC_Start(&hadc1);
		Last_ADC_Value=HAL_ADC_GetValue(&hadc1);
		
		for(uint8_t i=20;i>1;i--)//均值滤波
		{
			ADC_Value=HAL_ADC_GetValue(&hadc1);
			HAL_Delay(10);
			Last_ADC_Value=Last_ADC_Value+ADC_Value;
		}
		Last_ADC_Value=Last_ADC_Value/20;
		
		Tempture_Value=Last_ADC_Value*(3.3/4096);			//电压值
		Tempture_Value=(Tempture_Value-0.76)/0.0025+25;
		printf("Tempture_Value = %f\r\n", Tempture_Value);
		HAL_Delay(500);

3.1.4 数据观察

在这里插入图片描述
可以看到即使加入均值滤波,读取到的电压值仍然波动较大。后续会考虑使用卡尔曼滤波。
在这里插入图片描述

STM32应用(六)一阶卡尔曼滤波代码和简单应用

3.2 光敏传感器实验

3.2.1 简单介绍

探索者 STM32F4 开发板自带的一个光敏传感器,本实验还是要用到 ADC 采集,通过 ADC 采集电压,获取光敏传感器的电阻变化,从而得出环境光线的变化。

探索者 STM32F4 开发板板载了一个光敏二极管(光敏电阻),作为光敏传感器, 它对 光的变化非常敏感。光敏二极管也叫光电二极管。光敏二极管与半导体二极管在结构上是类 似的,其管芯是一个具有光敏特征的 PN结,具有单向导电性,因此工作时需加上反向电压。 无光照时,有很小的饱和反向漏电流,即暗电流,此时光敏二极管截止。当受到光照时,饱和反向漏电流大大增加,形成光电流,它随入射光强度的变化而变化。当光线照射 PN 结时, 可以使 PN结中产生电子一空穴对,使少数载流子的密度增加。这些载流子在反向电压下漂 移, 使反向电流增加。因此可以利用光照强弱来改变电路中的电流。

3.2.2 电路连接示意图和实物图

在这里插入图片描述

图中, LS1 是光敏二极管(实物在开发板摄像头接口右侧), R58 为其提供反向电压,当环境光线变化时, LS1 两端的电压也会随之改变,从而通过 ADC3_IN5 通道,读取LIGHT_SENSOR(PF7)上面的电压,即可得到环境光线的强弱。
光线越强,电压越低,光线越暗,电压越高。
在这里插入图片描述

3.2.3 开启ADC3_IN5

在这里插入图片描述

3.2.4 现象观察

在这里插入图片描述
在这里插入图片描述

3.3 上述所有代码

上述所有代码 提取码:x557

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值