演示代碼
GitHub FwLib_STC8/tree/master/demo/spi/nrf24l01_audio
Gitee FwLib_STC8/tree/master/demo/spi/nrf24l01_audio
使用說明 https://www.cnblogs.com/milton/p/15852161.html
無線音頻傳輸的實現
大部分低端MCU不帶DAC轉換, 但是可以使用PWM模擬, 對于音頻傳輸
- 人普通談話的聲波頻率在500-2000Hz之間, 人耳可以聽到的聲波的頻率范圍在20Hz至20kHz之間
- 用于通話, 8kHz的帶寬就能達到較好的語音傳輸效果
- 通過PWM模擬DAC, 因為PWM是方波, 其頻率會引入底噪, 底噪的頻率是PWM頻率的倍數
- PWM頻率在8KHz時, 在聽感上底噪很大, 與傳輸的音頻一樣明顯, 將PWM的頻率調節到16kHz以上才能有效抑制底噪
發送部分
發送部分需要實現的是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都可以
接線說明
在測試中發送部分使用的是 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, 沒問題后最后加入音頻放大模塊.
|