最近在做一个离线语音控制的智能家居网关,把一块离线语音识别板接到树莓派上,用来识别固定词条然后通过串口下发指令。这块语音板本身不依赖任何云服务,识别完指令直接在本地输出,方案看起来非常干净。但我第一次直接拿杜邦线把两边的TX、RX、GND一连,结果相当惨:树莓派偶尔直接重启,语音板识别率极低,串口里全是系统启动日志。后来我把问题拆开才发现,真正需要解决的不是“识别”,而是“适配”。这篇就记录一下我如何用一块通用适配板(general adapter)把离线语音板(offline speech board)和树莓派(Raspberry Pi)稳定串在一起,包括有线串口的电平转换、独立电源处理、系统串口配置,以及扩展蓝牙无线连接时的适配器驱动问题。如果你正准备做离线语音控制、智能开关、机器人语音交互,这篇文章应该能帮你省下好几天的排查时间。
1. 为什么直接接线不行:三个层面的“不匹配”
1.1 电平逻辑不是一回事
树莓派的GPIO工作电平是3.3V,而且芯片手册写得很清楚,GPIO输入引脚不是5V tolerant,也就是不能直接承受5V高电平。很多离线语音板为了驱动麦克风偏置和功放,主控部分虽然是3.3V逻辑,但为了兼容一些5V的单片机外设,会把UART引脚做成5V TTL输出,或者板子上拉了5V上拉电阻。
这种“看起来能接”的情况最坑人。你把语音板的TX接到树莓派的RX(GPIO15),语音板空闲时是高电平5V,树莓派SoC对应引脚就要一直承受超出供电电压的电平。虽然不会像短路那样立刻冒烟,但长期运行会加速芯片老化,严重的时候直接烧掉树莓派的UART控制器,甚至烧坏整颗SoC。我见过不止一个朋友把树莓派接坏了,症状是开机正常,但/dev/ttyAMA0完全没反应,换板子才发现是GPIO挂了。
反向链路同样存在隐患。树莓派的TX输出高电平只有3.3V,如果语音板的RX引脚内部没有上拉,并且被配置成需要5V高电平才认为是有效信号,那么树莓派发的指令就可能被语音板当成无效电平而忽略。这就是为什么适配器首要任务就是做双向电平转换,把5V和3.3V两个世界在逻辑上对齐。
1.2 电源和音频比想象中敏感
语音识别板的工作电流不是恒定的。识别唤醒、点亮LED、播报提示音、驱动D类功放这些瞬间,电流脉冲可能到几百毫安甚至更高。如果直接和树莓派共用一个5V电源轨,尤其是很多项目里树莓派本身还带着风扇、传感器、WiFi模块,这时候语音板一播报,整个5V电压就会被拉低。树莓派对电压跌落特别敏感,跌到4.6V以下就可能触发欠压警告,再低一点就直接重启。
我遇到过的情况是:树莓派单独运行没有任何问题,语音板单独用电源适配器也没问题,两个一接到同一块面包板上,语音板只要识别到词条、喇叭一响,树莓派立刻重启。起初还以为是程序写了什么冲突,后来用示波器看5V引脚,才发现语音播报瞬间电压跌到了4.3V,树莓派自然扛不住。
音频部分的问题更加隐蔽。语音板的功放地和树莓派的数字地如果走同一条长导线,扬声器的大电流会在导线上产生压降,这个压降会直接叠加到信号地上,形成共模噪声。结果就是语音识别率下降、麦克风采集到“嗡嗡”声、串口偶尔出现乱码。适配板需要把电源和地平面做合理的分割与单点连接,而不是简单并到一起。
1.3 串口的“隐形占用”
树莓派系统默认把UART分配给了Linux控制台。也就是说,开机时内核日志和登录提示会一直往串口上打印。你如果不知道这个,插上语音板,用串口工具一看,满屏都是系统启动信息,偶尔才夹着语音板发来的识别结果,完全没法用。
还有更麻烦的:树莓派的板载蓝牙和UART共用硬件资源。默认情况下,树莓派4B、CM4、5B这些板子的GPIO14/15串口实际上是留给蓝牙的mini UART,而真正的PL011硬件串口被蓝牙占用。如果你既想用蓝牙又想用GPIO串口,需要对设备树overlay做调整,否则只能用那个时钟不稳的mini UART,波特率一高就丢数据。
这些“隐形占用”问题,在厂商文档里不会特别强调,但对实际接线的人来说就是第一个拦路虎。适配器要解决的第三件事,就是把这些串口资源关系梳理清楚,确保语音板的指令能稳定到达系统应用层。
1.4 适配器到底“适”什么:一个通用定义
所以,标题里说的Adapter不只是一根转接线。它的本质是一个小型的硬件/系统适配层,至少包含四部分:
- 电平转换:让5V TTL和3.3V逻辑可以互相通信,且不会损坏任何一方。
- 电源管理:为语音板提供独立、干净的供电,减少对树莓派5V电源轨的冲击。
- 串口路由:把树莓派的UART引到正确的位置,解决控制台占用和蓝牙冲突。
- 可选无线桥接:通过蓝牙串口模块或USB蓝牙适配器,实现树莓派与语音板之间的物理隔离或者灵活布局。
我在项目里把这套东西做成了一块通用转接板,接上语音板和树莓派之后,两边都觉得自己在跟一个“正常设备”通信。下面我会把选型思路和具体接线全部展开。
2. 适配器的设计方案:有线优先,蓝牙作为扩展
2.1 先确认你手上的语音板到底输出什么信号
不同离线语音板的对外接口差异很大。以市面上常见的方案为例:
- CI1103方案板:常见5V供电,UART TTL输出,有些模块默认波特率9600,支持通过串口下发词条和接收识别结果。
- ASRPRO方案板:通常3.3V逻辑,支持UART、I2C、SPI,部分板子直接带功放输出。
- LU-ASR01这类低成本模块:5V供电,串口电平看具体版本,有的兼容3.3V,有的必须5V才能稳定工作。
所以在选适配器之前,先去看你手上板子的原理图或说明书,确认三件事:供电电压、UART电平、波特率。没有文档的话,用万用表量一下板子串口TX引脚的空闲电平:如果对地电压接近0V,可能是开漏输出需要上拉;如果接近供电电压(比如5V或3.3V),就是推挽输出。这个信息直接决定你要不要做额外上拉。
2.2 电平转换芯片选型:BSS138与TXS0108E的实际表现
我在通用适配板上试过几种电平转换方案,整理成表格供参考:
| 方案 | 原理 | 适用场景 | 需要注意的问题 |
|---|---|---|---|
| 分压电阻 | 用两个电阻把5V分到3.3V | 单向信号、调试临时用 | 只能降电平,不能升电平;阻抗匹配差,高速信号会变形 |
| BSS138 MOSFET | 双N沟道MOSFET背靠背,自动双向 | UART、I2C等低速信号,9600~115200波特率很稳定 | 两侧必须分别接上拉电阻,否则空闲电平会飘 |
| TXS0108E | TI电平转换芯片,内部自动方向检测 | 多通道、信号速率稍高的场景 | 需要OE拉高,内部上拉电阻会影响外部电路,接线长度要短 |
对于离线语音板这种低速UART通信,BSS138方案是性价比最高的,一个四路模块十几块钱,电压范围1.8V到10V都能对付,9600波特率下非常稳定,115200也完全没问题。我最初以为直接买模块插上去就行,但踩了个坑:很多便宜的BSS138电平转换模块,只在高压侧做了上拉,低压侧没有上拉电阻。语音板的TX是5V推挽输出时问题不大,但如果语音板的TX是开漏输出,低压侧没有上拉就会导致空闲电平稳不住,串口收到一堆乱码。
解决办法很简单:在3.3V侧(也就是树莓派RX一侧)加上4.7kΩ上拉到3.3V。我自己画的适配板上直接贴了0402电阻,从源头避免模块批次差异带来的问题。
2.3 电源方案:DC-DC与LDO的选择、音频接地处理
语音板供电我从两个方向考虑:
如果只是树莓派5V直供,我会在适配板上加磁珠和电容滤波。磁珠选600Ω/100MHz,串联在树莓派5V和语音板VCC之间,后面接一个220μF电解电容和0.1μF陶瓷电容。这样语音播报瞬间的电流由电容和磁珠后面的支路分担一部分,不会直接把树莓派5V拉垮。但要注意,这种方式只能减轻冲击,不能彻底隔离。如果语音板峰值电流超过1A,还是建议用独立5V电源。
如果项目里本身有12V电源(比如智能家居继电器板常用12V),我会先用MP1584这类DC-DC降压到5V给语音板单独供电,树莓派用另一路5V,两路电源之间只共地。这样语音板的电流波动完全不会传导到树莓派这边。
音频部分的接地很关键。语音板的扬声器输出或功放供电,如果直接和信号地走同一条线,地线阻抗产生的压降会变成共模噪声,被麦克风放大后严重影响识别率。我的做法是:语音板的地分成两块——功率地(功放、喇叭)和信号地(麦克风、UART),在适配板上用0欧电阻单点连接,两个地平面之间不要大范围覆铜连在一起。如果板子上没有分开,也可以从语音板的电源地引脚单独拉一根粗线到树莓派的GND,避免和信号地线共用。
2.4 蓝牙适配器与树莓派的驱动匹配
有些场景里,语音板装在墙上、树莓派藏在弱电箱里,有线连接不现实。这时候蓝牙串口模块是个好方案。我在适配板上留了一个6针接口,可以插HC-05或HM-10这类低功耗蓝牙串口模块,语音板的UART走蓝牙透传,树莓派侧通过板载蓝牙或USB蓝牙适配器接收。
这里就牵扯到“通用蓝牙适配器驱动”的问题。树莓派板载蓝牙芯片是BCM43455,对Linux支持很好,但它的射频性能一般,而且只要启用板载蓝牙,系统默认会占用UART资源。如果你想用USB蓝牙适配器,最常见的CSR 4.0蓝牙棒在树莓派OS上不一定插上就能用,有些需要单独装bluez-firmware固件包,否则bluetoothctl能识别到controller,但扫描时直接报错。
驱动的匹配思路是:装好bluez和bluez-firmware,然后看dmesg | grep btusb和bluetoothctl list,确认USB蓝牙适配器被系统识别,并且确保系统当前使用的是你指定的那个adapter,而不是板载蓝牙。多个controller并存时,bluetoothctl会默认使用第一个,这会让USB适配器看起来“像坏了一样”。这些都是非常典型的蓝牙适配器驱动问题,我后面在实测章节会给出完整排查过程。
3. 接线、系统配置与CM4 GPIO引脚对照
3.1 适配板与树莓派40-pin的接线表
先给一个最常用的有线UART接线表,适用于树莓派3B/4B/5B以及使用40-pin接口的CM4底板。
| 适配板/语音板侧 | 树莓派40-pin引脚 | BCM GPIO | 说明 |
|---|---|---|---|
| 语音板VCC | Pin 2 或 Pin 4(5V) | - | 建议经磁珠或DC-DC后供电,见2.3节 |
| 语音板GND | Pin 6 | GND | 必须共地,不要省略 |
| 语音板TX | 适配板B侧低压RX | 树莓派GPIO15(UART RXD) | 串口交叉:语音板发,树莓派收 |
| 语音板RX | 适配板B侧低压TX | 树莓派GPIO14(UART TXD) | 串口交叉:树莓派发,语音板收 |
注意两个坑:
第一,串口一定要交叉连接。树莓派的TX(GPIO14)接语音板的RX,树莓派的RX(GPIO15)接语音板的TX。很多人第一次接线时习惯性地把同名端子接在一起,结果完全没反应。
第二,语音板供电如果是从树莓派5V引脚取的,适配板上的磁珠和电容一定要接。如果不加,语音板播报瞬间的电流冲击会通过5V线路传回树莓派。我的第一版就是图省事从Pin 4直接飞线,结果树莓派在语音播报时频繁重启。
3.2 使用Compute Module 4时需要额外对照底板引脚图
CM4本体的接口是SO-DIMM金手指,没有直接裸露的GPIO,必须通过底板引出。这个点经常被新手忽略——你拿到的是一块很小的核心板,不能像普通树莓派一样直接插杜邦线。
以树莓派官方Compute Module 4 IO Board为例,它把GPIO通过J1排针引出,物理排列和普通树莓派40-pin一致,所以上面那份接线表可以直接用。但市面上很多第三方CM4扩展底板并不保证引脚顺序和官方一致,有些底板甚至把GPIO14/15留作调试串口、接到了别的插座上,或者被复用为其他功能。所以使用CM4时,第一时间打开底板原理图,找到UART和5V/GND引脚的丝印,不要想当然认为所有底板都是标准40-pin。
官方IO Board上比较关键的部分引脚如下:
| 引脚编号 | 功能 | BCM GPIO |
|---|---|---|
| Pin 2 | 5V电源 | - |
| Pin 6 | GND | - |
| Pin 8 | 串口TX | GPIO14 |
| Pin 10 | 串口RX | GPIO15 |
在CM4 IO Board上,GPIO14/15默认对应PL011串口,会受设备树overlay影响。如果你在config.txt里设置了dtoverlay=disable-bt,那这两个引脚就会变成可用的串口。在部分工业底板上,UART可能被引到DB9或者RJ45调试口,此时不要强行从GPIO14/15接语音板,直接用底板自带的UART接口更省事。
3.3 修改config.txt开启系统串口
树莓派OS从Bullseye开始,配置目录是/boot/firmware/config.txt,旧版本是/boot/config.txt。修改前先备份:
sudo cp /boot/firmware/config.txt /boot/firmware/config.txt.bak sudo nano /boot/firmware/config.txt添加或修改以下几行:
enable_uart=1 # 如果不用板载蓝牙,就把PL011串口释放给GPIO14/15 dtoverlay=disable-bt # 如果必须保留板载蓝牙,则改用这行,让蓝牙占用mini UART # dtoverlay=miniuart-bt # 使用mini UART时建议固定core_freq,否则波特率会随GPU频率漂移 # core_freq=250同时检查/boot/firmware/cmdline.txt,把里面的console=serial0,115200或console=ttyAMA0,115200删掉。如果不删,系统开机日志和登录shell会一直占用串口,语音板发来的数据会混在一堆系统信息里。
改完重启,执行:
ls -l /dev/serial* dmesg | grep tty正常情况下能看到/dev/serial0 -> ttyAMA0(使用disable-bt时)或/dev/serial0 -> ttyS0(使用mini UART时)。这里建议直接把Python程序里的设备路径写成/dev/serial0,因为系统会自动映射到当前启用的那个串口,即使日后切换overlay也不用手动改代码。
3.4 串口权限和通路验证
树莓派默认用户pi(或新系统里的自定义用户)不在dialout组里,直接打开串口会报权限错误。执行:
sudo usermod -aG dialout $USER sudo reboot验证最简单的方法是把GPIO14和GPIO15短接,形成回环,然后执行:
echo "hello serial" > /dev/serial0另开一个终端:
cat /dev/serial0如果能看到hello serial,说明系统串口链路是通的。这个时候再接语音板,基本就只剩协议解析和波特率的问题了。
4. 协议解析和Python控制示例
4.1 语音板串口报文的常见格式
连上串口后,先用minicom或者Python监视一段时间,看看语音板识别词条后到底发了什么。
sudo apt install minicom minicom -b 9600 -D /dev/serial0不同语音板的协议千差万别,但主要就两类:
ASCII字符串指令:比如识别到“开灯”就发送ON\r\n,识别到“关灯”就发送OFF\r\n。这种格式最直观,直接用readline()就能处理。
二进制帧:比如AA 55 06 01 01 00 00 5D,其中前两个字节是帧头,第三字节是数据长度,后面是命令码和校验和。这种格式解析稍微麻烦点,但信息更紧凑,还能携带命令参数。
我用的语音板是二进制帧格式,波特率9600,每次识别到词条后发6个字节。先用minicom确认了帧结构,然后在Python里按固定长度读取并拆解。如果你的语音板文档丢了,最笨但有效的方法是:对着minicom原始数据,念一个词条记一组数据,多试几组,规律自然就出来了。
4.2 用Python读取并解析指令
下面是一个可以直接跑的示例。假设语音板识别“开灯”后发送AA 55 01 01 01 56,识别“关灯”后发送AA 55 01 02 01 55,我们在树莓派上控制GPIO17接的LED。
import serial import time from gpiozero import LED # 使用系统映射的串口设备 ser = serial.Serial("/dev/serial0", 9600, timeout=1) ser.reset_input_buffer() led = LED(17) COMMANDS = { bytes.fromhex("AA5501010156"): ("open", led.on), bytes.fromhex("AA5501020155"): ("close", led.off), } def handle_frame(frame): if frame in COMMANDS: name, action = COMMANDS[frame] print(f"[recv] {name}") action() else: print(f"[unknown] {frame.hex(' ')}") while True: frame = ser.read(6) # 固定帧长 if frame and len(frame) == 6: handle_frame(frame)这里有一点需要特别说明:语音板的识别结果不是流式数据,而是“触发式”的一帧。所以ser.read(6)在没有任何指令时会一直阻塞到timeout,不会消耗CPU。但如果语音板一帧的字节间隔大于1秒,可能被timeout截断,这时候要适当调大timeout,或者改为循环读取:
def read_frame(expect_len=6, timeout=0.1): buf = b"" end = time.time() + timeout while time.time() < end: data = ser.read(max(1, expect_len - len(buf))) if data: buf += data end = time.time() + timeout if len(buf) >= expect_len: break return buf这个read_frame思路和判断“帧是否结束”的常用办法一致:如果超过一定时间没有新字节,就认为上一帧已经结束了。
4.3 联动GPIO、MQTT和外部服务
语音板识别结果出来后,具体做什么就看项目需求了。最简单的就是控制GPIO,上面代码已经演示了。更常见的场景是把指令转成MQTT消息,发给其他设备联动:
sudo pip3 install paho-mqttimport paho.mqtt.client as mqtt client = mqtt.Client() client.connect("192.168.1.100", 1883, 60) def handle_frame(frame): if frame == bytes.fromhex("AA5501010156"): client.publish("home/light/switch", "on") elif frame == bytes.fromhex("AA5501020155"): client.publish("home/light/switch", "off")这样离线语音板的交互范围就远远不止树莓派本机GPIO了。我在项目里把语音指令映射成MQTT主题后,家里的灯、风扇、窗帘都能通过离线词条控制,所有逻辑只依赖本地局域网,语音识别本身完全离线,不经过云服务。
4.4 识别慢、误触发、丢帧的排查方法
如果语音板识别正常,但串口数据不稳定,优先怀疑四个地方:
波特率不匹配。语音板说明书标9600,但实际可能因为外部晶振不同而有偏差。在minicom里把波特率从9600、19200、115200逐个试,看哪个能出可读数据。
串口被系统占用。如果改了config.txt仍能看到系统日志,说明cmdline.txt里的console=没有删干净。重启后执行who不会有串口登录提示,不代表没有占用,最直接的方法是sudo lsof /dev/serial0。
电平转换上拉不够。开漏输出信号高电平会变“圆”,出现边沿太慢导致的误码。这时候在低压侧加4.7kΩ上拉,或者换TXS0108E。
电源噪声干扰。语音播报瞬间串口数据错乱,几乎可以断定是功率地和信号地没处理好。把喇叭地单独走线,和电源地在适配板上单点连接,问题通常能解决。
另外,语音板识别到指令后一般会先播报“好的”之类的提示音,这时候如果你在程序里立即读串口,可能下一条指令的帧还没发出来,所以联动逻辑里不需要额外延迟,但要注意不要让GPIO动作(比如继电器吸合)产生的大电流干扰到语音板供电,否则会形成“识别→动作→误触发→再识别”的循环。
5. 实测过程与那些文档不会写的坑
5.1 直连导致树莓派重启的完整排查链路
我第一次做这个项目时,语音板直连树莓派,现象很奇怪:树莓派开机后一切正常,但语音板一识别到词条、喇叭一响,树莓派就重启,而且不是每次都重启,时好时坏。
排查顺序分享一下:
第一步,先排除软件问题。把串口程序停掉,只接线不跑代码,语音播报时树莓派照样重启,说明问题在硬件链路,不是Python程序。
第二步,怀疑供电。把语音板和树莓派的供电完全分开,语音板用USB单独供电,树莓派还是用原来的电源。再接上串口线和共地线,语音播报时树莓派不再重启了。到这里基本确定是共用电轨导致电压跌落。
第三步,确认串口。恢复共电后,我在config.txt里加了dtoverlay=disable-bt并删掉cmdline.txt里的console=,然后用minicom监听。这时候能收到语音板的识别结果了,但每隔几毫秒会有一些奇怪的0x00字节,后来发现是电平转换模块低压侧上拉不够,加上4.7kΩ上拉后干净了。
这个案例的典型性在于:问题表现是“重启”,真正原因却是“电源”和“串口占用”两个问题叠加。如果你也遇到类似情况,建议用我的排查顺序:先断软、再分电、后查串口。不要一上来就怀疑语音板坏了,离线语音板这种东西只要供电正常,一般不会自己把宿主搞重启。
5.2 蓝牙适配器驱动的掉坑实录
有线方案稳定之后,我又想把语音板放到吊顶上,树莓派留在弱电箱,中间用蓝牙串口透传。语音板侧接HC-05从机模块,树莓派侧用了一个CSR 4.0 USB蓝牙适配器。
第一次测试,插上USB蓝牙适配器后执行bluetoothctl,能看到controller,但scan on几乎立刻报错:
Failed to start discovery: org.bluez.Error.Failed排查过程:先看dmesg | grep -i btusb,发现USB蓝牙被识别为Cambridge Silicon Radio,但firmware没有加载成功。安装bluez-firmware后重新插入,hciconfig -a能正常显示型号了。
但扫描还是有问题。后来我注意到bluetoothctl list里有两个controller:一个是板载的hci0(BCM43455),一个是USB的hci1(CSR)。系统默认使用了hci0,而板载蓝牙的天线位置在机箱里被金属挡住了,射频信号弱,所以配对一直失败。解决办法是手动指定:
bluetoothctl list select <USB适配器的MAC地址> power on scan on选对adapter后,很快发现了HC-05,默认PIN码是1234,配对成功:
pair 00:14:03:01:23:45 trust 00:14:03:01:23:45然后绑定串口:
sudo rfcomm bind 0 00:14:03:01:23:45 1这样/dev/rfcomm0就出现了,语音板的串口数据会通过蓝牙透传到这个虚拟串口,Python程序只要把设备路径从/dev/serial0改成/dev/rfcomm0即可。
这里提醒一句,新版BlueZ对rfcomm的支持没有以前那么顺手了,如果rfcomm命令提示找不到,需要安装bluez-tools,或者直接用Python的socket走RFCOMM协议,效果一样。另外HC-05在空闲一段时间后会进入休眠,导致第一次数据传输有延迟,最好在硬件上把HC-05的STATE引脚接一个LED指示,或者在程序里定期发送心跳指令唤醒。
5.3 长期运行与稳定性建议
语音控制这种东西,做demo容易,稳定7x24小时跑起来难。我的项目连续跑了差不多两个月,中间遇到几个长期运行才会暴露的问题。
程序守护。直接把python3脚本放在前台跑,SSH断开后程序就没了。写成systemd服务是基本操作:
[Unit] Description=Offline Speech Board Service After=network.target [Service] ExecStart=/usr/bin/python3 /opt/speech_control.py WorkingDirectory=/opt Restart=on-failure RestartSec=3 [Install] WantedBy=multi-user.target启用:
sudo systemctl enable speech_control sudo systemctl start speech_control有了Restart=on-failure,程序哪怕因为串口异常退出,3秒后也会自动拉起来。
硬件看门狗。树莓派本身没有硬件看门狗对外开放,但BCM283x系列SoC内置了一个,可以在config.txt里开启:
dtparam=watchdog=on然后在Python脚本里通过/dev/watchdog每隔一段时间写入一次,防止程序进入死循环导致系统假死:
try: with open("/dev/watchdog", "w") as wd: while True: wd.write("x") wd.flush() time.sleep(10) except Exception: print("watchdog open failed")使用mini UART时注意,core_freq如果浮动,波特率会漂移。长期运行的项目建议在config.txt里固定core_freq=250,否则可能几个小时不报错,跑一天后串口突然乱码,重启又恢复,这种情况多半就是GPU频率变化导致mini UART时钟不准。
最后,SD卡掉电损坏是所有树莓派项目的通病。语音控制网关经常被直接断电,容易把日志文件系统弄坏。我在生产环境里把根文件系统切到overlay只读模式,数据写入全部放到内存tmpfs,这样断电后SD卡基本不会损坏。程序本身放在/opt下,只读不会影响运行,需要修改时再临时关掉overlay。
回头看我这个项目,刚开始以为难点在语音识别,实际真正花时间的是把电平和电源理顺。如果你也遇到类似情况,别急着怀疑语音板坏掉,先用万用表和minicom按这个顺序查一遍:先分电源、再清串口占用、最后检查电平转换上拉。把这些适配问题解决后,树莓派和离线语音板其实是非常省心的一对组合——不依赖网络、延迟低、代码也简单。希望这次的经验对你有点帮助。