音乐频谱显示说白了就是“儿童版”频谱仪。笔者平时比较喜欢听音乐,闲暇之余听音乐的时候如果有个频谱显示的小玩具在旁边跳来跳去的也挺有意思的,所以笔者去万能的某宝上搜索了一下,发现便宜的都很小,大一点的都很贵,而且都需要音频接头输入,很麻烦,所以笔者就自制了这个小玩具。效果图如下图1所示。

效果视频: 自制音乐频率响应小玩具_哔哩哔哩_bilibili

3、在显示时间和温度时,一段时间后屏幕自动熄灭。触动小玩具即可再次点亮

1、FFT(Fast Fourier transform)

快速傅里叶变换是一种利用计算机进行高速快捷的离散傅里叶变换的一种方法,而什么是傅里叶变换?傅里叶变换的物理意义是什么呢?

当年,著名的数学家傅里叶表示:任何连续测量的时序或信号,都可以表示为不同频率的正弦波信号的无限叠加。而通过傅里叶变换就可以将叠加的波形以正弦波为基本单位将其拆分开。

而快速傅里叶变换为什么可以快速呢?首先先看一下离散傅里叶变换的公式:

通过公式不难看出如果我们让计算机去计算时,我们需要计算N^2次运算。但是通过观察可以发现,在计算中有想当一般的数据都是冗余的,并且不会显示在频谱中。所以我们可以将这些数据保存下来计算的时候直接调用或在此数据基础上做简单的运算。通过这样的方法我们就可以将DFT的N^2次运算减少到Nlog10(N)次运算了。

例如如果做1000采样点的傅里叶变换使用DFT的运算次数就是1000000次,而使用FFT就可以减少到3000次运算。

2、STM32实现FFT

因为笔者做的这个玩具使用的芯片是STM32单片机F10系列。所以在做FFT的时候没有官方库的支持(以前是有,但是F4系列上线后就取消了,真实万恶的资本主义\dogs)虽然网上有很多教程是直接移植或者找之前的DSP库,但是笔者觉得着实有些麻烦,F10系列没有DSP运算核心,这个DSP库就犹如花瓶。

这里主要借鉴了这位大神的文章: 《C》C语言实现FFT算法_杨贵安的博客-CSDN博客_c语言fft

在单片机上做FFT时需要注意堆栈的大小,以免发生硬件错误。代码如下:

double * FFT(double *pr,int n)
	static double amp_data[FFT_max*2];//定义输出幅值
	static double fr_data[FFT_max*2];//定义输出实部
	static double fi_data[FFT_max*2];//定义输出虚部
	static double pr_data[FFT_max];//缓存输入实部
	static double pi_data[FFT_max];//缓存输入虚部
	unsigned int k;//n=2^k;
	int i,j;
	int it,m,is,nv;
	double p,q,s,vr,vi,poddr,poddi;
//===============初始化================================//
	k = log10(n)/log10(2);//n=2^k;
	for(i=0;i<n;i++)
		pr_data[i] = *(pr+i);//读入缓存
		pi_data[i] = 0;//读入缓存
//========将pr[0]和pi[0]循环赋值给fr_data[]和fi_data[]==========//
  for (it=0; it<=n-1; it++)  
		m=it; 
		is=0;
		for(i=0; i<=k-1; i++)
			j=m/2; 
			is=2*is+(m-2*j); 
    fr_data[it]=pr_data[is]; 
    fi_data[it]=pi_data[is];
//==================================================//
	pr_data[0]=1.0; 
	pi_data[0]=0.0;
	p=6.283185306/(1.0*n);
	pr_data[1]=cos(p); //将w=e^-j2pi_data/n用欧拉公式表示
	pi_data[1]=-sin(p);
//================计算pr_data和pi_data========================//
  for (i=2; i<=n-1; i++)  
		p=pr_data[i-1]*pr_data[1]; 
		q=pi_data[i-1]*pi_data[1];
		s=(pr_data[i-1]+pi_data[i-1])*(pr_data[1]+pi_data[1]);
		pr_data[i]=p-q; pi_data[i]=s-p-q;
//===================计算fr_data和fi_data=====================//
  for (it=0; it<=n-2; it=it+2)  
		vr=fr_data[it]; 
		vi=fi_data[it];
		fr_data[it]=vr+fr_data[it+1]; 
		fi_data[it]=vi+fi_data[it+1];
		fr_data[it+1]=vr-fr_data[it+1]; 
		fi_data[it+1]=vi-fi_data[it+1];
//=================蝴蝶操作=========================//
	m=n/2; 
	nv=2;
  for (i=k-2; i>=0; i--)
		m=m/2; 
		nv=2*nv;
    for (it=0; it<=(m-1)*nv; it=it+nv)
			for (j=0; j<=(nv/2)-1; j++)
				p=pr_data[m*j]*fr_data[it+j+nv/2];
				q=pi_data[m*j]*fi_data[it+j+nv/2];
				s=pr_data[m*j]+pi_data[m*j];
				s=s*(fr_data[it+j+nv/2]+fi_data[it+j+nv/2]);
				poddr=p-q; 
				poddi=s-p-q;
				fr_data[it+j+nv/2]=fr_data[it+j]-poddr;
				fi_data[it+j+nv/2]=fi_data[it+j]-poddi;
				fr_data[it+j]=fr_data[it+j]+poddr;
				fi_data[it+j]=fi_data[it+j]+poddi;
//=================计算幅值输出==========================//
  for (i=0; i<=n-1; i++)
		amp_data[i]=sqrt(fr_data[i]*fr_data[i]+fi_data[i]*fi_data[i]);  //幅值计算
//====================返回数据=========================//
	return amp_data;//返回幅值

直接通过KEIL仿真可以观察出FFT的输出波形与MATLAB对比图如下图3,图4

因为MAX7219这款IC输入电压范围在4-5.5V故一般需要5V供电,信号端也需要5-3.3V的转换。虽然大部分STM32的I/O口都是可以容忍5V输入与输出的。但笔者为了保险起见加了3路的3.3V-5V电路。其电路原理图如下。

4、STM32与音频输入电路

笔者将整个小玩具分成了两个块电路板,其中一块全是点阵和MAX7219一块是STM32、锂电池充放电电路、MPU6050外围电路和一路的音频采集电路,引出剩下部分引脚。音频采集电路主要使用咪头,经MAX4466做前置放大,放大后信号直接接入STM32内置ADC引脚。电路图如下图7所示

5、点阵屏时间显示

时间的计算采用STM32内置的RTC时钟即可,首先需要显示数字的字模,根据电路和字体大小(5*3),计算出数字0-9字模如下:

unsigned char disp1[11][3]={
{0x1F,0x11,0x1F},//0
{0x00,0x1F,0x08},//1
{0x1D,0x15,0x17},//2
{0x1F,0x15,0x15},//3
{0x1F,0x04,0x1C},//4
{0x17,0x15,0x1D},//5
{0x17,0x15,0x1F},//6
{0x18,0x17,0x10},//7
{0x1F,0x15,0x1F},//8
{0x1F,0x15,0x1D},//9
{0x00,0x0A,0x00} //:

根据电路结构和扫描顺序,写出底层显示驱动程序,程序如下:

//参数从左到右依次为:字体数据,字体长度,字体宽度,起始位置的x坐标(自右向左),起始位置y坐标(自下而上)
void MAX7219_N_display(unsigned char *cData,unsigned char Length,unsigned char Width,unsigned char x,unsigned char y)
	static u16 iSbufWidth[24];//纵向显示缓存
	u16 iSbuf;//用户数据缓存
	u16 iSbuf_Middle;//缓存中间变量
	unsigned int i;
	for(i=0;i<Length;i++)
		iSbuf = 0;//缓存清零
		iSbuf |= *(cData+i)<<y;//只有有效位存在"1"的可能,非有效位全为0
		iSbufWidth[i+x] |= iSbuf;//向显示缓存写入有效位的“1”
		iSbuf = ~*(cData+i);//按位取反
		iSbuf <<= y;//左移到显示位置
		iSbuf = ~iSbuf;//相当于左移补1
		iSbuf_Middle = 0xffff;//置位
		iSbuf_Middle <<=(y+Width);
		iSbuf |= iSbuf_Middle;//补全高位使得只有有效位存在"0"的可能,非有效位全为1
		iSbufWidth[i+x] &= iSbuf;//向缓存写入有效位的“0”
	for(i=0;i<8;i++)
		Write_Max7219_N(i+1,iSbufWidth[i],iSbufWidth[i+8],iSbufWidth[i+16],iSbufWidth[i+16]>>8,iSbufWidth[i+8]>>8,iSbufWidth[i]>>8);//显示

这个装置整体来说比较简单,因为有姿态传感器和一个点阵屏,所以开发的自由度也比较高。本文附资源,资源包含两个电路板的PCB源文件和开发的源代码。如有好玩的想法或者改进欢迎留言讨论。

资源下载:音乐频谱显示资料.zip-硬件开发其他资源-CSDN下载本资源内含STM32源程序和PCB文件。可直接DIY制作。声明:本资料仅供娱乐参考。如转发或在其更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/qq_24025329/12331286?spm=1001.2014.3001.5503

0、前言音乐频谱显示说白了就是“儿童版”频谱仪。笔者平时比较喜欢听音乐,闲暇之余听音乐的时候如果有个频谱显示的小玩具在旁边跳来跳去的也挺有意思的,所以笔者去万能的某宝上搜索了一下,发现便宜的都很小,大一点的都很贵,而且都需要音频接头输入,很麻烦,所以笔者就自制了这个小玩具。效果图如下图1所示。效果视频:https://www.bilibili.com/video/BV1dZ4y1x77d...
是这样的,我的毕设是要做一个音乐的分离和音乐转录,音乐生成的三合一项目,听起来有点像3+2饼干,我喜欢吃柠檬口味的,众所周知音乐分离这块基本上做到了SOAT的程度,这段时间经过我的查阅资料发现音乐转录这块在2019年也做到了SOAT的程度,看来只有音乐生成这个模块还没有做到,说不定我在看几天就找到了。 为什么要做这个 从去年开题以来,我一直在对这个领域有不断的信息的来源,也逐渐对这个领域产生了兴趣,从刚开始代码代码挑不通,到现在论文看不懂,也是有所进步的嘛,希望记录下自己的心路历程,不求发多好的论文,只求可
STM32语音识别1】信号采集(麦克风、前置放大、模数转换) 1、麦克风 本文采用驻极体电容传声器,这里从电路的角度分析其工作原理,见下图。E.M.C unit 将声波转换成交变电压,由于信号内阻大,所以需要 FET Impedance converter 进行阻抗变换,同时具有信号放大功能。33pF 和 10pF 电容防止射频干扰,涉及电容的谐振频率,一般来说分别对应 GSM-900 和 GSM-1800 频段。偏置电阻 RL 为 FET 正常工作提供直流偏置电压,详情参考 FET 放大电路。 电子设计大赛已经过去很久了,一直想写一篇关于FFT的文章也没有来得及,现在写一下来记录分享一下。 本篇文章不讲复杂的FFT原理,只讲如何在stm32里面怎么实现FFT 一、FFT是什么,能干啥? FFT(fast Fourier transform)快速傅里叶变换,把时域信号变换到频域,至于换到频域后能做啥,那就多了 二、先用matlab来认识一下FFT 1.上代码 代码如下: fs = 1024; %采样频率 NPT = 1024; %样点个数 t=0:1/f
在 MDK 里面搭建 STM32F4 的 DSP 运行环境(使用.lib 方式)是很简单的,分为 3 个步骤: 1, 添加文件。 首先,我们在例程工程目录下新建:DSP_LIB 文件夹,存放我们将要添加的文件: arm_cortexM4lf_math.lib 和相关头文件(文件由官方提供),如图: 然后,打开工程,新建 DSP_LIB 分组,并将 arm_cortexM4lf_math.lib 添加到工程里面,如图: 2, 添加头文件包含路径 添加好.lib 文件后,我们要添
STM32F1系列单片机上面实现FFT 最近需要做一台基于stm32的示波器,测量信号参数,用单片机上面一些传统的方法局限性还是比较大,故开始琢磨直接上fft
回答: STM32FFT音乐频谱是通过使用STM32单片机进行FFT变换,将音频信号的频谱数据转换为幅值谱,并在LED全彩显示屏上显示出来。具体的实现过程是,通过外部设备(如电脑、手机等)的3.5mm耳机孔输出音频信号,经过继电器模块的音源选择后,一路给有源音响播放音乐,另一路经过音频信号调理电路,输入到STM32单片机的引脚进行采样和AD转换。然后,通过程序对采样到的音频信号进行FFT变换,得到频谱数据,并将其幅值谱显示在LED全彩显示屏上。为了保证采样的准确性,采样频率被设置为10KHz,采样点数为256个点,而显示屏的分辨率为128*64,因此只取FFT计算结果的一半,即128个点进行显示。[1][2]