ADC采样的优化及AR滤波(自回归滑动平均)讲解

2019-10-11 16:35发布

此贴为慢更重原理及推到开始讲解进度会比较慢。讲的有问题可提醒楼主哦


我想论坛里的坛友学习过单片机都知道怎么用单片机的AD采样吧!
但都会碰到很多问题 如输出数值乱跳 不准等现象  ,碰到这样的问题大多数是加上了均值滤波、滑动平均、中值滤波甚至是在循环里加上延时等等。但是还是会碰到无论加多少次的平均还是不理想。下面就是我要分享的数字处理的简单方法,在讲之前我先问几个问题:
1、你们AD采样用的是什么方法呢?
2、采样率、与采样结果有什么样的关系呢?
3、各位觉得你们的你们猜出来的数据理想吗?如果有不错的方法可以分享出来。

下n层开始讲采样率对输出结果的优化
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
10条回答
yijinxiaoyou
2019-10-12 17:30
本帖最后由 yijinxiaoyou 于 2016-9-21 08:58 编辑

先放了定时器触发的例子可以试一下哦

#define ADC1_DR_Address    ((uint32_t)0x4001244C)
#define ADC_CH_NUM      1                /*通道数*/
#define ADC_CONV_COUNT  64               /*转换次数*/

__IO uint16_t ADC_RegularConvertedValueTab[ADC_CH_NUM * ADC_CONV_COUNT]/*, ADC_InjectedConvertedValueTab[32]*/;
__IO uint32_t Index;
uint8_t ADC_ACMP_flag = 0;


/*初始化定时器、ADC、DMA*/
void  Tim_ADC_Init(uint32_t _ulFreq, uint32_t _ulDutyCycle)
{
        ADC_InitTypeDef           ADC_InitStructure;
        NVIC_InitTypeDef          NVIC_InitStructure;
        DMA_InitTypeDef           DMA_InitStructure;
        TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
        TIM_OCInitTypeDef         TIM_OCInitStructure;
        GPIO_InitTypeDef          GPIO_InitStructure;
        uint16_t usPeriod;
        uint16_t usPrescaler;
        uint32_t uiTIMxCLK;

        /* Enable peripheral clocks ------------------------------------------------*/
        /* Enable DMA1 clock */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

        /* Enable GPIOA, GPIOC, ADC1 and TIM1 clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC |  RCC_APB2Periph_GPIOD |RCC_APB2Periph_GPIOE |
                RCC_APB2Periph_ADC1 | RCC_APB2Periph_TIM1, ENABLE);

        /* Configure TIM1_CH1 (PA8) as alternate function push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* Configure PC.06 as output push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_Init(GPIOC, &GPIO_InitStructure);

        /* Configure PA.01 、PA.02 and PC.03 (ADC Channel1、 Channel2 and Channel3) as analog input */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /*-----------------------------------------------------------------------
        system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:

        HCLK = SYSCLK / 1     (AHB1Periph)
        PCLK2 = HCLK / 2      (APB2Periph)
        PCLK1 = HCLK / 4      (APB1Periph)

        因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
        因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

        APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM6, TIM12, TIM13,TIM14
        APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11

        ----------------------------------------------------------------------- */

        uiTIMxCLK = SystemCoreClock;


        if (_ulFreq < 100)
        {
                usPrescaler = 10000 - 1;                                        /* 分频比 = 10000 */
                usPeriod = (uiTIMxCLK / 10000) / _ulFreq - 1;                /* 自动重装的值 */
        }
        else if (_ulFreq < 3000)
        {
                usPrescaler = 100 - 1;                                        /* 分频比 = 100 */
                usPeriod = (uiTIMxCLK / 100) / _ulFreq - 1;                /* 自动重装的值 */
        }
        else        /* 大于4K的频率,无需分频 */
        {
                usPrescaler = 0;                                        /* 分频比 = 1 */
                usPeriod = uiTIMxCLK / _ulFreq - 1;        /* 自动重装的值 */
        }

        /* TIM1 configuration ------------------------------------------------------*/
        /* Time Base configuration */
        TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
        TIM_TimeBaseStructure.TIM_Period = usPeriod;
        TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
        TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
        /* TIM1 channel1 configuration in PWM mode */
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse = (_ulDutyCycle * usPeriod) / 1000;//0x7F;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OC1Init(TIM1, &TIM_OCInitStructure);

        /* DMA1 Channel1 Configuration ----------------------------------------------*/
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_RegularConvertedValueTab;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = ADC_CH_NUM * ADC_CONV_COUNT;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Circular循环  DMA_Mode_Normal单次
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);

        /* Enable DMA1 channel1 */
        DMA_Cmd(DMA1_Channel1, ENABLE);
        /* Enable DMA1 Channelx Transfer Complete interrupt */
        DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;  //设置中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //主优先级设置
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //设置优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //打开中断
        NVIC_Init(&NVIC_InitStructure);

        /* ADC1 configuration ------------------------------------------------------*/
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
        ADC_InitStructure.ADC_NbrOfChannel = ADC_CH_NUM;/*ADC_CH_NUM*/
        ADC_Init(ADC1, &ADC_InitStructure);

        /* ADC1 regular channel14 configuration */
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_13Cycles5);
        //  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_7Cycles5);
        //  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_7Cycles5);
        //  ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 4, ADC_SampleTime_7Cycles5);
        //  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 5, ADC_SampleTime_7Cycles5);
        //  ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 6, ADC_SampleTime_7Cycles5);

        //  /* Set injected sequencer length */
        //  ADC_InjectedSequencerLengthConfig(ADC1, 1);
        //  /* ADC1 injected channel Configuration */
        //  ADC_InjectedChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_71Cycles5);
        //  /* ADC1 injected external trigger configuration */
        //  ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_None);

        //  /* Enable automatic injected conversion start after regular one */
        //  ADC_AutoInjectedConvCmd(ADC1, ENABLE);

        /* Enable ADC1 DMA */
        ADC_DMACmd(ADC1, ENABLE);

        /* Enable ADC1 external trigger */
        ADC_ExternalTrigConvCmd(ADC1, ENABLE);

        /* Enable JEOC interrupt */
        //  ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);

        /* Enable ADC1 */
        ADC_Cmd(ADC1, ENABLE);

        /* Enable ADC1 reset calibration register */
        ADC_ResetCalibration(ADC1);
        /* Check the end of ADC1 reset calibration register */
        while (ADC_GetResetCalibrationStatus(ADC1));

        /* Start ADC1 calibration */
        ADC_StartCalibration(ADC1);
        /* Check the end of ADC1 calibration */
        while (ADC_GetCalibrationStatus(ADC1));

        /* TIM1 counter enable */
        TIM_Cmd(TIM1, ENABLE);

        /* TIM1 main Output Enable */
        TIM_CtrlPWMOutputs(TIM1, ENABLE);

        //  /* Test on channel1 transfer complete flag */
        //  while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));
        //  /* Clear channel1 transfer complete flag */
        //  DMA_ClearFlag(DMA1_FLAG_TC1);

        //  /* TIM1 counter disable */
        //  TIM_Cmd(TIM1, DISABLE);
}


void DMA1_Channel1_IRQHandler(void)
{
        if (DMA_GetITStatus(DMA1_IT_TC1) != RESET)
        {
                /* TIM1 counter disable */
                //TIM_Cmd(TIM1, DISABLE);

                ADC_ACMP_flag = 1;

                /* Clear channel1 transfer complete flag */
                DMA_ClearITPendingBit(DMA1_IT_TC1);
        }
}


Tim_ADC_Init(50*64,200); /*ADC初始化 采样率:50HZ*64点  20ms*/

一周热门 更多>