研究了一下,發現esp32cam的兩個DAC引腳被攝像頭占用了,分別是25和26,我們只能用I2S總線輸出數字音頻,之后用MAX98357模塊將數字信號轉成模擬信號,下面是代碼:

匯入模塊和定義引腳:
from machine import I2S
from machine import Pin
import time
# 初始化引腳定義
sck_pin = Pin(14) # 串行時鐘輸出
ws_pin = Pin(13) # 字時鐘
sd_pin = Pin(12) # 串行資料輸出
# 初始化i2s
audio_out = I2S(1,sck=sck_pin,
ws=ws_pin,
sd=sd_pin,
mode=I2S.TX,
bits=16,
format=I2S.MONO,
rate=16000,
ibuf=20000)
# 下面是官方檔案,Google翻譯的,不準確,可以自己去翻看
'''
sck 是串行時鐘線的引腳物件
ws 是單詞選擇行的引腳物件
sd 是串行資料線的引腳物件
mode 指定接識訓發送
bits 指定樣本大小(位),16 或 32
format 指定通道格式,STEREO(左右聲道) 或 MONO(單聲道)
rate 指定音頻采樣率(樣本/秒)
ibuf 指定內部緩沖區長度(位元組)
'''
引腳接線:
ESP32 CAM --- MAX98357
GPIO14 --- BCLK
GPIO13 -- LRC
GPIO12 -- DIN
GND -- GND
5V -- VCC
(建議焊接,插接的方式會導致雜音或者無法播放)
代碼部分:
方法一:
wavtempfile = "temp.wav"
wav = open(wavtempfile,'rb')
print('播放音頻')
# 讀取音頻檔案的二進制資料
buf = wav.read()
# wav檔案的頭部資料,不是實際的音頻資料,是檔案資訊,所以我們要丟棄這部分資料
bufhead = 44
# 實際音頻資料大小,等于總大小減去頭部資訊的大小
bufsize = len(buf) - bufhead
# 緩沖區大小,前面初始化的時候設定的最后一個引數
bufcap = 20000
# 寫入DAC的次數
bunum = 1
# 要寫入的資料 開始位置
bufstart = bufhead
# 回圈讀取
while bufsize:
# 讀取結束位置,等于讀取次數*緩沖區大小
bufend = bufcap * bunum
# 當結束位置大于總資料長度的時候,結束位置等于資料最后一位
if bufend > len(buf):
bufend = len(buf)
# 要寫入的資料
bufwrite = buf[bufstart:bufend]
# 寫入資料
num_written = audio_out.write(bufwrite)
# 總大小減去每次寫入的大小
bufsize -= len(bufwrite)
# 重新設定讀取位置,為上次結束后一位
bufstart = bufend
# 讀取次數
bunum = bunum + 1
# 在最后一個檔案區間寫入完畢后,計算最后的檔案播放需要的時間,不然會播放不完整
times = len(bufwrite) * (1/16000)
# 關閉檔案
wav.close()
# 等待播放完畢
time.sleep(times )
# 取消初始化 I2S 總線
audio_out.deinit()
print('播放完畢')
方法二:
wavtempfile = "temp.wav"
wav = open(wavtempfile,'rb')
# 前進到WAV檔案中資料段的第一個位元組
pos = wav.seek(44)
#分配樣本陣列
#用于減少while回圈中堆分配的記憶體視圖
wav_samples = bytearray(1024)
wav_samples_mv = memoryview(wav_samples)
print('播放音頻')
#從WAV檔案中連續讀取音頻樣本
#并將其寫入I2S DAC
while True:
try:
num_read = wav.readinto(wav_samples_mv)
num_written = 0
#WAV檔案結束
if num_read == 0:
break
#前進到資料段的第一個位元組
# pos = wav.seek(44)
else:
#回圈,直到所有樣本都寫入I2S外圍設備
while num_written < num_read:
num_written += audio_out.write(wav_samples_mv[num_written:num_read])
except Exception as e:
print('錯誤,',e)
break
times = len(wav_samples_mv[num_written:num_read])
最后關閉檔案,注銷i2s
wav.close()
# 等待播放完畢
time.sleep(times )
# 取消初始化 I2S 總線
audio_out.deinit()
完成后:
esp32cam使用i2s驅動max98357播放音頻
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/298196.html
標籤:其他
