本文采用四路AD采集光照强度、烟雾浓度、一氧化碳、空气质量等四个物理量,并采用中位值平均滤波(防脉冲干扰平均滤波法)算法对偶然出现的脉冲性干扰,消除由其引起的采样值偏差。
ADC简介
STM32F103C8T6有两个ADC,12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐的方式存储在16位数据寄存器中。
主要用到的ADC参数和函数
void ADC1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置 ADC 分频因子 6
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
ADC_DeInit(ADC1); //将外设 ADC1 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//连续转化模式设置
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据左对齐
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//软件触发
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_NbrOfChannel=1;//通道数
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//扫描模式设置
ADC_Init(ADC1,&ADC_InitStructure);
ADC_Cmd(ADC1,ENABLE);//使能指定ADC外设
ADC_ResetCalibration(ADC1);//使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束
ADC_StartCalibration(ADC1);//开启AD校准
while(ADC_GetCalibrationStatus(ADC1));//等待AD校准结束
}
u16 Get_ADC_Value(u8 channel)//ADC采样
{
ADC_RegularChannelConfig(ADC1,channel,1,ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
void ADC_DeInit(ADC_TypeDef* ADCx) :将外设 ADCx 的全部寄存器重设为缺省值 ADC_ContinuousConvMode:用来设置是否开启连续转换模式,单次转换:DISABLE;连续转换:ENABLE,因为我们是单次转换,所以设置为DISABLE
ADC_DataAlign:用来设置 ADC 数据对齐方式是左对齐还是右对齐,ADC转换后的数据被保存到数据寄存器中(ADC_DR)的0~15位或16~32位,数据宽度为16位,ADC转换精度12位。左对齐则是把ADC转换后的数值最高位D12与存储区域的最高位Bit15对齐,存储区域的低4位无意义。右对齐则是ADC转换的数值最低位D0保存在存储区域的最低位Bit0,高四位无意义
ADC_ExternalTrigConv:用来设置启动规则转换组转换的外部事件 ,ADC在收到触发信号后才开始进行模数转换
ADC_Mode:ADC的模式非常多,包括独立模式,注入同步模式等等,而不同的ADC是共用通道的,当两个ADC采集同一个通道的先后顺序、时间间隔不同时,就会有多种模式。我们只使用了一个ADC,所以选择独立模式,参数为 ADC_Mode_Independent。
ADC_NbrOfChannel:保存要进行ADC数据转换的通道数,可以为1 ~ 16个。这里我们是单次采集一个通道,所以值为 1即可
ADC_ScanConvMode:用来设置是否开启扫描模式,当有多个通道需要采集信号时,可以把ADC配置为按一定的顺序轮流采集各通道的值。如果采集多个通道,必须开启此模式。这里我们是单次采集一个通道的信号,这里我们选择不开启 : DISABLE
注:以下函数都没有写形参和返回值,仅仅写出了它的功能,具体参见STM32F103固件库说明手册
ADC_Init():根据 ADC_InitStruct 中指定的参数初始化外设 ADCx 的寄存器
ADC_Cmd():使能或者失能指定的 ADC,:函数 ADC_Cmd 只能在其他 ADC 设置函数之后被调用
ADC_ResetCalibration(): 重置指定的 ADC 的校准寄存器
ADC_GetResetCalibrationStatus(): 获取 ADC 重置校准寄存器的状态 ,返回值: ADC 重置校准寄存器的新状态(SET 或者 RESET) ,当值为RESET时重置成功
ADC_StartCalibration():开始指定 ADC 的校准状态
ADC_GetCalibrationStatus(): 获取指定 ADC 的校准程序 ,返回值: ADC 校准的新状态
ADC_RegularChannelConfig ():设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间,RANK值是指在进行多通道扫描时,本通道的扫描顺序。例如通道4、5、6、7的RANK值被分配为4、3、2、1,则在ADC扫描时,扫描的顺序为通道7、6、5、4 。
ADC_SampleTime:用于配置本通道的采样周期,这里的周期指的是ADCCLK的时钟周期,ADC时钟频率越高,转换速度就越快,但ADC时钟有上限值,不能超过14Mhz。ADC的时钟(ADCCLK)为ADC预分频器的输出,而ADC预分频器的输入则为高速外设时钟(PCLK2)。PCLK2的常用时钟频率为72Mhz,可设置PCLK2为2、4、6、8分频。因为ADCCLK必须低于14Mhz,所以ADCCLK最高频率为PCLK2的8分频,即ADCCLK = 9Mhz.
STM32的ADC采样时间计算公式:T=采样周期+12.5个周期
本实验中ADC通道的转换时间:T= (239.5+12.5)x(1÷12) = 21us
注:12.5为固定周期
ADC_SoftwareStartConvCmd():使能或者失能指定的 ADC 的软件转换启动功能
ADC_GetFlagStatus();检查制定 ADC 标志位置 1 与否
ADC_FLAG 的值
u16 ADC_GetConversionValue(ADC_TypeDef* ADCx) :返回最近一次 ADCx 规则组的转换结果
中位值平均滤波(防脉冲干扰平均滤波法)
方法:“中位值滤波法"+“算术平均滤波法”
连续采样N个数据,去掉一个最大值和一个最小值,然后计算N-2个数据的算术平均值,N值的选取:3~14
优点:融合了两种滤波的优点。对于偶然出现的脉冲性干扰,可消除有其引起的采样值偏差。对周期干扰有良好的抑制作用,平滑度高,适于高频振荡的系统。
缺点:测量速度慢。
这里采用了一个二维数组来分别存储四个AD通道的采样值,然后分别进行计算,具体代码如下:
void middleAverageFilter() //中位值平均滤波(防脉冲干扰平均滤波法)
{
u16 i,j,k,g;
u16 temp;
u16 Sum_Value[ADC_Value_Size] = {0};
u16 value_buf[ADC_Value_Size][ADC_Value_Number] = {0};
for(g = 0 ; g < ADC_Value_Size ; g++)
{
for(i = 0; i < ADC_Value_Number; i++)
{
value_buf[g][i] = Get_ADC_Value(g+0x04);
}
}
/*从小到大冒泡排序*/
for(g = 0 ; g < ADC_Value_Size ; g++)
{
for(j = 0; j < ADC_Value_Number-1; j++)
{
for(k = 0; k < ADC_Value_Number-j-1; k++)
{
if(value_buf[k] > value_buf[k+1])
{
temp = value_buf[g][k];
value_buf[g][k] = value_buf[g][k+1];
value_buf[g][k+1] = temp;
}
}
}
}
for(g = 0 ; g < ADC_Value_Size ; g++)
{
for(i = 1; i < ADC_Value_Number-1; i++)
{
Sum_Value[g] += value_buf[g][i];
}
}
Light_value =4096 - Sum_Value[0]/(ADC_Value_Number-2);
m7_value=Sum_Value[1]/(ADC_Value_Number-2);
m135_value =4096 - Sum_Value[2]/(ADC_Value_Number-2);
m2_value = Sum_Value[3]/(ADC_Value_Number-2);
}
传感器
本实验用到了 MQ-2 烟雾传感器、MQ-7一氧化碳传感器、MQ-135空气质量传感器和光敏电阻传感器。传感器这里就不再介绍啦,大家有传感器就应该有资料的,直接连在对应的引脚就可以用啦。
4. 实验现象
百度网盘下载链接
链接:https://pan.baidu.com/s/1SpTvf2CjtPRw3GmdaW4xTA 文章来源:https://www.toymoban.com/news/detail-544250.html
提取码:1k6q文章来源地址https://www.toymoban.com/news/detail-544250.html
到了这里,关于基于STM32F103C8T6四路AD采集数据显示在oled屏上非DMA传输方式(附百度网盘下载链接)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!