第二十四章 录放音频-K230声音采集与播放能力
🎯 本章目标:
掌握在 K230 开发板上实现音频录制与播放的方法。由于 K230 在 CanMV MicroPython 环境中不原生支持复杂音频编解码与 DAC 播放,本章将提供可行的音频处理方案,包括:
- 使用外接 I2S 麦克风进行音频采集
- 使用 PWM 模拟音频播放
- 通过串口或网络传输音频数据
- 结合外部模块(如 ESP32、专用音频芯片)实现完整音频功能
1. K230 音频能力现状
功能 | 支持情况 | 说明 |
---|---|---|
I2S 输入(麦克风) | ⚠️ 部分支持 | 可配置 I2S 采集 PCM 数据 |
I2S 输出(扬声器) | ❌ 通常不支持 | 固件未暴露完整播放 API |
PWM 模拟输出 | ✅ 可行 | 通过 GPIO 输出 PWM 模拟音频(低质量) |
音频编解码(WAV/MP3) | ❌ 不支持 | 无软件解码库 |
麦克风输入接口 | ✅ 支持 | 外接 I2S 麦克风(如 INMP441、SPH0645) |
📌 结论:
K230 更适合作为“音频采集终端”或“音频数据转发器”,不适合独立完成高质量音频播放。
2. 硬件准备
2.1 推荐外设
设备 | 型号 | 接口 | 用途 |
---|---|---|---|
I2S 麦克风 | INMP441、SPH0645 | I2S | 高质量录音 |
I2S 扬声器 | MAX98357A + PAM8403 | I2S | 音频播放(需外部驱动) |
PWM 播放 | 无源蜂鸣器或小喇叭 | GPIO | 简单提示音 |
音频协处理器 | ESP32、K210 | UART/SPI | 音频编解码与播放 |
3. 音频录制:I2S 麦克风采集 PCM 数据
3.1 硬件连接(以 INMP441 为例)
麦克风引脚 | K230 引脚 | 说明 |
---|---|---|
BCLK | I2S_BCLK(如 Pin13) | 位时钟 |
LRCLK | I2S_WCLK(如 Pin14) | 左右声道选择 |
DIN | I2S_SDIN(如 Pin15) | 数据输入 |
GND | GND | 地 |
VDD | 3.3V | 电源 |
3.2 FPIOA 映射与 I2S 初始化
from fpioa_manager import fm
from machine import I2S
# I2S 引脚定义
BCLK_PIN = 13
WCLK_PIN = 14
SDIN_PIN = 15
# FPIOA 映射
fm.register(BCLK_PIN, fm.fpioa.I2S0_BCLK)
fm.register(WCLK_PIN, fm.fpioa.I2S0_WCLK)
fm.register(SDIN_PIN, fm.fpioa.I2S0_SDIN)
# 创建 I2S 对象(输入模式)
i2s = I2S(
I2S.DEVICE_0,
mode=I2S.MODE_PDM_RX, # 或 MODE_I2S_RX
bits=I2S.BITS_16,
channel=I2S.CHANNEL_0,
rate=16000, # 采样率
align_mode=I2S.STANDARD_MODE # 标准 I2S 模式
)
⚠️ 注意:
不同麦克风使用不同模式(PDM 或 I2S),请查阅数据手册。
3.3 录制 PCM 音频数据
import time
import os
# SD 卡挂载(见第21章)
os.mount(sd, "/sd")
# 开始录音
print("开始录音...")
filename = "/sd/audio.raw"
f = open(filename, "wb")
try:
# 录制时长(秒)
DURATION = 10
start_time = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start_time) < DURATION * 1000:
# 读取音频数据块
audio_data = i2s.record(1024) # 返回 bytearray
f.write(audio_data)
print("已录制:", f.tell(), "字节")
print("✅ 录音完成:", filename)
except Exception as e:
print("❌ 录音失败:", e)
finally:
f.close()
i2s.finish()
✅ 生成文件:
audio.raw
为原始 PCM 数据,可在 PC 上用 Audacity 打开:
- 格式:Raw Data
- 编码:Signed 16-bit PCM
- 采样率:16000 Hz
- 声道:Mono
4. 音频播放:PWM 模拟输出(简单提示音)
4.1 使用 PWM 播放固定频率音调
from machine import Timer, PWM
from fpioa_manager import fm
# 定义蜂鸣器引脚
BUZZER_PIN = 12
fm.register(BUZZER_PIN, fm.fpioa.PWM0_OUT)
# 创建 PWM 对象
pwm = PWM(PWM.PWM0, freq=1000, duty=0.5, pin=BUZZER_PIN)
# 播放音调
def play_tone(frequency, duration_ms):
pwm.freq(frequency)
pwm.duty(0.5) # 50% 占空比
time.sleep_ms(duration_ms)
pwm.duty(0) # 停止
# 示例:播放“滴”声
play_tone(1000, 200) # 1kHz,200ms
✅ 用途:系统提示音、报警声
4.2 播放简单旋律
# 音符频率表(C调)
tones = {
'C4': 262, 'D4': 294, 'E4': 330, 'F4': 349,
'G4': 392, 'A4': 440, 'B4': 494, 'C5': 523
}
melody = [('C4', 200), ('E4', 200), ('G4', 200), ('C5', 400)]
for note, duration in melody:
play_tone(tones[note], duration)
time.sleep_ms(50) # 音符间隔
5. 播放录制的 PCM 音频(理论可行)
⚠️ 限制:K230 无法直接播放
raw
音频,但可通过 外部 DAC 或 ESP32 实现。
5.1 方案:串口转发到 ESP32 播放
# 在 K230 上发送音频数据
uart.write(audio_data) # 通过 UART 发送给 ESP32
ESP32 接收并使用
I2S
播放 PCM 数据。
6. 实战项目:语音记录仪(带状态提示)
# 结合 OLED 显示录音状态
import sensor
import i2s
import lcd
import time
# 初始化 I2S(略)
def record_with_prompt(duration=5):
# 提示音
play_tone(800, 100)
# 显示
lcd.fill(0)
lcd.draw_string(10, 10, "Recording...", color=(255,255,255))
# 录音
f = open("/sd/voice.raw", "wb")
start = time.ticks_ms()
while time.ticks_diff(time.ticks_ms(), start) < duration * 1000:
data = i2s.record(512)
f.write(data)
f.close()
# 结束提示
play_tone(1200, 100)
lcd.draw_string(10, 30, "Saved", color=(0,255,0))
7. 高级方案:外接音频协处理器
7.1 使用 ESP32 实现 MP3 播放
- K230 通过 UART 发送“播放 MP3”指令
- ESP32 接收指令,从 SD 卡读取 MP3 并播放
✅ 优势:实现完整音频功能,减轻 K230 负担
8. 常见问题与调试
❌ 问题1:I2S 无数据
排查:
- FPIOA 映射是否正确?
- 麦克风供电是否正常?
- 采样率是否匹配?
- 使用
i2s.record()
前是否初始化?
❌ 问题2:PWM 播放无声
解决:
- 检查引脚是否支持 PWM
- 蜂鸣器是否为有源/无源?
- 占空比是否为 0?
❌ 问题3:音频噪音大
优化:
- 使用差分麦克风(如 INMP441)
- 远离电源干扰
- 增加软件滤波(均值、FIR)
9. 性能与限制
操作 | 能力 |
---|---|
录音采样率 | 最高 16kHz ~ 32kHz |
位深 | 16 位 |
声道 | 单声道 |
播放质量 | PWM:低质量;需外接 DAC |
✅ 建议:
- 仅用于语音命令采集、提示音播放
- 高质量音频交由专用模块处理
✅ 本章你已掌握:
- I2S 麦克风音频采集
- PCM 数据录制到 SD 卡
- PWM 模拟音频播放
- 外部音频协处理器集成
- 音频数据传输与回放思路