这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【原创】简易滤波算法--from恶龙咆哮

共24条 1/3 1 2 3 跳转至

【原创】简易滤波算法--from恶龙咆哮

工程师
2022-10-09 10:06:33     打赏

前两天在玩灰尘传感器GP2Y10,遇到这样一个问题,当我读取灰尘传感器的数据的时候,发现它的数据会忽然抖动,像这样:

1.jpg

候,发现它的数据会忽然抖动,像这样:

明明在正常环境中,但是忽然·有一个跳变的值,这样的数据显然不是很稳定,相关的代码很短,就九行:

float pm;
       GP2Y_Low;
       delay_us(280);
       AD_PM = Get_Adc(ADC_Channel_0);       //PA0
       delay_us(40);
       GP2Y_High;
       delay_us(9680);
       pm = 0.17*AD_PM-0.1; //电压-灰尘转换
       printf("\r\n灰尘浓度:%f\n",pm);

对于这些不稳定的数据看上去就很头疼,于是,我查了查资料,找到了一个简单的滤波算法,原理就是设置一个数组,我设的有七个数,将读取到的AD值存到这个数组里,再定义三个变量,最大值,最小值和平均值,通过写一个函数查找最大值和最小值以及求数组数据总和,并把最大值和最小值减去,再求个平均数(好像比赛的时候裁判打分的规则啊),然后将这个AD值转换成为我们所需要的数据就OK啦。测得的值就稳定得多了:

2.png

这里把完整的代码发出来:

//===================C文件==============================
#include "bsp_GP2Y10.h"
#include "sys.h"
#include "delay.h"
#include "adc.h"
#include "usart.h"
       u16 AD_PM;
#define PM_N 7
 
void GP2Yinit(void)
{
//定义变量
    ADC_InitTypeDef A_InitStructure;
    GPIO_InitTypeDef G_InitStructure;    //PA0
    GPIO_InitTypeDef Gpio_InitStructure;//PB1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE );   //使能ADC2通道时钟
    
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
 
    //PA0 作为模拟通道输入引脚                       
    G_InitStructure.GPIO_Pin = GPIO_Pin_0;
    G_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
    GPIO_Init(GPIOA, &G_InitStructure);
  
    ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
  
    A_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
    A_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式
    A_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
    A_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
    A_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
    A_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
    ADC_Init(ADC1, &A_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 
  
  
    ADC_Cmd(ADC1, ENABLE);         //使能指定的ADC1
    ADC_ResetCalibration(ADC1); //使能复位校准
    while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
    ADC_StartCalibration(ADC1);  //开启AD校准
    while(ADC_GetCalibrationStatus(ADC1));  //等待校准结束
    Gpio_InitStructure.GPIO_Pin = GPIO_Pin_1;                    
    Gpio_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出 
    Gpio_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;          
    GPIO_Init(GPIOB, &Gpio_InitStructure);
    GP2Y_High;
}
void GetGP2Y(void)
{
       float pm,calcVoltage;
       int  pm_sum, i  ;
       int pm_max, pm_min;
       int pm_buf[PM_N];
       for(i = 0; i < PM_N; i++)
       {
              GP2Y_Low;
       delay_us(280);
       pm_buf[i] = Get_Adc(ADC_Channel_0);    //PA0
       delay_us(19);
       GP2Y_High;
       delay_us(9680);
       }
        pm_max = pm_buf[0];
   pm_min = pm_buf[0];
   pm_sum = pm_buf[0];
      
        for(i = PM_N - 1; i > 0; i--)
 
  {
 
    if(pm_buf[i] > pm_max)
 
      pm_max=pm_buf[i];
 
     else if(pm_buf[i] < pm_min)
 
      pm_min=pm_buf[i];
 
      pm_sum = pm_sum + pm_buf[i];
 
      pm_buf[i] = pm_buf[i - 1];
 
     }
 
                 i = PM_N - 2;
 
      pm_sum = pm_sum - pm_max - pm_min + i/2;          //加上i/2是为了四舍五入//
 
      pm_sum = pm_sum / i;
 
     
       pm = (0.17*pm_sum-0.1); //电压-灰尘转换
         if (pm<0)pm=0;
       printf("\r\n灰尘浓度:%f\n",pm);
}
 
//=======================H文件=========================
  #ifndef _BSP_GP2Y10_H_
#define _BSP_GP2Y10_H_
 
#include "stm32f10x.h"
 
#define GP2Y_High GPIO_SetBits(GPIOB,GPIO_Pin_1);
#define GP2Y_Low  GPIO_ResetBits(GPIOB,GPIO_Pin_1);
 
void GP2Yinit(void);
void GetGP2Y(void);
#endif
 
 
//=======================主函数=========================
#include "stm32f10x.h"
#include "bsp_dma_mtm.h"
#include "bsp_led.h"
#include "bsp_GP2Y10.h"
#include "usart.h"
#include "stdio.h"
#include "delay.h"
 
extern const uint32_t aSRC_Const_Buffer[BUFFER_SIZE];
 
extern uint32_t aDST_Buffer[BUFFER_SIZE];
 
 
 
void delay(uint32_t count)
{
       for(;count!=0;count--);
}
 
int main(void)
{
              GP2Yinit(); // 传感器初始化
    uart_init(115200); // 串口初始化
              delay_init();
    while(1)
    {
       GetGP2Y();
        delay_ms(1000);
    }
}




专家
2022-10-09 12:51:48     打赏
2楼

感谢楼主分享


高工
2022-10-09 16:06:29     打赏
3楼

谢谢分享


高工
2022-10-10 07:32:27     打赏
4楼
谢谢分享

专家
2022-10-10 08:32:39     打赏
5楼

学习


专家
2022-10-10 08:35:28     打赏
6楼

学习了,谢谢分享


专家
2022-10-10 08:47:50     打赏
7楼

谢谢分享


专家
2022-10-10 08:48:27     打赏
8楼

谢谢分享


菜鸟
2022-10-11 11:01:26     打赏
9楼

不错,谢谢分享


工程师
2022-10-12 23:22:58     打赏
10楼

非常感谢您的分享


共24条 1/3 1 2 3 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]