DAC-ADC-DSP库FFT获取正弦波频率

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"

#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 */

如果没有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 */

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 */
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 */
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);
输出信号

在这里插入图片描述

ADC

cubemx配置
ADC1

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

在这里插入图片描述

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

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

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

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

while(1)
while (1)
  {
	  if(ad_flag == 1)
	  {
          //数据处理
          //......
          
          ad_flag = 0;	//标志位置0
      }
}

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;							// 频率
arm_cfft_radix4_instance_f32 scfft;        //FFT对应结构体变量
arm_cfft_radix4_init_f32(&scfft,fft_adc_n,0,1); //初始化scfft结构体,设置FFT相关参数
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;
}
  • 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

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在称重仪表中使用FFT(快速傅里叶变换)滤波可以有效地消除噪音和干扰,提高称重仪表的精确度和稳定性。 首先,FFT是一种常用的信号处理技术,可以将时域的信号转换为频域的信号。在称重仪表中,通过采集和记录物体的重量数据,得到时域的重量信号。 然而,由于各种噪音和干扰的存在,时域信号中可能包含多余的频率成分,这会影响到称重结果的准确性。这时,使用FFT滤波可以将这些干扰成分滤除,只保留真实的重量信号。 具体而言,首先将时域信号进行FFT变换,得到频域的信号。然后,通过频率谱分析,可以观察到信号的频率成分分布情况。根据实际情况,可以选择合适的频率范围,将异常的频率成分剔除掉。最后,将滤波后的频域信号进行反变换,得到滤波后的时域信号。 通过FFT滤波,可以有效地去除噪音和干扰,使得称重仪表的重量信号更加精确和稳定。这对于需要高精度的称重应用,如实验室测量和工业生产中的重量检测都是至关重要的。 总之,在称重仪表中使用FFT滤波可以通过频域分析的方法去除噪音和干扰,提高称重仪表的精确度和稳定性。这种信号处理技术的应用使得称重结果更加准确可靠,满足高精度称重的需。 ### 回答2: 在称重仪表中使用FFT滤波是为了去除信号中的噪音和干扰,提高称重系统的精度和稳定性。 FFT(快速傅里叶变换)是一种信号处理的技术,它可以将时间域的信号转换为频域的信号。在称重仪表中,我们可以将被称重物体产生的微弱的变形信号通过传感器采集到,并经过模拟转换成电信号。这个信号往往包含了一些噪音、干扰以及其他不需要的频率成分。 通过应用FFT滤波,我们可以将这个频域信号分解成许多不同频率成分,并根据自己的需要选择性地去掉那些噪音和干扰。去除这些不需要的成分后,我们可以重新合成信号并进行重构,以得到干净、准确的称重结果。 使用FFT滤波技术的好处是,它能够快速处理信号,提高信号处理过程的效率。同时,FFT滤波还能够保留信号的特征频率,不会对信号本身的重要信息进行损失。这就使得我们在去除噪音的同时,不会损害实际信号的有效信息,保证了称重结果的准确性和稳定性。 总之,在称重仪表中使用FFT滤波可以有效去除噪音和干扰,提高称重系统的性能。通过合理设置滤波参数,我们能够获得更加准确和可靠的称重结果。 ### 回答3: 在称重仪表中使用FFT滤波有助于提高称重仪表的精度和稳定性。FFT(快速傅里叶变换)是一种将时域信号转换为频域信号的方法,通过对称重仪表输入的信号进行FFT分析,可以得到该信号包含的各个频率分量的强度。 首先,通过FFT分析可以检测和过滤掉输入信号中的噪声,提高称重仪表的测量精度。噪声是在测量过程中常常伴随出现的随机干扰信号,会对测量结果产生不良影响。通过FFT分析可以将噪声与有效信号进行区分,然后通过滤波的方式将噪声信号去除,减小了误差。 其次,使用FFT滤波还可以检测和修正称重仪表中的系统漂移或非线性问题。系统漂移是指在长时间使用过程中,由于温度变化、元件老化等因素导致输入信号的偏移。非线性问题是指称重仪表输出信号与输入信号之间存在非线性关系。通过对称重仪表输入信号进行FFT分析,可以得到频域上的频率响应,进而判断出系统偏移或非线性的存在,并通过滤波技术来对其进行修正,使得称重仪表的测量结果更加准确可靠。 综上所述,通过在称重仪表中使用FFT滤波技术,可以提高测量精度和稳定性,减小噪声影响,检测和修正系统偏移和非线性问题,从而提高称重仪表的性能和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值