使用Keil uVision和STM32F429 Discovery板实现IIR低通滤波器

3
我正在设计一个IIR 二阶低通滤波器,采样频率为100Hz,截止频率为10Hz。使用Matlab中的fdatool设计Chebyshev I型滤波器系数。但该代码不能过滤信号(即对于所有频率,输出的幅度与输入信号相同)。仅在10kHz及以上的输入信号上观察到幅度的轻微下降。我保证ADC和DAC工作正常,因为我已经测试了FFT滤波器。
以下是代码:
/* Include core modules */
#include "stm32f4xx.h"
#include "stdint.h"
#include "stdlib.h"
#include "arm_math.h"

#include "my_files.h"

#define URS 2
#define numStages 1
#define NUM_TAPS 5*numStages
#define samples 3

////////ADC FUNCTION//////////////////
void ADC_configure(void)
 {
     RCC->APB2ENR|=1Ul<<8;                         // ADC1 clock enabled
     ADC1->CR2|=0x00000001;                      // enable ADC
     ADC1->CR1|=0;                                   // single conversion ADC1 pin 0 has been selected
 }

int32_t readADC(void)
             {
                    ADC1->CR2|=(1UL<<30);
                    return(ADC1->DR);
             }

////////DAC FUNCTION/////////////////
int32_t dv1,dv2,ds;
//---function declaration--//
// initilising DAC---------//
void DAC_init(void)
{
  RCC->APB1ENR|=1UL<<29;
    DAC->CR|=((1UL<<16)|(1UL<<0));
  RCC->AHB1ENR|=0x00000001;                              // clock to gpio A
    GPIOA->MODER|=0x00000F03;                            // pt0,4,5 in Analog mode
}
// Sending to DAC...........//
void Send_DAC(int32_t data_in1, int32_t data_in2)
{   dv1=data_in1;
      dv2=data_in2<<16;
      ds=dv2+dv1;

      DAC->DHR12RD=ds;
}


/* IIR settings */
float32_t pState[2*numStages];
const float pCoeffs[NUM_TAPS] = {1,2,1,-1.1997,0.5157};//{b0,b1,b2,a1,a2}


/* Global variables */
float32_t Input[samples];                           /* Data to be read from ADC */
float32_t InputData[samples];                       /* Data to be processed */
float32_t Output[samples];                          /* Output filtered Data */

    arm_biquad_cascade_df2T_instance_f32 S;         /* ARM IIR module */
    uint16_t i;

void TIM3_Init (void) {

  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;             /* enable clock for TIM1    */

  TIM3->PSC   = 8600;                             /* set prescaler   = 10KHz  */
  TIM3->ARR   = 100;                              /* set auto-reload = 10ms */
  TIM3->RCR   =  0;                               /* set repetition counter   */
  TIM3->CR1 |= (1UL << URS);

  TIM3->DIER = TIM_DIER_UIE;                      /* Update Interrupt enable  */
  NVIC_EnableIRQ(TIM3_IRQn);                      /* TIM1   Interrupt enable  */
  NVIC_SetPriority (TIM3_IRQn, 0); 
  TIM3->CR1  |= TIM_CR1_CEN;                      /* timer enable             */
}

void TIM3_IRQHandler() {

        /*Shift Operation*/
        for(i=samples-1;i>0;i--){
            Input[i]= Input[i-1];
            InputData[i]= Input[i];
        }

        /* Input part from the ADC */
        Input[0] = (float32_t)readADC();
        InputData[0] = Input[0];

        //////////IIR//////////////////////
        /* Initialize the IIR module */
        arm_biquad_cascade_df2T_init_f32(&S, numStages, pCoeffs, pState);

        /* Process the data through the IIR module */
        arm_biquad_cascade_df2T_f32(&S, InputData, Output, samples);

        ////////DAC Output/////////////////
        Send_DAC(Input[0], Output[0]);
    }

/////////main function///////////////
int main(void) {
    /* Initialize system */
    SystemInit();
    DAC_init();
    ADC_configure();
    TIM3_Init();

    while (1) {     
    }
}

任何建议或解决方案都将非常有帮助。

使用了许多缩写词。而且问题不清楚! - Anand Gupta
1
你启用了FPU吗?很好,你不应该在stdlib中使用太多的init。但是你真的应该为寄存器初始化使用符号常量!这不会额外花费。此外,请检查ADC(和DAC?)的对齐方式。如果我理解正确,你在readADC中触发每次转换。这会导致抖动(导致数字信号噪声);通过定时器触发对话并使用ADC中断来读取数据,这就是STM具有其可变触发选项的原因。另外:你是否检查了中断溢出的时间? - too honest for this site
您可以使用DWT模块轻松进行分析(需要ARM架构参考手册-免费但需要注册)。 - too honest for this site
感谢@Olaf,问题只是对齐的问题。一切都是正确的。只是我从输出数组的错误侧面取得了输出。一旦我从另一端取出它,问题就解决了。非常感谢。此外,我引入了定时器触发的对话。这对你的帮助很大。再次感谢。 - user11622
我把那个作为答案了,希望你能相应地予以尊重。哦,我还添加了一些提示。 - too honest for this site
2个回答

1
一些可能存在的问题:
  • 你是否启用了FPU?
  • 检查ADC(和DAC)的对齐方式。
  • 确保中断处理程序不会运行太长时间(溢出)。

很好,你并没有在stdlib中使用过多的内容。但是你真的应该为寄存器初始化使用符号常量!这不会额外增加成本。

虽然不直接相关,但会导致错误结果:如果我理解正确,你会在readADC中触发每个转换。这会导致抖动(产生数字信号噪音);通过计时器触发转换(这就是触发系统的作用),并使用ADC中断来读取数据或使用DMA(STM DMA提供了双缓冲模式,非常适合此类操作)。在这个简单的例子中,如果使用DMA,甚至可以完全不需要中断,并在主程序中进行计算。

对于DAC,你也应该这样做。

不确定为什么要使用计时器;ADC可以自动触发。这不足以满足需求吗?


我只是一个初学者,正在逐渐学习。现在我的下一个任务是使用DMA。 :) - user11622
如果我可以建议的话,你应该先正确地获取信号链。这意味着要尽可能消除抖动。例如,可以使用STM触发系统来实现这一点,这相当复杂(对于大多数现代MCU而言),需要阅读所有(可能的)外设模块的参考手册。只有在此之后,您才应该优化处理和数据传输。通常,处理会在线程/主程序中进行,以便不会干扰其他中断。另一种选择可能是使用中断优先级(顺便说一下,这适用于我的当前专业STM32项目)。 - too honest for this site
据我所读,您在DAC上遇到了噪声问题。这可能是由于抖动引起的,但您也可以查看应用笔记。其中有一个关于ADC / DAC和噪声问题的说明。此外,您可能会发现探索板并没有完全遵循模拟设计实践(它更像是'429的LCD / SDRAM功能的廉价演示器,这些功能对于'F4系列来说是/曾经是新的)。 - too honest for this site
如果上面的答案有帮助解决问题,请点赞和/或接受答案。 - too honest for this site

0

每次都不需要初始化IIR滤波器。只需在init代码中执行一次即可。初始化过程会清除pState中的先前值,但这些值对于IIR的正确执行是必需的。这就是为什么您的滤波器不起作用的原因。FPU的存在只影响计算速度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接