系统设计主要涉及的有作为核心进行计算的stm32单片机的主控电路设计、实现蓝牙电磁数据传输的mh-m18蓝牙音频采集电路的设计、负责提供音乐切换控制信号的按键状态采集电路、对fft变换计算所得频谱进行展示的oled显示电路以及作为物理功放的lm386音频放大电路设计。原理图:
3.程序框图
主程序首先进行初始化,对系统的adc、定时器、oled等等进行初始参数配置,其后是对设计目标的计算工作。本设计主要分为三个大的模块,一是蓝牙的数据接收,二是音乐的传输播放,三是时域信号傅里叶变换后的频域展示,其中最主要的是时域信号傅里叶变换后的频域展示。主程序main中主要对频谱在oled上的显示规则、fft计算的相关需求进行了设计。
主程序的总体设计思路是系统开机后首先对stm32单片机内部进行复位,之后是对各项设置进行一个初始化操作,包括定时器、模数转换器、通信协议等方面,然后程序开始正式运行,执行功放和fft任务,进入循环和等待控制信号。
蓝牙传输模块的作用是接收源设备所发射的蓝牙音频信号,并提供给音频放大电路进行放大及播放。蓝牙传输子程序,首先需要判断蓝牙状态,确认蓝牙开启后进行参数扫描,扫描后选择目标设备来进行连接,连接成功之后即可根据指令进行音频信号接收。本设计的蓝牙音乐源为手机,因此需设置适用于手机传输的波特率,并于手机相连。
按键状态采集程序是用于实现对音乐的切换,完成上一曲、下一曲及暂停功能。按键状态的采集程序较为简单,仅需要对按键状态采集电路中各个按键的状态作出判断,当按下不同按钮后,stm32单片机获取到不同的状态信息,从而通过判断语句实现音乐的切换功能。
4.算法的实现
傅里叶变换是时域与频域之间转换的重要工具。快速傅氏变换fft是一种用于计算离散傅里叶变换(dft)的一种快速算法,它是对离散傅里叶变换的一种改进,常用于通信领域。它是傅里叶变化的一大进步,对于计算机系统中的时频变换来说意义重大,根据奇、偶、虚、实等特性,它把原来复杂度为o(n ^2^ )的朴素多项式乘法转化为了o(nlogn)的算法。
dft的复杂度较高,不利于计算机计算,其计算表达式为
fft算法利用dft的奇偶相关特性,使时频变换算法复杂度大大降低,具体的算法原理可见文件夹“dsp_lib”中算法程序。
利用fft实现交互的程序设计也可参见主函数main。首先要进行模数转换,将电子元件中通过电压传递的模拟信号采样为数字信号,设计程序对数字信号进行缓存,缓存到一定数据量后对该段信号进行fft计算,得到其频谱数据;之后清楚数据,重复上述缓存及计算步骤。本设计需要采集的采样频率是10 khz^[14]^。本设计对adc缓存设计数量为256,即对256个时序信号点进行fft算法运算,然后反馈至oled显示。音频信号采集、fft运算及oled显示效果程序设计思路:程序系统每次进入adc_dma数据传输中断回滚函数后,就可以将adc_dma数据传输通道关闭,之后将 adc转换的数据展开傅里叶(fft)运算、计算各次谐波幅值,根据用户设定的特效模式,将各次谐波赋值代入到相应算法中,进行特效运算,最后oled显示音乐频谱效果。fft运算及oled显示流程如图所示。
5.主代码展示:
/* 变量定义 */uint16_t adc_buff[npt]; //adc缓存变量uint8_t adcconvend; //dma转换完成标志位long inbufarray[npt]; //输入数组long outbufarray[npt/2]; //输出数组long magbufarray[npt/2]; //谐波数组uint8_t flag;uint8_t key_flag; //按键标志位/* user code end pv *//* private function prototypes -----------------------------------------------*/void systemclock_config(void);/* user code begin pfp */void getpowermag(){ signed short lx,ly; float x,y,mag; unsigned short i; for(i=0; i< npt/2; i++) { lx = (outbufarray[i] < > 16; ly = (outbufarray[i] > > 16); //除以32768再乘65536是为了符合浮点数计算规律 x = npt * ((float)lx) / 32768; y = npt * ((float)ly) / 32768; mag = sqrt(x * x + y * y) / npt; if(i == 0) magbufarray[i] = (unsigned long)(mag * 32768); else magbufarray[i] = (unsigned long)(mag * 65536); //magbufarray[]为计算输出的幅值数组 }}/* 显示柱子高度 */void display(uint8_t x, uint8_t height){ uint8_t i, j, data, k; for(i=0; i< 8; i++)//显示高度 { oled_set_pos(x*4, i); if(((i+1)*8) <= (64-height)) data = 0x00; else{ if((((i+1)*8)-(64-height)) < 8){ data = 0; for(k=0; k >= 1; data |= 0x80; } } else data = 0xff; } for(j=0; j< 3; j++) { oled_wr_byte(data, oled_data); } }}
直流无刷风机盘管缺点
PCB的布线原则介绍
采用复杂控制逻辑器件和VHDL语言实现曼彻斯特编解码器的设计
Galaxy S21系列将提供以下颜色选项
映众GTX1660黑金至尊高清拆解图赏
基于STM32单片机的音乐频谱显示器设计
你不得不知道的玻璃激光切割工艺
CES Asia 2019:升级健康管理 惊帆科技携多款脉搏波健康监测产品亮相
怎样配置Java开发环境?
广东省首家5G智慧校园落户华南理工大学广州学院
印制板镀金工艺的钎焊性和键合功能
汽车模具高速切削加工技术应用
关于英飞凌CoolSiC MOSFET的抗短路能力
球阀的使用应注意哪些事项
神经网络如何帮助汽车实现识别幻影物体
Google发布了第二个Android Q Beta
向天再借一个肾!iphone8价格上涨部分可以买台华为mate9
福州智慧灯杆2.0版长啥样?
8GB和16GB内存的M1 MacBook性能有什么不同?
Microchip将为Mersen SiC电源协议栈参考设计提供碳化硅MOSFET和数字栅极驱动器