STM32F4单片机ADC采样及ARM-DSP库的FFT

模拟信号经过ADC采样后变成数字信号,数字信号可以进行FFT运算,在频域中更容易分析信号的特征。本文将介绍如何用STM32F4的进行ADC采样,并利用ARMDSP库里的FFT算法对ADC采样值进行快速傅里叶变换。

我使用的是STM32F407VG单片机,由于需要的ADC采样值较多(采集了4096个点),所以配置了STM32的ADC和DMA,使用DMA将ADC采样值传输到内存效率更高。配置外设时,使用APB2时钟的2分频作为ADCCLK,ADC采样时间为84个ADCCLK,Tconv(总转换时间) = 采样时间+12个ADCCLK,理论上ADC的采样频率约4,375,00Hz。为了保证信号的完整性,由奈奎斯特定理知采样频率需要大于信号中最高频率的2倍,因此该外设配置方法测量的信号频率不应大于218,750Hz。外设配置代码如下:

GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure; 
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef  NVIC_InitStructure;	

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2|RCC_AHB1Periph_GPIOC,ENABLE);	
while(DMA_GetCmdStatus(DMA2_Stream0)!=DISABLE);				
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 	
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);  	
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); 	
//init GPIO ADC1, channel 14
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;	
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;					
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;			
GPIO_Init(GPIOC, &GPIO_InitStructure);
	
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&(ADC1->DR);
DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)&(fft.ADC_ConvertedValue[0]);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = 4096;
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_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream0,&DMA_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

DMA_ClearFlag(DMA2_Stream0,DMA_IT_TC);
DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);//使能数据流传输完成中断
DMA_Cmd(DMA2_Stream0,ENABLE);

ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;//84M/2 = 42M
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
	
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1,&ADC_InitStructure);
ADC_Cmd(ADC1,ENABLE);
	
ADC_RegularChannelConfig(ADC1,ADC_Channel_14,1,ADC_SampleTime_84Cycles);//转换时间84个ADC周期
 
ADC_SoftwareStartConv(ADC1);
ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);
ADC_DMACmd(ADC1,ENABLE);

接下来,将ADC的采样值转换为对应的电压值,利用DSP库的FFT算法进行FFT运算,计算幅频特性。这里,我使用的是基4浮点FFT算法,基4的算法比基2的算法运算速度更快。代码如下:

#define FFT_LENGTH 4096
void FFTTestTask(void *arg)
{
    OS_ERR err;
    CPU_TS ts;
    arm_cfft_radix4_instance_f32 scfft;
    int i = 0;
    unsigned char str[10];
	
    arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);//FFT初始化
    while(1)
    {
        OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,&ts,&err);//等待传输完成信号量
	for(i=0;i<FFT_LENGTH;i++)
	{
    	    fft.fft_input[2*i] = (float)fft.ADC_ConvertedValue[i]*3.3f/4096.0f;//实部为ADC采样值
	    fft.fft_input[2*i+1] = 0;//虚部为0
	}		
	arm_cfft_radix4_f32(&scfft,fft.fft_input);//FFT运算
	arm_cmplx_mag_f32(fft.fft_input,fft.fft_output,FFT_LENGTH);//计算每个点的模值
	for(i=0;i<FFT_LENGTH;i++)
	{
            sprintf((char*)str,"%.2f\r\n",fft.fft_output[i]);
	    board.UART4Send(str,strlen((char*)str));//将数据打印至串口助手,便于观察
	    OSTimeDly(1,OS_OPT_TIME_DLY,&err);
	}
	OSTimeDly(500,OS_OPT_TIME_DLY,&err);
	board.ADC1_DMA2Enable();//重新启动ADC转换和DMA传输
    }
}

实验中,我用FPGA和DAC做了DDS信号发生器,生成波形函数为f= 1.65+1.65\cdot cos(2\cdot \pi \cdot 1937\cdot t)。用上述方法采集电压信号进行FFT运算,最后使用MATLAB绘制了部分幅频特性曲线。直流分量的理论幅值为6758.4,实际值7168.2;基波分量的理论幅值为3379.2,实际值3454.3。

不足之处请大佬指正。

代码下载: STM32F4 ADC采样FFT运算测试代码

 

 

### 回答1: STM32F4ADC采样使用单通道、DMA和定时器触发FFT是一种常见的应用场景。 首先,单通道表示只使用一个ADC通道进行采样STM32F4系列微控制器通常具有多个ADC通道,可以选择适合的通道进行采样。通过配置ADC的控制寄存器和通道选择寄存器,可以设置ADC的工作模式和采样通道。 接下来,DMA(Direct Memory Access)是一种数据传输方式,可以在不经过CPU的情况下将数据从ADC缓冲区传输到存储器中。使用DMA可以提高系统性能,减轻CPU的负担。在配置DMA时,需要设置DMA的起始地址和目标地址,使得ADC采样数据可以直接传输到存储器中。 然后,定时器触发是指使用定时器的计时功能来触发ADC采样。通过配置定时器的计数器、预分频器和计时器模式,可以设置ADC采样频率采样间隔。 最后,FFT(快速傅里叶变换)是一种信号处理算法,可以将时域信号转换为频域信号。在采样数据传输到存储器后,可以使用FFT算法对采样数据进行处理,提取出频域信息。 综上所述,STM32F4ADC采样单通道、DMA、定时器触发FFT的应用流程如下:首先,选择合适的ADC通道并配置ADC的控制寄存器和通道选择寄存器。接着,配置DMA的起始地址和目标地址,使得ADC采样数据可以直接传输到存储器。然后,配置定时器的计数器、预分频器和计时器模式,设置ADC采样频率采样间隔。最后,将采样数据传输到存储器后,使用FFT算法对采样数据进行处理,提取出频域信息。这种应用场景可以实现对信号的快速采样和频谱分析,广泛应用于音频信号处理、通信系统等领域。 ### 回答2: stm32f4ADC采样是指通过ADC模块对外部模拟信号进行转换,并将转换结果存储在内部寄存器中。以下是以单通道、DMA和定时器触发FFT为例的ADC采样过程的详细描述: 首先,需要配置ADC模块的参数。可以选择单通道采样,即只使用一个模拟信号通道进行采样。可以选择采样率和采样精度,并设置对应的转换模式。 然后,需要配置DMA通道,以实现ADC数据的直接存储。DMA通道负责从ADC的数据寄存器中读取转换结果,并将其存储到指定的存储器区域中。通过使用DMA,可以在ADC转换过程中同时进行其他任务,提高采样效率。 接下来,需要配置一个定时器来触发ADC的转换。定时器可以生成一个周期性的触发信号,用于精确控制采样的时间间隔。通过将定时器与ADC的触发源相连接,可以在每个定时器触发事件上开始一次ADC转换。 最后,可以将采样到的数据应用于FFT算法。FFT即快速傅里叶变换,可以将时域信号转换为频域信号。通过对ADC采样得到的数据进行FFT分析,可以获取信号的频谱信息,用于进一步的数据处理和分析。 综上所述,通过配置ADC模块的参数、设置DMA传输和定时器触发,可以实现stm32f4ADC单通道采样、DMA传输和定时器触发FFT分析。通过这种方式,可以有效地进行模拟信号的采样和频域分析,用于各种应用场景中。 ### 回答3: STM32F4系列的ADC采样单通道、DMA、定时器触发FFT是一种常见的硬件实现方法,适用于实时信号分析和处理的应用场景。 首先,STM32F4系列的微控制器内部集成了一种精确的ADC模块,可实现模拟信号的数字化转换。采样单通道即表示一次只对一个模拟输入通道进行采样,这有利于简化系统设计和提高采样精度。 其次,通过使用DMA(直接内存访问)控制器,可以实现高效的数据传输。DMA可以在ADC转换完成后,自动将采样数据从ADC模块中读出,并传输到指定的存储区域(如数组或缓冲区)。这样可以减少CPU的负担,提高系统的实时性和效率。 同时,使用定时器触发ADC转换,可以实现定时采样。通过配置定时器的参数,如采样频率采样时间等,可以实现对模拟信号的周期性采样。这对于实时信号分析和处理非常重要,可以确保采样数据的一致性和准确性。 最后,采样后的数据可以通过FFT(快速傅里叶变换)算法进行频谱分析。FFT算法可以将时域上的采样数据转换为频域上的频谱信息,从而可以分析信号的频率成分和谱线。这对于信号处理和频谱显示非常有用,可以帮助工程师更好地了解信号的特性和用途。 总之,STM32F4ADC采样单通道、DMA、定时器触发FFT是一种有效的硬件实现方法,适用于实时信号分析和处理的应用场景。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值