SF32LB52制作一款语音盒子

2026-11-121
AI 快速预览详细 收起
本文介绍了如何使用SF32LB52制作一款语音盒子,详细解析了从麦克风采集到功放输出的完整链路。首先,蓝牙配对成功并不意味着互联网可用,需要进一步检查PAN连接事件、网络参数与会话握手。麦克风偏置和功放供电也会影响声音质量。音频回调按16kHz、单声道、16bit PCM工作,每10ms采样320字节,累计到60ms后通知编码线程。压缩、重采样和功放门控接力完成播放。屏幕亮起只说明显示链路走通了一部分,还需要检查复位、SPI时钟等。沿着这块板子的声音路径,模拟电路、实时调度和网络协议之间的关系就清楚了。

SF32LB52 插件版语音盒子的显示与按键布局

屏幕显示会话状态,两个实体按键承担交互,音频采集与播放由盒内的插件板完成。

蓝牙已经配对,屏幕也能显示表情,设备却没有回应,这类现象很容易被归结为网络不好。对于 SF32LB52 语音终端,真正需要追踪的是一条完整链路。麦克风先把声音送进片上音频单元,固件再完成缓存、编码和网络传输,返回的语音还要经过解码、采样率转换与功放,才能从喇叭里出来。

这块立创插件版小智板把主控集中在 LC-OPEN-SF32LB52-MOD-N16R8 模组上,外围使用较多直插器件,方便观察电路和排查焊接问题。下面沿着声音的去向,把联网条件、模拟前端和固件调度放到一起看。电路参数按公开的 1.3 版原理图讨论,板卡后续修订不能直接套用同一套阻容值。

蓝牙连接以后还要有一条 IP 通道

SF32LB52 没有 Wi-Fi 外设,这个方案通过手机的蓝牙网络共享接入互联网。板子作为 PANU 终端,手机提供 NAP 网络接入服务,BNEP 在经典蓝牙链路上封装网络帧,板内的 lwIP 再处理 IP、TCP 等上层通信。

因此,蓝牙配对成功和云端会话建立是两个阶段。手机还要开放网络共享,设备才能继续完成地址配置、域名解析和应用连接。这里传送的是压缩语音与控制消息,不能把它理解成蓝牙耳机的音频播放通道。

语音终端经手机蓝牙网络共享连接云端的分层链路

采集和播放留在板端,手机承担网络接入,语音识别与回复生成由云端服务完成。

main.c 收到连接请求后,明确指定要建立 PAN 配置文件连接。

if (value == BT_APP_CONNECT_PAN)
{
    if (g_bt_app_env.bt_connected)
    {
        bt_interface_conn_ext((char *)&g_bt_app_env.bd_addr,
                              BT_PROFILE_PAN);
    }
}

这段代码只负责发起 PAN 连接。把它执行过当成互联网已经可用,会让后面的排查失去层次。更有效的顺序是先确认蓝牙链路,再看 PAN 连接事件,随后检查网络参数与会话握手。当前工程默认配置走 WebSocket 分支,同时保留了可切换的 MQTT 分支,两条路径应分别核对。

麦克风需要偏置,功放需要独立看待供电

1.3 版电路中,驻极体麦克风正端通过 R3 接到 MIC_BIAS,同一信号节点进入 MIC_ADC_IN,负端接地。偏置为麦克风内部器件提供工作电流,声压引起的变化叠加在直流工作点上,再交给音频 ADC 采样。输入节点还并联了 10nF 电容,它会和前端等效阻抗一起影响高频响应。

麦克风偏置与功放输出两条模拟路径

麦克风围绕偏置点采集小信号,喇叭跨接功放的两个输出端,两者的接地方式不能混用。

图中 R3 为 10kΩ。这个值决定了偏置回路的一部分工作条件,并不是越小录音就一定越好。修改时要同时检查麦克风工作点、ADC 输入范围和频响,不能只根据听感提高增益,也不能把某一组 RC 的计算结果当成整个采集系统的带宽。

播放侧使用 LM4871N。模组的 AU_DAC1P、AU_DAC1N 经过耦合电容和阻容网络进入功放,喇叭接在 VO1、VO2 之间。这是桥接输出,喇叭任意一端都不应当作地线。测量输出波形也应使用合适的差分测量方式,不能把接地探头直接夹到某个输出端。

供电同样影响声音。功放 VDD 接到 VSYS,屏幕等外围使用模组引出的 3.3V 电源。播放时的负载变化若通过较大的公共回路阻抗耦合到麦克风参考点,就可能表现为底噪或啸叫。布局时应缩短功放供电与去耦回路,让麦克风输入远离喇叭走线,并保留连续、低阻抗的地参考。

板上没有给串口下载器配置一条整机供电路径,也没有画出板载充电管理。原理图标注的是采用 CR123A 外形的 3.7V 可充电电芯,不能仅凭电池外形推断电压或充电方式。烧录时仍需让板子自身供电,串口连接重点是共地以及 TX、RX 交叉。

十毫秒采样怎样拼成一包语音

音频回调按 16kHz、单声道、16bit PCM 工作。每个采样占两个字节,因此 10ms 对应 160 个采样,也就是 320 字节。工程里的 XZ_MIC_FRAME_LEN 定义为 320 * 6,对应 60ms 的 1920 字节原始语音。

xiaozhi_audio.c 在回调后段将数据写入环形缓冲区,累计到一帧后通知编码线程。

rt_ringbuffer_put(thiz->rb_opus_encode_input, p->data, p->data_len);
thiz->mic_rx_count += 320;

if (thiz->mic_rx_count >= XZ_MIC_FRAME_LEN)
{
    thiz->mic_rx_count = 0;
    rt_event_send(thiz->event, XZ_EVENT_MIC_RX);
}

六段十毫秒采样组成一个六十毫秒编码帧

图中表示采样数据进入编码队列的节奏,启用语音检测后还会经过状态判断与前段语音缓存。

环形缓冲区用于衔接连续采集与编码调度,事件用于唤醒消费者,二者承担不同职责。编码线程取走一帧后,还会检查队列是否仍有完整帧,并再次发送事件,继续处理积压数据。事件位本身并不保存每一包语音。

这段实现也带着明确假设。写入长度取自 p->data_len,计数却固定增加 320,而且这里没有检查环形缓冲写入的返回值。只要驱动块长发生变化,或者编码被网络发送拖慢,计数就可能和实际有效数据脱节。扩展时应记录写入不足次数、队列高水位和单帧处理耗时,再决定缓存容量与丢帧策略。

压缩、重采样和功放门控接力完成播放

编码线程创建 16kHz 单声道 Opus 编码器,把帧长设置为 60ms,目标码率设为 16kbit/s。

thiz->encoder = opus_encoder_create(16000, 1, OPUS_APPLICATION_VOIP, &err);
RT_ASSERT(thiz->encoder);
opus_encoder_ctl(thiz->encoder,
                 OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_60_MS));
opus_encoder_ctl(thiz->encoder, OPUS_SET_VBR(1));
opus_encoder_ctl(thiz->encoder, OPUS_SET_VBR_CONSTRAINT(1));

opus_encoder_ctl(thiz->encoder, OPUS_SET_BITRATE(16000));
opus_encoder_ctl(thiz->encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
opus_encoder_ctl(thiz->encoder, OPUS_SET_COMPLEXITY(0));
opus_encoder_ctl(thiz->encoder, OPUS_SET_LSB_DEPTH(16));

未经压缩的上行 PCM 速率为 256kbit/s。按目标码率估算,一帧压缩载荷约为 120 字节,但可变码率会让实际长度波动,协议头和网络开销还要另计。较长帧能减少封包频率,也引入更长的成帧等待,不能把低码率等同于低延迟。

下行解码器按 24kHz 单声道创建。opus_decode 返回的是每声道采样数,写入 16bit PCM 时需要乘二换成字节数。当前构建启用了 AEC 路径,音频设备的读写采样率均设为 16kHz,所以代码通过 sifli_resample_open(1, 24000, 16000) 把下行语音转换到播放设备使用的速率。

下行语音从解码到桥接功放的播放路径

24kHz 解码输出先转换到 AEC 音频设备的 16kHz 路径,再经 DAC 和功放驱动喇叭。

AEC 用于减轻喇叭声音被麦克风再次采集形成的回声,VAD 则判断输入是否包含语音,两者不能互相替代。即使软件同时启用它们,麦克风与喇叭的声学隔离、增益和供电噪声仍会影响效果。

THT 板级配置把功放控制脚设为 PA26,工作电平为低,和 LM4871 的高电平关断端相对应。bsp_init.c 的启动路径初始化控制脚后,延时 550μs,再写入工作电平。

GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pin  = PA_EN_PIN;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(hwp_gpio1, &GPIO_InitStruct);
HAL_Delay_us(550);
HAL_GPIO_WritePin(hwp_gpio1, PA_EN_PIN, PA_LEVEL);

停止路径写入相反电平后再释放引脚。这样,音频软件的启停才落实为功放的实际工作状态。更换功放时,既要改控制极性,也要重新核对启动时序;550μs 是本工程采用的延时,并不代表所有器件都适用。

屏幕亮起只说明显示链路走通了一部分

显示接口使用 SPI 形式的信号,板级代码由 LCD 控制器配置对应复用。背光和复位分别由 PA42、PA00 控制,数据线通了也不能替代屏幕复位、初始化命令和背光检查。

功能 硬件连接 软件对应关系
屏幕片选与时钟 PA03、PA04 LCDC1 的 SPI CS、CLK
屏幕数据与命令选择 PA05、PA06 DIO0、DIO1 对应板上的数据与 DC 接线
屏幕复位与背光 PA00、PA42 LCD_RESET_PIN、LCD_BL_PIN
功放关断控制 PA26 PA_EN_PIN,低电平工作
串口接收与发送 PA18、PA19 USART1 RXD、TXD

屏幕接口从模组引脚到八针排母的信号对应

屏幕的电源、复位、背光与通信信号分开核对,排针外形相同不代表引脚兼容。

背景灯亮而画面不更新,应继续检查复位、SPI 时钟、CS、DC 和屏幕驱动选型。表情能切换却没有语音,应把注意力转到会话状态、上行队列、下行解码和 PA26。把这两组现象分开,可以避免反复更换固件却没有触及故障节点。

板卡版本和运行状态都要留得住

编译时应选择 sf32lb52-xty-ai-tht 板级目标,使用与工程匹配的 SDK 和配置。相同主控并不意味着 LCD、按键和功放电平都兼容。1.3 版原理图中的阻容值、当前在线工程的修订以及已烧录固件,也应分别确认,不能把不同版本拼成一张采购表。

排查录音问题,可以先看麦克风偏置与 PCM 数据是否随声音变化,再观察编码队列是否持续消费。排查播放问题,则先确认下行载荷进入队列、解码得到有效采样,再检查采样率转换、DAC 输出和功放门控。网络方向应保留 PAN 事件、会话握手及断连原因,不能只看屏幕上的蓝牙图标。

沿着这块板子的声音路径,模拟电路、实时调度和网络协议之间的关系就清楚了。偏置与供电决定采样起点,环形缓冲和 Opus 决定语音怎样离开设备,重采样与功放控制决定回复能否完整播放。把这些节点逐个对应起来,语音盒子的调试就有了可观察的依据,后续更换屏幕、调整交互或扩展功能也更容易控制影响范围。

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -