当前位置:   article > 正文

DAC-ADC-DSP库FFT获取正弦波频率_正弦波求频率的函数 arm

正弦波求频率的函数 arm

DSP与FFT

DSP库的添加

cubemx配置
下载DSP库

在这里插入图片描述
在这里插入图片描述

添加DSP库到工程中

在这里插入图片描述在这里插入图片描述

工程配置
添加宏

在这里插入图片描述

ARM_MATH_CM4,__CC_ARM,ARM_MATH_MATRIX_CHECK,ARM_MATH_ROUNDING

第一个宏:

M3:ARM_MATH_CM3

M4:ARM_MATH_CM4

H7:ARM_MATH_CM7

include

在这里插入图片描述

#include "arm_math.h"
#include "math.h"
#include "arm_const_structs.h"
  • 1
  • 2
  • 3

#include "arm_const_structs.h" 如果cubemx生成的库没有,可以找板子的例程,将DSP的lib文件添加到工程中
在这里插入图片描述

测试
/* USER CODE BEGIN PV */
uint8_t lcd_id[12];				//存放LCD ID字符串
float data = 0;//定义一个float型变量
float fft_inputbuf[FFT_LENGTH*2];	//FFT输入数组
float fft_outputbuf[FFT_LENGTH];	//FFT输出数组
/* USER CODE END PV */

/* USER CODE BEGIN 1 */
	arm_cfft_radix4_instance_f32 scfft;
	uint8_t key,t=0;
	float time; 
	uint8_t buf[50]; 
	uint16_t i; 
	char send[15];
/* USER CODE END 1 */

/* USER CODE BEGIN 2 */
	LCD_Init();
	POINT_COLOR=RED;      //画笔颜色:红色
	sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将LCD ID打印到lcd_id数组。		
	LCD_ShowString(30,40,210,24,24,"mcudev STM32F4");	
	LCD_ShowString(30,70,200,16,16,"TFTLCD TEST");
	LCD_ShowString(30,90,200,16,16,"mcudev.taobao.com");
	arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);//初始化scfft结构体,设定FFT相关参数
  /* USER CODE END 2 */

/* USER CODE BEGIN WHILE */
  while (1)
  {
	  data = arm_sin_f32(PI/6);					//计算sin30°
	  sprintf((char*)lcd_id,"LCD ID:%.5f",data);//0.49999
	  LCD_ShowString(30,110,200,16,16,lcd_id);
		for(i=0;i<FFT_LENGTH;i++)//生成信号序列
		{
			 fft_inputbuf[2*i]=100+
							   10*arm_sin_f32(2*PI*i/FFT_LENGTH)+
							   30*arm_sin_f32(2*PI*i*4/FFT_LENGTH)+
							   50*arm_cos_f32(2*PI*i*8/FFT_LENGTH);	//生成输入信号实部
			//printf("%.2f\r\n",fft_inputbuf[2*i]);
			sprintf(send,"%.2f\r\n",fft_inputbuf[i*2]);
			HAL_UART_Transmit(&huart1,(uint8_t*)send,8,0xff);
			 fft_inputbuf[2*i+1]=0;//虚部全部为0
		}
		printf("\r\n");
		arm_cfft_radix4_f32(&scfft,fft_inputbuf);	//FFT计算(基4)
		printf("after:");
		for(i=0;i<FFT_LENGTH;i++)//生成信号序列
		{
			sprintf(send,"%.2f\r\n",fft_inputbuf[i*2]);
			HAL_UART_Transmit(&huart1,(uint8_t*)send,8,0xff);
		}
		arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH);	//把运算结果复数求模得幅值
		printf("\r\n%d point FFT runtime:%0.3fms\r\n",FFT_LENGTH,time/1000);
		printf("FFT Result:\r\n");
		for(i=0;i<FFT_LENGTH;i++)
		{
			printf("fft_outputbuf[%d]:%f\r\n",i,fft_outputbuf[i]);
		}		
    /* USER CODE END WHILE */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

如果没有LCD

/* USER CODE BEGIN PV */
float data = 0;//定义一个float型变量
float fft_inputbuf[FFT_LENGTH*2];	//FFT输入数组
float fft_outputbuf[FFT_LENGTH];	//FFT输出数组
/* USER CODE END PV */

/* USER CODE BEGIN 1 */
	arm_cfft_radix4_instance_f32 scfft;
	uint8_t key,t=0;
	float time; 
	uint8_t buf[50]; 
	uint16_t i; 
	char send[15];
/* USER CODE END 1 */

/* USER CODE BEGIN 2 */
	arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);//初始化scfft结构体,设定FFT相关参数
  /* USER CODE END 2 */

/* USER CODE BEGIN WHILE */
  while (1)
  {
	  data = arm_sin_f32(PI/6);					//计算sin30°
      //开调试看data值或串口输出
		for(i=0;i<FFT_LENGTH;i++)//生成信号序列
		{
			 fft_inputbuf[2*i]=100+
							   10*arm_sin_f32(2*PI*i/FFT_LENGTH)+
							   30*arm_sin_f32(2*PI*i*4/FFT_LENGTH)+
							   50*arm_cos_f32(2*PI*i*8/FFT_LENGTH);	//生成输入信号实部
			//printf("%.2f\r\n",fft_inputbuf[2*i]);
			sprintf(send,"%.2f\r\n",fft_inputbuf[i*2]);
			HAL_UART_Transmit(&huart1,(uint8_t*)send,8,0xff);
			 fft_inputbuf[2*i+1]=0;//虚部全部为0
		}
		printf("\r\n");
		arm_cfft_radix4_f32(&scfft,fft_inputbuf);	//FFT计算(基4)
		printf("after:");
		for(i=0;i<FFT_LENGTH;i++)//生成信号序列
		{
			sprintf(send,"%.2f\r\n",fft_inputbuf[i*2]);
			HAL_UART_Transmit(&huart1,(uint8_t*)send,8,0xff);
		}
		arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH);	//把运算结果复数求模得幅值
		printf("\r\n%d point FFT runtime:%0.3fms\r\n",FFT_LENGTH,time/1000);
		printf("FFT Result:\r\n");
		for(i=0;i<FFT_LENGTH;i++)
		{
			printf("fft_outputbuf[%d]:%f\r\n",i,fft_outputbuf[i]);
		}		
    /* USER CODE END WHILE */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

DAC

cubemx配置
DAC

在这里插入图片描述

  • Trigger:Timer2 Trigger Out event

在这里插入图片描述

DMA点ADD添加,Circular模式

在这里插入图片描述

确认配置无误

TIM2

在这里插入图片描述

  • 时钟频率为168MHz
  • PSC取168-1
  • ARR取5-1

输出频率为:168000000/168/5 = 200000Hz

工程配置
BEGIN0 产生正弦波函数

在这里插入图片描述

/* USER CODE BEGIN 0 */
void SineWave_Data( uint16_t num,uint16_t *D,float U)
{
    uint16_t i;
    for( i=0;i<num;i++)
    {
        D[i]=(uint16_t)((U*sin(( 1.0*i/(num-1))*2*3.14159265358979)+U)*4095/3.3);
    }
}

/* USER CODE END 0 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
BEGIN1 正弦波数组

在这里插入图片描述

 /* USER CODE BEGIN 1 */
	uint16_t Sine12bit[32] = {
		2048	, 2460	, 2856	, 3218	, 3532	, 3786	, 3969	, 4072	,
		4093	, 4031	, 3887	, 3668	, 3382	, 3042	,2661	, 2255	, 
		1841	, 1435	, 1054	, 714	, 428	, 209	, 65	, 3		,
		24		, 127	, 310	, 564	, 878	, 1240	, 1636	, 2048
	};
	
  /* USER CODE END 1 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
BEGIN2 初始化

在这里插入图片描述

//DAC
	TIM2->ARR = 9;						//修改ARR 可不加
	HAL_TIM_Base_Start(&htim2);			//打开定时器中断
	//HAL_DAC_Start(&hdac,DAC_CHANNEL_1);
	SineWave_Data(n,DualSine12bit,1.6);	//产生正弦波函数
	HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)Sine12bit, 32, DAC_ALIGN_12B_R);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
输出信号

在这里插入图片描述

ADC

cubemx配置
ADC1

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 定时器3触发
  • 添加DMA
  • 打开中断
TIM3

在这里插入图片描述

在这里插入图片描述

  • 时钟频率168MHz
  • PSC:168-1
  • ARR:2-1
  • Update Event
  • 打开中断
工程配置
BEGIN PD
#define fft_adc_n 1024    // 采1024个点
  • 1
BEGIN PV
float adc_data[fft_adc_n*2]={0};        // 存ADC值
uint8_t ad_flag = 0;
  • 1
  • 2
BEGIN2

在这里插入图片描述

HAL_TIM_Base_Start_IT(&htim3);				//打开定时器3中断
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&adc_buffer,fft_adc_n);	//ADC采集一组数据
  • 1
  • 2
BEGIN4
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    ad_flag=1;
}
  • 1
  • 2
  • 3
  • 4

ADC中断,采集完成后标志位置1

while(1)
while (1)
  {
	  if(ad_flag == 1)
	  {
          //数据处理
          //......
          
          ad_flag = 0;	//标志位置0
      }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

FFT

float fft_in_adc_data[fft_adc_n*2]={0}; // FFT输入,实部是ADC值,虚部补0
float fft_out_adc_data[fft_adc_n]={0};  // FFT输出
uint16_t flag[fft_adc_n] = {0};			// 数据处理时暂时存放数据
int k = 1;  							// 找第k大值
float32_t maxValue = 0;					// ADC最大值
uint32_t index = 0;						// 最大值下标
int i,j;
float freq = 0;							// 频率
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
arm_cfft_radix4_instance_f32 scfft;        //FFT对应结构体变量
arm_cfft_radix4_init_f32(&scfft,fft_adc_n,0,1); //初始化scfft结构体,设置FFT相关参数
  • 1
  • 2
if(ad_flag == 1)
{
    printf("finish\r\n");
    ad_flag = 0;
    for(i=0;i<fft_adc_n;i++)
    {
        fft_in_adc_data[i*2] = adc_buffer[i]*3.3/4095;		//实部
        fft_in_adc_data[i*2+1] = 0;							//虚部
    }
    printf("\r\n");
    arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_in_adc_data,0,1);
    arm_cmplx_mag_f32(fft_in_adc_data,fft_out_adc_data,fft_adc_n);
		  
    fft_out_adc_data[0]/=1024;
    for(i=1;i<fft_adc_n;i++)
        fft_out_adc_data[i]/=512;
    for(i=0;i<fft_adc_n;i++)
    {
        printf("%.5f\t",fft_out_adc_data[i]);
    }
    printf("\r\n");
    //arm_max_f32(&fft_out_adc_data[1],fft_adc_n/2-1,&maxValue,&index);

    /****查找最大值及其下标*********/
	memset(flag, 0, sizeof(flag));
  	for (i = 1; i <= k; i++)
  	{
    	maxValue = 0.0;
    	for (j = 1; j < fft_adc_n / 2; j++)
    	{
            if (flag[j] == 1)
                break;
            if (fft_out_adc_data[j] > maxValue)
            {
                maxValue = fft_out_adc_data[j];
                index = j;
            }
		}
    	flag[index] = 1;
  	}
    printf("index:%d\r\n",index);
    printf("Vmax:%.2f\r\n",maxValue);
    freq = (float)500000/fft_adc_n * (index) /2;		//500000为采样率
    
    printf("freq: %.3f",freq);
    ad_flag = 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • arm_cfft_sR_f32_len1024arm_const_structs.h里面,如果报错,检查头文件
  • 如果更改采样点数,注意修改arm_cfft_sR_f32_len1024,如果采样512个点,则改为arm_cfft_sR_f32_len512,以此类推
  • fft_out_adc_data[0]为直流分量电压值
  • maxValue为基波电压幅值
  • fft_out_adc_data[0]+maxValue=正弦波最大值
  • fft_out_adc_data[0]-maxValue=正弦波最小值
参考文章

https://blog.csdn.net/Nothing_To_Say_/article/details/123606260

https://blog.csdn.net/qq_34022877/article/details/123190943

https://blog.csdn.net/qq_24426625/article/details/129738537

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号