STM32 ADC采样详解

0x00 前言

在单片机开发过程中,常常涉及到ADC的使用,市面上大部分便宜的传感器都是采用的ADC来获取其数据,如MQ-2 烟雾传感器、光敏传感器等等。
在这里插入图片描述
在这里插入图片描述

此类传感器工作原理为根据所采集到的数据变化,造成其电阻率、电导率等参数变化,从而改变输出电压的大小。而我们通过采集传感器模块的输出电压,即可分析到所需要的信息,这个过程是由模拟信号(因为数据并不是直接以数字体现,而是以电压形式给出,所以称模拟)转化为数字信号(我们需要的是一个数值:浓度,强度),所以这个外设被称为ADC(Anology to Digital),其中C表示的Convert,为转换器的意思。

那么通俗的来说,ADC就是将模拟信号转换为数字信号的一个外设。通过ADC,可以获取到以电压形式体现的信息。还是以烟雾传感器传感器为例,假设烟雾传感器的电压输出范围是0-5v,其中显而易见0代表的是烟雾浓度为0%,5v代表的是烟雾浓度为100%,2.5v代表的烟雾浓度为50%。

我们为获取当前环境的烟雾传感器浓度,只需要采集到 烟雾传感器输出的电压即可。

0x01 ADC配置

现在需要确定一下你的引脚选择,既然是要使用ADC,那么所选择的引脚必须是具有ADC功能才对,现在可以在以下表中选择ADC引脚,例如我选择PA1引脚,那么我接下来应该配置ADC1的通道1。
在这里插入图片描述

具体的配置参数细节都已经在注释之中了:

void ADC_Init()
{
	ADC_InitTypeDef ADC_InitStructure; 
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// 使能ADC1外设时钟,以及将PA1引脚设置为模拟输入模式。
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE );
	// 设置ADC的时钟频率,也就是STM32的主频 72M/分频因子6 = 12M, 不能超过14M,否则会造成ADC采样精度下降
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	// 配置为模拟输入模式 Anology Input                    
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	ADC_DeInit(ADC1);  //复位ADC1 
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//ADC工作模式:ADC1和ADC2工作在独立模式
	// 开启扫描模式,则会依次扫描通道,例如你有多个烟雾传感器连接在通道1,通道2,通道3 ,通道4
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//模数转换工作在单通道模式
	// 单次转换模式或连续转换模式,如果开启了连续转换模式就会自动连续进行转换,否则需要自己需要的时候开启转换
	// 使用DMA时开启自动转换也会更加方便
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;	//模数转换工作在单次转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//转换由软件而不是外部触发启动
	//左对齐,数据范围0-65535,右对齐,数据范围0-4065(精度一样都是12位,只是12位数据以不同的对齐方式放在了uint16_t变量中)
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;	//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;//顺序进行规则转换的ADC通道的数目
	
	ADC_Init(ADC1, &ADC_InitStructure);	//根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器

	// 注意这两个函数是不一样的,先复位校准再进行初始校准
	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1
	ADC_ResetCalibration(ADC1);	//使能复位校准  
	while(ADC_GetResetCalibrationStatus(ADC1));	//等待复位校准
	ADC_StartCalibration(ADC1);	 //开启AD校准
	while(ADC_GetCalibrationStatus(ADC1));	 //等待初始校准
}

至此ADC校准就结束了,此时就可以编写ADC的单次转换函数了

uint16_t GetAdcValue(u8 ch)   
{
  	// 对ADC1的通道1 进行单次转换
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
	//使能指定的ADC1的软件转换启动功能	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
	return (ADC_GetConversionValue(ADC1));	// 返回ADC采样值
}

0x02 滤波处理

一般由于ADC采样到的值是不稳定的,并且电压变化的速率以及大于了ADC的采样速率,并且现实中也会有各种的干扰情况发生,所以单次采样的值并不能代表实际采样的值。

为减少这种情况的发生,所以就要进行一定的滤波处理了。

初中老师以及教过,对于化学、物理、生物实验,为了避免实验的偶然性,应当多做实验。ADC 采样也不例外,可以多次测量,取平均值,在短时间内进行多次ADC采样,取得平均值结果。那么这个就是叫做平均值滤波。这个一般只是一个很简单的处理,通常也是误差比较大的,因为加入你采到了一个非常离谱的数据,贸然取平均值便会导致整体采样值偏移。

如图,以下是由180个采样点,插入一些随机的噪声,贸然取平均值得到的数据,整体大致偏移了2000,这算是很大的误差了

在这里插入图片描述

那么还有一个方法是参考其他的采样数据,从而剔除不合理的数据,例如采用方差
等数据剔除不合理的数据,筛选一遍过后,计算得到平滑数据,如下:
在这里插入图片描述
当然,并非只有一种滤波算法可选,也可以选择一套动态的滤波算法如FFT,适用且可以应用于大多数场景。

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IoT_H2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值