单片机内部署c语言滑动平均滤波器(以stm32f103开发板为例)

    作为最简单实用的滑动平均滤波器部署如下 , 该实验以加了50Hz的工频干扰的心电信号为实验对象。

        思路如下:怎么处理50Hz信号呢?用1分钟除以50Hz: 1000 / 50 = 20ms ,20ms是工频干扰的一个周期,一个周期内的所有采样点相加即为0,那我们就得刚好设置adc 采样时间为这20ms内,假设我的adc采样时间为4ms,那么就有4*5 = 20 , 所以就只需要有5个点就能完成一次滤波,这样我们就可以设置一个5长度的队列或者数组,当进来一个数据的时候出去一个数据,再对新进来的与之前的4个数据进行求和取平均运算。

 配置adc为定时器3触发:

/*********************************************************************************************************
* 函数名称:ConfigADC1
* 函数功能:配置ADC1
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:ADC123_IN1-PA1
**********************************************************************************************************/
static void ConfigADC1(void)
{                          
  GPIO_InitTypeDef  GPIO_InitStructure; //GPIO_InitStructure用于存放GPIO的参数
  ADC_InitTypeDef   ADC_InitStructure;  //ADC_InitStructure用于存放ADC的参数

  //使能RCC相关时钟
  RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC时钟分频,ADCCLK=PCLK2/6=12MHz
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1  , ENABLE);  //使能ADC1的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIOA的时钟
 
  //配置ADC1的GPIO
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;    //设置引脚
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AIN; //设置输入类型
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //根据参数初始化GPIO

  //配置ADC1 
  ADC_InitStructure.ADC_Mode               = ADC_Mode_Independent;  //设置为独立模式
  ADC_InitStructure.ADC_ScanConvMode       = ENABLE;                //使能扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;               //禁止连续转换模式
  ADC_InitStructure.ADC_ExternalTrigConv   = ADC_ExternalTrigConv_T3_TRGO;  //使用TIM3触发
  ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;   //设置为右对齐
  ADC_InitStructure.ADC_NbrOfChannel       = 1; //设置ADC的通道数目
  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 1, ADC_SampleTime_239Cycles5); //设置采样时间为239.5个周期

  ADC_DMACmd(ADC1, ENABLE);                   //使能ADC1的DMA
  ADC_ExternalTrigConvCmd(ADC1, ENABLE);      //使用外部事件启动ADC转换
  ADC_Cmd(ADC1, ENABLE);                      //使能ADC1
  ADC_ResetCalibration(ADC1);                 //启动ADC复位校准,即将RSTCAL赋值为1
  while(ADC_GetResetCalibrationStatus(ADC1)); //读取并判断RSTCAL,RSTCAL为0跳出while语句
  ADC_StartCalibration(ADC1);                 //启动ADC校准,即将CAL赋值为1
  while(ADC_GetCalibrationStatus(ADC1));      //读取并判断CAL,CAL为0跳出while语句
}

 TIM3设置为4ms:

/*********************************************************************************************************
* 函数名称:InitADC
* 函数功能:初始化ADC模块
* 输入参数:void
* 输出参数:void
* 返 回 值:void
* 创建日期:2018年01月01日
* 注    意:
**********************************************************************************************************/
void InitADC(void)
{
  ConfigTimer3(399, 719);   //100KHz,计数到400为4ms
  ConfigADC1();             //配置ADC1
  ConfigDMA1Ch1();          //配置DMA1的通道1

  InitU16Queue(&s_structADCCirQue, s_arrADCBuf, ADC1_BUF_SIZE); //初始化ADC缓冲区  
  InitU16Queue(&s_structFilter,s_arrFilterBuf,FILTER_BUF_SIZE);  //初始化滑动滤波器缓冲区大小
}

最后写一个滑动平均滤波器的滤波:

/*********************************************************************************************************
* 函数名称:u16 WriteFilterBuf(u16 d)
* 函数功能:向Filter缓冲区写入数据
* 输入参数:d-待写入的数据
* 输出参数:滤完波后的输出mooth
* 返 回 值:成功标志位,1为成功,0为不成功
* 创建日期:2018年01月01日
* 注    意:
**********************************************************************************************************/
u16 WriteFilterBuf(u16 d)
{
   u8 i ;
  u16 mooth = 0;  //将读取成功标志位的值设置为0

  EnU16Queue(&s_structFilter, &d, 1); //入队
    
    if(U16QueueLength(&s_structFilter) == 5)
    {
        
        for(i = 0 ; i < 5 ; i++ )
        {
            mooth += s_structFilter.pBuffer[i];
            
            
        }   
        DeU16Queue(&s_structFilter, &d, 1);
        mooth = mooth/5;
            printf("%d,\r\n",mooth);
    }
    

  return mooth;  //返回读取成功标志位的值
}


心电未处理前:

单片机内部署c语言滑动平均滤波器(以stm32f103开发板为例)_第1张图片

心电处理后:

单片机内部署c语言滑动平均滤波器(以stm32f103开发板为例)_第2张图片

你可能感兴趣的:(单片机,c语言,stm32)