目錄
- STC8H開發(一): 在Keil5中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(二): 在Linux VSCode中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(三): 基于FwLib_STC8的模數轉換ADC介紹和演示用例說明
- STC8H開發(四): FwLib_STC8 封裝庫的介紹和使用注意事項
- STC8H開發(五): SPI驅動nRF24L01無線模塊
- STC8H開發(六): SPI驅動ADXL345三軸加速度檢測模塊
- STC8H開發(七): I2C驅動MPU6050三軸加速度+三軸角速度檢測模塊
- STC8H開發(八): NRF24L01無線傳輸音頻(對講機原型)
關于PWM, DAC和音頻
PWM是脈沖寬度調制的縮寫, 因為介紹的文章很多, 自己做功課即可, 參考
- 維基百科 Pulse-width_modulation
- 百度百科 PWM技術
大部分低端MCU不帶DAC轉換, 但是可以使用PWM模擬, 對于音頻傳輸
- 人普通談話的聲波頻率在500-2000Hz之間, 人耳可以聽到的聲波的頻率范圍在20Hz至20kHz之間
- 用于通話, 8kHz的帶寬就能達到較好的語音傳輸效果
- 通過PWM模擬DAC, 因為PWM是方波, 其頻率會引入底噪, 底噪的頻率是PWM頻率的倍數
- PWM頻率在8KHz時, 在聽感上底噪很大, 與傳輸的音頻一樣明顯, 將PWM的頻率調節到16kHz以上才能有效抑制底噪
無線音頻傳輸的實作
發送部分

接收部分

以下實作的是單聲道 8kHz 8bit 采樣的音頻信號傳輸
發送部分
發送部分需要實作的是8kHz采樣, 并通過NRF24L01將每秒的8000位元組資料發送出去.
語音輸入
語音輸入可以使用駐極體話筒加S9013放大輸入或者直接使用MAX9814. 在測驗階段建議使用后者, 可以保證采樣輸入不失真, 在調通后再用駐極體話筒電路替換.
ADC音頻采樣
因為ADC采樣需要實作準確的每秒8000采樣, 所以不能用DMA方式, 在STC8H(包括STM32等其它MCU)下, 無法在DMA情況下精確調節每秒的采樣個數, 因為ADC的采樣頻率, 采樣周期和轉換周期在不同MCU中都是固定的, 所以很難正好做到8kHz的采樣. 具體的實作中有兩種方式:
1.定時器驅動采集
通過定時器設定為8kHz, 在中斷中發起ADC轉換, 是比較容易實作的. 這時候需要將ADC也實作為中斷方式, 因為ADC的轉換時間比較長, 如果在定時器中斷中做同步的ADC轉換, 容易影響主行程. 需要有定時器的中斷處理和ADC的中斷處理, 定時器的中斷處理單純用于發起轉換, ADC的中斷才用于讀出結果.
2.連續采集定時讀取
通過定時器設定為8kHz, 將ADC的采集設定為回圈方式(中斷采集, 但是在中斷時再次發起), 在定時器中斷中僅僅讀取采集結果. 這種方式也能實作8kHz的采樣. 因為這種方式實際上會多消耗電量, 所以實際使用中還是采用了前一種方法.
NRF24L01發送
NRF24L01在設定為1Mbps帶寬時實際傳輸速度能達到23k位元組每秒, 因此對于8bit 8kHz采樣的傳輸是沒問題的. 因為NRF24L01傳輸時的回應和重發機制, 在信號不好時, 容易導致發送中斷, 為了避免傳輸時間的波動影響, 在實作中使用了雙陣列做緩沖. 采樣到發送之間的邏輯為
- 兩個256位元組陣列作為全域變數, 同時定義變數指向當前寫入的陣列編號和寫入位置
- ADC中斷讀取結果時, 往當前編號的陣列和位置中寫入并移動位置, 當寫滿一個陣列時, 將此陣列標記為可發送, 并切換到下一個陣列繼續寫入
- 在主行程中, 判斷當前是否有可發送的陣列, 如果可發送, 則在回圈中按32個位元組一組將資料全部發送.
因為在正常收發的信號強度下, NRF24L01的發送速度是比采樣速度快的, 所以基本上NRF24L01的發送是發送 -> 等待 -> 發送的狀態
接收部分
接收部分要實作的是將NRF24L01接收到的資料進行存盤, 并按照8kHz的頻率, 將每個值設為PWM輸出的占空比, 實作DAC模擬
RNF24L01接收
因為NRF24L01發送是集中發送, 而PWM還原是勻速的, 所以在接收也需要有緩沖, 接收的機制和發送相似
- 兩個256位元組陣列作為全域變數, 同時定義變數指向當前寫入的陣列編號和寫入位置
- NRF24L01通過中斷接收資料, 在接收時, 往當前編號的陣列和位置中寫入并移動位置, 當寫滿一個陣列時, 將此陣列標記為可用, 并切換到下一個陣列繼續寫入
PWM模擬DAC還原
初始化一個PWM輸出, PWM周期為256對應8bit的占空比調節范圍, 確保PWM頻率不低于16kHz. 在8kHz定時器的中斷中, 判斷當前讀取的陣列和位置, 每次讀取一個值, 并將其設定為PWM占空比. 如果陣列不可用, 就不做任何操作, 如果此時將占空比設為0, 會產生噪音.
音頻輸出
測時階段, 可以在PWM輸出上串聯一個200R的電阻后值連喇叭, 可以聽到輸出的音頻. 這個電阻不能太小, 測驗中如果阻值小于100R, 會導致MCU供電不足反復重啟. 在確定音頻輸出沒問題后, 可以替換為 PAM8403 音頻放大模塊.
在使用 PAM8403 模塊時
- 模塊需要獨立供電, 測驗中如果與MCU都使用USB2TTL供電, 會使MCU供電不足而導致聲音輸出例外
- 模塊與MCU的輸出可以不共地, 即模塊MCU的PWM輸出和地, 可以直接接入PAM8403的音頻輸入
- 因為是單聲道信號, 所以只能用PAM8403的一個聲道, L或者R都可以
演示代碼
- GitHub FwLib_STC8/tree/master/demo/spi/nrf24l01_audio
- Gitee FwLib_STC8/tree/master/demo/spi/nrf24l01_audio
接線說明
在測驗中發送部分使用的是 STC8H3K32S2, 接收部分使用的是 STC8H1K08, 你可以使用STC8H系列的任意一個型號
共同的連接部分(NRF24L01)
8H3K32S2/8H1K08 NRF24L01
P35(SS, Ignored) => CSN 16
P34(MOSI) => MOSI 15
P33(MISO) => MISO 14
P32(SPCLK) => CLK 13
P36(INT2) => IRQ 17
P37(IO) => CE 18
發送部分
STC8H3K32S2 MAX9814
P11(ADC1) => MIC
3.3V => VDD
3.3V => GAIN
GND => A/R
GND => GND
ADC, 如果是STC8H3K32S2, 使用ADC采樣需要將AVcc, AGnd 和 ADC_Vref+ 正確連線
AVcc => 3.3V
AGnd => GND
ADC_Vref+ => 3.3V
P11 => Output(MAX9814) or MIC
接收部分
STC8H1K08 PAM8403
P10(PWM1P) => 200R => L or R Input
GND => _|_ Input
Ext 3.3V/5V => VCC
Ext GND => GND
注意:
- MCU的pin腳布局不一定相同, STC8H3K32S2和STC8H1K08都是20pin的封裝, 但是pin腳布局就不一樣
- 燒錄發送部分和接收部分時, 注意要調換 nrf24l01.c 中的 RX_ADDRESS 和 TX_ADDRESS
效果演示
B站視頻 https://www.bilibili.com/video/BV1kZ4y1Z78v
除錯說明
因為這個演示實際上包含了定時器, ADC采樣, NRF24L01發送, 接收, PWM調制這幾個環節, 任一個環節出問題, 都會導致演示失敗. 在除錯中, 需要遵循化整為零, 逐個確認的原則, 對每個節點是否作業正常進行確認.
定時器除錯
因為8kHz的輸出較難觀測, 可以用一個uint16_t的全域變數自增到8000后串口輸出觀察時間間隔是否正確
ADC除錯
- 先通過同步模式, 查看ADC采集是否正確, STC8H1K和STC8H3K的ADC接線是不一樣的, 如果接線不正確, 輸出的就是噪音.
- 同步采樣沒問題后, 再通過中斷方式采集檢查是否正確
- 中斷沒問題后, 就可以結合定時器, 通過定時器發起采樣
NRF24L01 除錯
可以參考前面的例子SPI驅動nRF24L01無線模塊 單獨運行 NRF24L01 進行收發是否功能正常
PWM 除錯
有條件的可以用邏輯分析儀, 輸出正常后, 用音頻進行測驗, 可以參考PWM輸出音頻這個例子, 回圈播放一段8bit音頻檢查PWM輸出是否正確, 因為音頻較大, 測驗這個需要使用Flash容量至少32K位元組的芯片, 例如STC8H3K32S2.
最小系統聯調
最小系統的發送端先不使用ADC, 使用固定的8bit音頻作為輸入進行發送, 接收端先不外接音頻放大, 直接用200歐串聯小喇叭進行檢查, 作業正常的情況下, 音頻播放效果應當是非常好的
在最小系統聯調沒問題后, 就可以開始除錯ADC, 沒問題后最后加入音頻放大模塊.
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/422972.html
標籤:嵌入式
