首頁 > 評測 > 第二篇 嵌入式系統(tǒng)硬件輸出系統(tǒng)簡介及播放實驗(播放篇之一)
第二篇 嵌入式系統(tǒng)硬件輸出系統(tǒng)簡介及播放實驗(播放篇之一)
- [導(dǎo)讀]
- Everyboard Can Sing
21ic打算攜手資(tu)深(ding)直男癌晚期工程師zhanzr21,來給大家講一講嵌入式系統(tǒng)與音頻處理的故事。
關(guān)于zhanzr21:
曾經(jīng)混跡于兩岸三地,摸爬滾打在前端后端,搞過學(xué)術(shù)上過班。現(xiàn)在創(chuàng)業(yè)中,歡迎各種撩
點擊鏈接加入群【嵌入式音頻信號處理】:https://jq.qq.com/?_wv=1027&k=45wk8Ks
嵌入式音頻專用資料代碼分享:https://pan.baidu.com/s/1dFh5pWd
前言
此章僅為最基本的播放原理介紹, 還有不少關(guān)於播放的內(nèi)容由于篇幅與活動配套安排等原因沒有包含在此, 所以在標題上加 播放篇之一, 后面的章節(jié)中也會有對這個話題的繼續(xù)討論.
1.基本的播放原理與硬件組成
從原理上講,數(shù)字系統(tǒng)播放聲音就是把聲音的樣本數(shù)據(jù)轉(zhuǎn)換成人耳能感覺到的變化.上一章的文章中我們已經(jīng)體驗過聲音的數(shù)字形式.那么將這種數(shù)據(jù)如何轉(zhuǎn)換為最終能感覺到的變化呢.理論上的功能Block如下:

圖 音頻播放的理論Block
這里依次說明.
1. 控制系統(tǒng),負責控制生成數(shù)據(jù)或者讀取數(shù)據(jù)(可能需要解壓或其他操作),并將其交給下一級的DAC,一般來講這個指的是MCU/DSP/CPU/FPGA這樣的器件.
2. 數(shù)據(jù)即是音頻數(shù)據(jù),可以是控制系統(tǒng)即時生成的也可以是讀取其它系統(tǒng)處理好的數(shù)據(jù).一般而言,除了實驗性質(zhì)或者創(chuàng)作性質(zhì)的系統(tǒng),數(shù)據(jù)一般是其它系統(tǒng)生成存放在存儲器中的數(shù)據(jù).
3. DAC負責把數(shù)字轉(zhuǎn)換成模擬.這個DAC可以是內(nèi)部DAC也可以是外部DAC.甚至可能是個假的DAC(數(shù)字口+低通濾波器).
4. 功率級將DAC的輸出進行功率放大,功率級視乎后面的輸出設(shè)備需求來決定其性質(zhì).可以是管子(FET,BJT,電子管),也可能是集成電路. 現(xiàn)代音頻系統(tǒng)中集成電路放大器居多.如果后一級的負載足夠小, 這一級可以省掉, 后面的實驗會進一步詳細解釋.
5. 輸出設(shè)備一般而言就是揚聲器(音箱或者耳機中的揚聲器).
2.實際硬件原理分析 (硬件DAC直接輸出)
這里給出我搭建的幾個音頻播放的硬件例子以助理解.
1.系統(tǒng)之一:Nucleo板子+有源音箱
首先來看看DAC+音箱形式.

圖 DAC+有源音箱形式
左邊是一個ST的Nucleo開發(fā)板子,具體型號是STM32F722ZE. 但是絕大多數(shù)的類似板子都能替代. 音頻信號通過芯片內(nèi)部的DAC輸出到音箱的輸入級. 音箱須為有源音箱(帶電源的就是有源音箱, 本文例子使用的就是網(wǎng)上買的幾十塊錢包郵的USB音箱, 如果是無源音箱, 需要另外增加功率分大級. 根據(jù)作者的經(jīng)驗, 你能找到的音箱絕大多數(shù)是有源音箱).
我們看看連接的細節(jié):

圖 耳機接口細節(jié)
這是個耳機接口座子+杜邦線改裝出來的連接器, 左右兩根線是左右聲道信號, 當中那個是共地. 本文所討論的音頻系統(tǒng)除非另外說明都為單聲道, 故此只會使用左右兩通道中的之一加下面那根地線.
大多數(shù)的MCU自帶DAC為兩個或以上的通道, 足夠完成簡單的立體聲輸出了. 為討論簡便, 先只用單聲道做實驗, 所以只會用到一個DAC輸出. 這是Nucleo板上的連接, 一個DAC輸出(PA5,DAC通道2), 一個地.

圖 DAC連接細節(jié)
2.系統(tǒng)之二: Nucleo板子+耳機

圖 DAC+耳機形式
按照數(shù)據(jù)手冊,ST的DAC是無法直接驅(qū)動耳機的.

圖 F722數(shù)據(jù)手冊中關(guān)于DAC的負載參數(shù)
這里發(fā)揚(不怕燒壞板子燒壞耳機的)探索精神, 使用STM32F722的DAC直接驅(qū)動32 Ohm耳機, 經(jīng)試驗是可以進行播放的. 當然當做產(chǎn)品長時間運行這樣是有點吊兒郎當?shù)? 此處只是做實驗. 如果你沒有心理準備或者接受不了這種冒險行為, 請勿模仿!
3.系統(tǒng)之三: Nucleo板子+功放板+揚聲器
這個系統(tǒng)應(yīng)該是屬于本章目前為止分析的最正統(tǒng), 最教科書式的系統(tǒng)構(gòu)造了.

圖 DAC+功放板子+揚聲器
DAC輸出信號到功放板,功放板驅(qū)動揚聲器. 其實這個系統(tǒng)跟第一個有音箱的系統(tǒng)在架構(gòu)上是一模一樣的. 只是把音箱拆開了開膛破肚, 把功放板與揚聲器拿出來, 大家更容易看明白信號的走向流程. 圖片中的功放板子是用的Adafruit做的一個板子, 作者自己打的板子將在后文中介紹.

圖 D類音頻功放板子
這里補一句, 一般而言音頻功放分為AB類和D類. 當然還有許多其他類以及變種, 但是用得最多的就是AB類和D類. 兩者的差別用一句話概括:
AB類效果好,D類效率高.
具體關(guān)于兩種放大器的分析與仿真作者打算使用自制的板子再開一篇來講. 這里先跳過去.
至于揚聲器,這里是作者從舊的筆記本上拆的,我想大家應(yīng)該都能在家中找到這樣的舊的揚聲器吧. 揚聲器上標的+-跟馬達/無源蜂鳴器/燈絲燈拋一樣, 只是個接線參考, 兩極從電路原理上講是對稱的.

圖 舊筆記本上拆的揚聲器
以上三個系統(tǒng)都是本人為了說明音頻播放原理而搭建的簡化型的系統(tǒng). 這些系統(tǒng)便于說明原理, 也能夠用作大家自己動手的參考. 事實上實際的音頻系統(tǒng)中很少直接使用處理器的ADC/DAC來播放音頻, 而經(jīng)常使用專用的Codecs來處理音頻. 這些Codecs都是專門為音頻應(yīng)用優(yōu)化過的ADC/DAC, 有的還加入了運放電路,DSP處理模塊等等. 在成本與性能上都大大優(yōu)于處理器自帶ADC/DAC. 本文在介紹基本原理時使用這些通用ADC/DAC, 在此之后將回到使用專用Codecs的更加主流的道路上來. 如果看過第一篇的讀者, 應(yīng)該會記得曾經(jīng)介紹過的F769-Discovery板子上的音頻系統(tǒng),那就是使用的專用Codecs: WM8994. 作者也會做一些測試板子來配合文中的內(nèi)容.
4.播放實驗之一(DAC+定時器播放生成音頻)
硬件介紹差不多了, 現(xiàn)在開始寫代碼了. 讀者如果要試驗本章配套代碼, 需要搭建的硬件就是上面所述的三種之一. 從軟件角度來說, 這三種硬件中控制器所需要做的工作就是將數(shù)據(jù)從DAC中發(fā)出去就行了. 具體而言, 就是將數(shù)據(jù)以目標采樣率的速度把數(shù)據(jù)發(fā)到DAC上, 就是這么簡單. 為求最迅捷的展示原理, 這里使用的音頻參數(shù)為:
8bit PCM * 單通道 * 8K采樣率
這個參數(shù)今天看來很寒酸,可是退回一二十年, 這樣參數(shù)的硬件可都是高端人士才用的起的數(shù)字音頻系統(tǒng)哦.作為嵌入式系統(tǒng),實現(xiàn)這種參數(shù)也是能接受的.
程序的結(jié)構(gòu)很容易構(gòu)思:

圖 最簡單的音頻播放程序結(jié)構(gòu)圖
以STM32F722ZE板子為例,主系統(tǒng)跑216MHz, 使用定時器6作8KHz的更新中斷, 那么Period設(shè)定為
P = (216000000/2)/8000 = 13500
這里順便碎碎念一下子采樣率與主頻率的關(guān)系. 當使用定時器6的時, 采樣率8K/16K/32K/48K/96K/144K都能計算得到整數(shù)的更新Period, 也就是都能得到無更新誤差的輸出精度.但是使用11.025K/22.05K/44.1K這樣的采樣率時得不到整數(shù)的更新Period, 也就是播放這種采樣率的音頻的時, 需要重新配置時鐘源才能得到無更新誤差的回放精度. 在音頻系統(tǒng)中經(jīng)常會有這樣的問題, 切換采樣率需要重新配置時鐘. 一旦主頻時鐘定了,某些采樣率是怎么也配置不了無更新誤差的. 在使用I2S接口這樣的外部Codecs時候原理也跟這個類似. 關(guān)于這個采樣率定時誤差后面的章節(jié)會再次詳敘.
在定時器ISR中做個標記,表示125us的節(jié)點到了,主函數(shù)該更新輸出了:
/* USER CODE BEGIN TIM6_DAC_IRQn 1 */
g_Tim6_Flag = true;
/* USER CODE END TIM6_DAC_IRQn 1 */
main文件中定義如下幾個宏用于生成播放數(shù)據(jù):
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define TEST_SAMPLE_RATE 8000
#define AUDIO_HZ 200
#define AUDIO_CYCLE (TEST_SAMPLE_RATE / AUDIO_HZ)
#define PULSE_HZ 4
#define PULSE_CYCLE (TEST_SAMPLE_RATE / PULSE_HZ)
主函數(shù)中的主循環(huán):
while (1)
{
if(true == g_Tim6_Flag)
{
//Play Next sample
//This demo play pulsed sine wave, if you want to play other shape of audio, please read the last article of this series,
//and modified the next line of data feeding
if(0==((time_index/PULSE_CYCLE)%2))
{
tmpSample = INT8_MAX * ((sin(M_PI*2*(time_index%AUDIO_CYCLE)/AUDIO_CYCLE)) + 1);
//Note: this macro is deliberately defined without parentness for simplication
#warning This gain is very important if you test the playback with an earphone,
too little you will not here audible sound, too loud your ears are in risk.
I suggest you start from a little value and adjust up.
#define TEST_GAIN 1/7
tmpSample = (uint8_t)(tmpSample * TEST_GAIN );
#undef TEST_GAIN
}
else
{
tmpSample = 0;
}
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_8B_R, tmpSample);
time_index ++;
HAL_DAC_Start(&hdac, DAC_CHANNEL_2);
HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
/* check the end of the file */
//No end for generated data, if you need to stop at some point, uncomment next block
// if(SOME_POINT == time_index)
// {
// while(1);
// }
g_Tim6_Flag = false;
}
}
完整代碼請參考共享文件夾. 這里播放的是2Hz脈沖(跳變頻率為4Hz)的200Hz正弦波. 聽到應(yīng)該是 嘟-嘟-嘟 這種效果. 關(guān)于如何生成該種波形, 請參考上一篇的內(nèi)容. 還說一點就是增益設(shè)置, 如果是音箱或者功放板子那倒無所謂, 如果用耳機收聽建議先將增益調(diào)小一點試驗(本文實驗中設(shè)置的1/7), 覺得聲音小了, 慢慢往上調(diào)整以保護你的耳朵.

圖 DAC實際輸出波形
5.播放實驗之二(DAC+定時器播放raw音頻)
上一章與上一節(jié)所講的播放這種計算出來的數(shù)據(jù)大致有兩種用途:
· 可以測試我們的系統(tǒng)是否工作,頻率響應(yīng)等等參數(shù)的測量都需要生成周期性的信號.
· 有藝術(shù)家這樣創(chuàng)作音樂.
除此之外, 大多數(shù)情況下音頻系統(tǒng)還是應(yīng)用在播放其他人已經(jīng)錄制/處理好的聲音. 這里播放一個作者處理好的8K/8bit的一段raw音頻為例作實驗. 至于如何處理這樣的文件下節(jié)馬上介紹. 這里先使用本文附帶資源中的文件作實驗.
共享文件夾 Chapter2coderesource 8k8bit_mono_raw_sample.bin
這個文件大小為: 125548, hex表示是0x1EA6C, 實驗使用的STM32F722ZE的Flash大小是0x80000, 這里將此文件燒錄在Flash的末端以0x08060000開始的位置.
首先打開STM32 ST-LINK Utility.exe,連接板子:

圖STM32 ST-LINK Utility.exe打開bin文件
點燒錄,注意選地址: 0x08060000.

圖 選地址燒錄
點Start開始燒錄.
再修改程序,上 一節(jié)的程序為更新DAC前計算采樣值. 將其改為從Flash取數(shù)據(jù)即可:
關(guān)鍵代碼:
#define RAW_FILE_ADDRESS 0x08060000
#define RAW_FILE_SIZE 125548
uint8_t* PlaybackPosition = (uint8_t*)RAW_FILE_ADDRESS;
....
//Play Next sample
HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_8B_R, *((uint8_t *)(PlaybackPosition)));
PlaybackPosition ++;
完整代碼請參考共享文件夾工程.
編譯之后下載就可以聽音樂了. 歌曲是老版本TVB拍的聊齋的主題曲<<隔世情>>的片段,也不知道讀者是否喜歡這種風格. 如果想播放你們想聽的歌曲, 請繼續(xù)閱讀下一節(jié)就能自己處理了.這里解釋一下子程序與音樂在Flash中的關(guān)系圖:

圖 音頻數(shù)據(jù)與程序在Flash中的分布圖(非比例)
一瞬間有一種馮諾伊曼架構(gòu)的感覺, 不過這是開玩笑的, 實際上M7是哈佛結(jié)構(gòu).
6. 將任意音頻文件處理成8K/8bit的raw數(shù)據(jù)
任意找一個你喜歡的音頻文件,比如xyz.mp3.用Audacity打開,注意首次Audacity打開mp3的話需要另外安裝插件. 這個通過軟件提示應(yīng)該很容易完成. 這里篇幅原因不介紹這個了.如果不想裝插件包, 請找個ogg格式或其他軟件自身支持的格式也是一樣操作.

圖 打開你要轉(zhuǎn)的文件
一般而言電腦上的音樂文件一般為雙通道的立體聲歌曲,這里為了后面簡單處理,將其合并為單通道.(立體聲的處理以后會講到.)

圖 立體聲至單聲道
重采樣,44.1KHz->8KHz,再將工程采樣率改成8KHz:

圖 重采樣
截取一段音頻,導(dǎo)出,因為只分配了128K的空間給音頻數(shù)據(jù),所以最多只能截取:
128K/(8K*8/8) = 16秒
的片段.(以后我們會講壓縮,以及外部存儲的.)

圖 選取并導(dǎo)出
注意選擇格式,最好把采樣率與位寬反映在文件名中,以便以后使用.

圖 選取格式
至此就可以燒錄播放了, Enjoy!
如果與上次生成的音頻數(shù)據(jù)長度不同的話,注意代碼中文件長度相應(yīng)的定義也需要改一下子,否則播放的后段會有以前的殘余數(shù)據(jù).
此篇至此為止,懇請讀者多多反饋指教.
后記
這篇介紹了最基本的音頻播放原理, 關(guān)于播放這個話題還有很多內(nèi)容沒有覆蓋, 比如Arduino開發(fā)板子播放音頻, PWM+LPF播放原理仿真, I2S接口信號介紹, SAI簡介,作者自制的音頻播放板子也沒有登場等等等. 暫時計劃將多余的內(nèi)容分成附錄形式在以后的章節(jié)順帶發(fā). 當然還得聽編輯與讀者的意見.
代碼與資源共享地址: https://pan.baidu.com/s/1dFh5pWd
-
- 本文系21ic原創(chuàng),未經(jīng)許可禁止轉(zhuǎn)載!
網(wǎng)友評論
- 聯(lián)系人:巧克力娃娃
- 郵箱:board@21ic.com
- 我要投稿
-
歡迎入駐,開放投稿
-
人均百萬?英偉達中國員工收入曝光! 2024-08-29
-
《黑神話:悟空》玩家硬盤升級攻略:提升游戲體驗,暢享3A大作 2024-08-29
-
數(shù)睿數(shù)據(jù)參加《系統(tǒng)與軟件工程 低代碼開發(fā)平臺通用技術(shù)要求》國家標準編制 2024-08-29
- NRF52810藍牙數(shù)字耳機找人定制
預(yù)算:¥30005天前
- 125KW模塊式PCS軟硬件外包開發(fā)
預(yù)算:¥1100000015小時前
- 12V汽車啟動電源項目BMS設(shè)計
預(yù)算:¥50000023小時前
- 數(shù)據(jù)可視化軟件 開發(fā)
預(yù)算:¥5000023小時前
- PLC項目調(diào)試修改
預(yù)算:¥100001天前
- 起動電機控制器開發(fā)
預(yù)算:¥1100001天前