- 系統設計主要涉及的有作為核心進行計算的STM32單片機的主控電路設計、實現藍牙電磁數據傳輸的MH-M18藍牙音頻采集電路的設計、負責提供音樂切換控制信號的按鍵狀態采集電路、對FFT變換計算所得頻譜進行展示的OLED顯示電路以及作為物理功放的LM386音頻放大電路設計。
- 原理圖:
3.程序框圖
主程序首先進行初始化,對系統的ADC、定時器、OLED等等進行初始參數配置,其后是對設計目標的計算工作。本設計主要分為三個大的模塊,一是藍牙的數據接收,二是音樂的傳輸播放,三是時域信號傅里葉變換后的頻域展示,其中最主要的是時域信號傅里葉變換后的頻域展示。主程序main中主要對頻譜在OLED上的顯示規則、FFT計算的相關需求進行了設計。
主程序的總體設計思路是系統開機后首先對STM32單片機內部進行復位,之后是對各項設置進行一個初始化操作,包括定時器、模數轉換器、通信協議等方面,然后程序開始正式運行,執行功放和FFT任務,進入循環和等待控制信號。
藍牙傳輸模塊的作用是接收源設備所發射的藍牙音頻信號,并提供給音頻放大電路進行放大及播放。藍牙傳輸子程序,首先需要判斷藍牙狀態,確認藍牙開啟后進行參數掃描,掃描后選擇目標設備來進行連接,連接成功之后即可根據指令進行音頻信號接收。本設計的藍牙音樂源為手機,因此需設置適用于手機傳輸的波特率,并于手機相連。
按鍵狀態采集程序是用于實現對音樂的切換,完成上一曲、下一曲及暫停功能。按鍵狀態的采集程序較為簡單,僅需要對按鍵狀態采集電路中各個按鍵的狀態作出判斷,當按下不同按鈕后,STM32單片機獲取到不同的狀態信息,從而通過判斷語句實現音樂的切換功能。
4.算法的實現
傅里葉變換是時域與頻域之間轉換的重要工具??焖俑凳献儞QFFT是一種用于計算離散傅里葉變換(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) > > 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< (((i+1)*8)-(64-height)); k++)
{
data > >= 1;
data |= 0x80;
}
}
else
data = 0xff;
}
for(j=0; j< 3; j++)
{
OLED_WR_Byte(data, OLED_DATA);
}
}
}
-
單片機
+關注
關注
6039文章
44583瀏覽量
636492 -
顯示器
+關注
關注
21文章
4990瀏覽量
140137 -
STM32
+關注
關注
2270文章
10910瀏覽量
356603 -
lm386
+關注
關注
9文章
101瀏覽量
54363 -
音頻放大電路
+關注
關注
7文章
34瀏覽量
26769
發布評論請先 登錄
相關推薦
評論