资讯动态

低功耗BLE指令式本地语音播报方案与GATT实现

发布时间:2026/9/19 11:32:31 来源:尧图企业网站定制
1. 为什么我要把蓝牙音频流从方案里踢出去去年接手一个便携语音提示设备的时候我第一反应也是走蓝牙音频那套手机连上当个蓝牙音箱用想播什么播什么开发量最小。真上手跑了两周功耗表一挂我就知道这条路走不通。问题出在链路的常驻开销上。蓝牙音频流A2DP 那一套本质上是一条持续的双向管道一旦建立射频、基带、解码、DAC 全部要保持在活动状态。哪怕你只是每五分钟播一句电量低请充电链路也得一直挂着或者反复建链断链。挂着的话实测待机电流直接从几百微安跳到十几毫安反复建链的话每次重连的握手时间在 1 到 3 秒之间浮动用户按了按钮要愣一下才出声体验很割裂。我当时的硬件选型是HC32L196这一类低功耗 MCU 加一颗独立 BLE 芯片的组合整机目标是把平均电流压在 50μA 以内用一颗 500mAh 的电池撑三个月以上。这个目标下音频流方案连门槛都够不着。后来换思路语音播报的本质需求是传递一条确定的信息不是播放一段高保真音频。既然信息是确定的、数量有限的那就不该走音频流而应该走指令。手机或上位机通过 BLE 的 GATT 写特征值把一条播放第 7 号语音的指令发下来MCU 收到后从本地 Flash 里取对应的音频数据推给 DAC 或 PWM 播出去。整条链路只在发指令的那几百毫秒内活跃播报过程中射频可以完全关掉。这个思路一换功耗结构就完全变了BLE 连接以长连接 低占空比维持或者干脆用广播唤醒播报时射频关闭只有 MCU 和功放在工作。实测平均电流能压到 30μA 出头播报一次3 秒语音的能耗大约是 12mAh 的千分之几。这篇文章就是把这套方案的完整实现路径摊开讲为什么 BLE 指令比音频流合适、本地语音数据怎么组织、连接参数怎么配、低功耗状态机怎么设计、踩过哪些坑。适合正在做低功耗语音类产品、被蓝牙音频功耗折磨过的硬件和嵌入式同学也适合做 App 端、需要理解 BLE 交互边界的人。代码基于 CMCU 侧和 Kotlin/Swift 混合描述App 侧平台无关HC32L196、HC32F460、ESP32 系列、nRF 系列的思路都能套。提示本文讲的本地语音播报指的是音频数据存在设备本地、播报时不依赖网络和音频流通道的方案。如果你的需求是实时播放任意内容比如在线音乐那这套方案不适用别硬套。2. 方案选型的账要算清楚指令式播报 vs 音频流2.1 两种链路的功耗结构差异要把这件事讲透得先把两种方案的电流消耗拆开看。很多人只盯着BLE 芯片的广播电流这一个数字其实真正决定续航的是时间维度的积分也就是平均电流。蓝牙音频流A2DP/HFP的功耗结构环节状态典型电流射频收发常驻活动8~15mA音频解码常驻活动3~8mADAC/功放常驻活动5~20mA时钟与 PLL常驻活动1~3mA这套东西加起来整机常驻就是 20mA 往上。而且 A2DP 链路本身有 keep-alive 机制你没法让它闲着的时候彻底睡死睡着就断连断了重连又要几秒。所以音频流方案的续航基本是按小时算的不是按天算的。BLE 指令式播报的功耗结构环节状态典型电流BLE 连接维持连接间隔 500ms周期性唤醒平均 20~60μAMCU 主循环深度睡眠为主平均 5~15μA播报时3 秒临时活动峰值 60mA播报后回到睡眠恢复低功耗关键在最后两行。播报是一次性事件3 秒的高电流摊到一天几十次播报上平均贡献极小。我用一个实际场景算一下假设设备每天播报 50 次每次 3 秒峰值 60mA那么播报贡献的平均电流是50 次 × 3 秒 × 60mA / 86400 秒 ≈ 0.104mA ≈ 104μA等一下这个数字看起来不小。问题在于 60mA 是峰值实际播报时的平均电流含 MCU 运行、Flash 读取、功放输出实测在 25~35mA 之间按 30mA 算50 × 3 × 30mA / 86400 ≈ 52μA再加上连接维持的 40μA整机平均在 90μA 左右。如果降频、优化功放能压到 50μA 上下。这个数字和音频流的 20mA 比是 400 倍的差距。注意这里的算法是能量平均不是简单相加。播报时的峰值电流和睡眠时的底电流要在时间轴上积分不要被峰值数字吓到也不要低估底电流的长期累积。我自己第一次算的时候就是被峰值劝退了后来才想明白要看积分。2.2 为什么指令这两个字是核心指令式方案能省电本质原因是它把信息传输和音频还原这两件事解耦了。音频流方案里每一帧音频数据都要实时传到设备设备做解码和播放传和播是强绑定的。指令式方案里传的只是一条短指令比如 4 个字节包头 语音编号 校验音频数据早就存在本地了收到指令后本地取数、本地播放传输过程极短。这里有个容易忽略的点指令式方案对连接质量的要求低得多。音频流对丢包、抖动很敏感断了就有杂音指令只要一发一收确认即可丢了大不了重发一次用户感知不到。这意味着你可以把 BLE 的连接间隔Connection Interval设得很大从功耗角度这是决定性的。不同连接间隔对平均电流的影响我实测过一组数据HC32L196 某 BLE 芯片从机模式连接间隔从机平均电流连接态一次指令往返时延30ms约 380μA 50ms100ms约 140μA约 150ms500ms约 45μA约 700ms1000ms约 30μA约 1.4s音频流方案基本只能选最上面那一档指令式方案可以选 500ms 甚至 1000ms。这一档的差距就是 10 倍功耗。2.3 什么场景该用哪套方案不是所有场景都适合指令式我把判断标准整理成一个速查表你对照自己的项目看判断维度适合指令式播报适合音频流播放内容固定、有限的语音条目任意、实时内容播放频率低频每天几十次以内高频、连续音质要求提示音级别8~16kHz 采样足够音乐级44.1kHz 起续航目标月级及以上天级交互实时性秒级可接受毫秒级敏感成本敏感度高可用小容量 Flash低我见过一个反例有同学做儿童故事机内容是从云端拉取的那就不适合本地指令式因为内容不固定。反过来做门锁语音提示、血压计播报、共享设备状态提示这些场景内容固定、频率低指令式是最优解。2.4 本地存储的容量账既然音频存本地就得算 Flash 容量。这不是拍脑袋要按采样率、位深、时长、压缩方式算。未压缩的 PCM公式是容量(Bytes) 采样率(Hz) × 位深(bit) / 8 × 时长(秒) × 声道数按 16kHz、16bit、单声道、每条 3 秒算16000 × 16 / 8 × 3 × 1 96000 Bytes ≈ 94KB每条语音 94KB如果做 50 条就是 4.7MB。这个数字对小容量 MCU 的片内 Flash 来说太大了所以必须做两件事第一降参数。语音提示不需要 16kHz/16bit。实测 8kHz、8bit 的语音配合简单的 ADPCM 压缩清晰度对电量低请插卡这类提示完全够用。这样每条 3 秒的语音是8000 × 8 / 8 × 3 24000 Bytes ≈ 23KB第二用外挂 SPI Flash。现在 4MB 的 SPI NOR Flash 单价很低放 100 条语音绰绰有余而且按页读取的速度对语音播放完全够。实操心得语音编号和 Flash 地址的映射表一定要单独存一份存在 Flash 的固定扇区或者 MCU 的 EEPROM 里。我最早把映射表硬编码在代码里后来要改条目顺序就得重新烧固件。改成映射表后产线烧录只需要更新映射表扇区不用动主固件效率提升很明显。3. BLE 连接与指令协议怎么设计3.1 GATT 服务的拆法BLE 的交互全靠 GATTGeneric Attribute Profile。做指令式播报服务设计不需要复杂三个特征值就能跑起来一个指令写特征App 写设备收、一个状态通知特征设备主动上报App 收、一个配置特征音量、语言、播放模式。指令写特征的属性配Write Without Response还是Write这是个要权衡的点。Write Without Response不等待 ACK速度快、功耗低但 App 拿不到设备已收到的确认Write有 ACK可靠但多一次往返。我的做法是日常指令用 Write Without Response 提速播报完成用状态通知回调。这样既快又能确认最终结果。状态通知特征必须开Notify而且要配 CCCDClient Characteristic Configuration DescriptorApp 端订阅后才能收到设备的上报。CCCD 的开启和关闭本身也是写操作别小看它有些 App 端框架在断连重连后 CCCD 会被重置导致通知收不到这个问题后面排查章节会细讲。指令的数据格式我习惯用固定长度简单可靠typedef struct { uint8_t header; // 固定 0xA5用于校验帧头 uint8_t cmd; // 指令类型0x01 播报0x02 停止0x03 设音量 uint8_t param; // 参数语音编号或音量值 uint8_t checksum; // 前三个字节异或校验 } voice_cmd_t;4 个字节一次 attribute write 就搞定。为什么用异或校验而不是 CRC因为 BLE 链路层本身有 CRC 保证应用层再加 CRC 是过度设计异或足够防止一些软件层的错位。这一点我踩过坑早期用 CRC16 校验多算了十几个时钟周期不说App 端还要引一份 CRC 库两边实现稍有出入就对不上排查了半天。3.2 连接参数协商的实际操作BLE 连接参数有三个核心量连接间隔Connection Interval、从机延迟Slave Latency、监督超时Supervision Timeout。这三个量决定了功耗和响应速度的平衡。连接间隔单位为 1.25ms范围 7.5ms 到 4s。我推荐的值是 500ms也就是 400 个单位。从机延迟表示从机可以跳过多少个连接事件不响应设为 4 表示从机可以睡 4 个间隔再醒一次相当于把有效唤醒周期拉长到 2.5 秒。监督超时是判断断连的时间必须满足下面这个约束Supervision Timeout (1 Slave Latency) × Connection Interval × 2按 500ms 间隔、4 从机延迟算(1 4) × 500ms × 2 5000ms所以监督超时至少设 5 秒我一般设 6 秒留余量。这个约束不是随便定的它是为了保证即使连续丢几个连接事件链路也不会被误判为断开。不同平台的连接参数更新时机不一样这是大坑。iOS 侧对参数有很强的控制欲App 端通过CBPeripheralManager提出的参数更新请求iOS 不一定会立刻接受它有自己的策略。Android 相对宽松requestConnectionPriority可以提三种模式。我实测下来的经验是参数更新请求要在连接建立后延迟 1~2 秒再发立即发容易被对端忽略。// MCU 侧发起连接参数更新以常见 BLE 协议栈 API 风格示意 gap_conn_param_t param { .interval_min 400, // 500ms .interval_max 400, .slave_latency 4, .timeout 600, // 6s单位 10ms }; gap_update_conn_param(param);3.3 广播与唤醒的设计取舍设备长期不连接的时候是保持广播还是彻底睡眠这取决于你的交互方式。如果设备一直广播功耗大约在 100~300μA 之间取决于广播间隔和广播信道数量这个对月级续航来说偏高了。我的做法是分状态待机状态不广播MCU 深度睡眠靠按键或传感器中断唤醒。用户交互后进入广播状态 30 秒等待 App 连接。连接后维持连接按连接参数周期唤醒。这样平均功耗能压到最理想的水平。有些场景比如设备需要被随时发现不能这么做那就得接受广播功耗或者用更长的广播间隔。还有一个省电技巧广播信道数。BLE 广播默认在 37、38、39 三个信道轮询发送只用一个信道能省三分之二的广播功耗代价是发现速度慢一些。如果你的 App 端扫描时间够长用单信道广播是划算的。注意广播间隔和发现速度是反比关系。间隔越大越省电但 App 扫描到的概率越低。我一般设 100ms 广播间隔、30ms 扫描窗口实测 2~3 秒内能发现设备功耗也能接受。3.4 断连重连的边界处理指令式方案里最容易被忽视的是重连后的状态恢复。BLE 有一个绑定机制配对后的设备重连可以跳过配对流程直接加密连接。这个机制用好重连时间能从 2~3 秒压到几百毫秒。但绑定信息存在哪里、怎么恢复各家芯片不一样。有的芯片绑定信息存在协议栈内部的 Flash 扇区有的要应用层自己存。我遇到过一个情况设备重置参数恢复出厂后绑定信息被清了但手机端还记着旧的绑定结果重连一直失败必须手机端忘记设备重新配对。处理办法是在固件的重置流程里明确调用协议栈的绑定信息清除接口并且在状态通知特征里上报一个已重置请重新配对的状态位。App 端收到这个状态位后主动清掉本地缓存重新走配对。这套逻辑不加的话售后会收到一堆连不上的反馈。4. 本地语音的存储、解码与播放实现4.1 语音数据的制作与格式选择本地语音的制作流程我走通的是这条链路文本 → 录音/合成 → 编辑降噪 → 重采样 → 压缩 → 打包烧录。具体参数上我推荐两种配置配置采样率位深压缩音质适用配置 A8kHz8bit无一般清晰可辨短提示音配置 B16kHz16bitADPCM 4:1较好需要在嘈杂环境听清配置 B 的 4:1 压缩后一条 3 秒语音的容量变成16000 × 16 / 8 × 3 / 4 24000 Bytes ≈ 23KB和配置 A 差不多但音质好很多所以我更推荐配置 B。ADPCM 的选择理由它的解码复杂度极低MCU 上一段几十行的查表加移位就能实现不需要 DSP 指令压缩率 4:1 足够把容量降下来而且它是有损压缩里对语音信号比较友好的不像 MP3 那样需要复杂运算。为什么不用 MP3 或 AAC解码库体积大、运算量大、还有授权问题。在资源受限的 MCU 上ADPCM 是性价比最高的选择。这一点我和做音频的同事讨论过他做音乐类产品觉得 ADPCM 音质不够但做语音提示完全够用。4.2 音频数据的 Flash 分区规划外挂 SPI Flash 一般按扇区4KB和块64KB管理。我的分区方案是这样的0x000000 ~ 0x000FFF 映射表区4KB存条目数与每条地址、长度 0x001000 ~ 0x0D0FFF 语音数据区约 832KB按条目顺序存放 0x0D1000 ~ 0x0D1FFF 用户配置区4KB音量、语言、序列号 0x0D2000 ~ 0x0D2FFF 预留区4KB映射表的结构typedef struct { uint32_t addr; // 语音数据在 Flash 中的起始地址 uint32_t length; // 数据长度字节 uint16_t crc; // 数据校验 uint8_t reserved; } voice_entry_t; // 12 字节4KB 可存 341 条为什么映射表要单独占一个扇区、还带 CRC因为语音数据烧录可能失败CRC 能在运行时检测数据损坏避免播报出乱七八糟的噪音。我在产线测试时就遇到过 Flash 焊接不良导致的读取错误有 CRC 就能及时发现并上报错误状态而不是让用户听到杂音。4.3 播放引擎的实现与中断设计播放引擎的核心是双缓冲 DMA/PWM 输出。不能边读 Flash 边播因为 Flash 读取有延迟和抖动会造成声音卡顿。我的实现是两块缓冲一块在播放由定时器中断或 DMA 从缓冲取数输出一块在后台从 Flash 预读下一段。当播放缓冲耗尽时切换切换的时机由中断控制。#define BUF_SIZE 256 static uint8_t buf_a[BUF_SIZE]; static uint8_t buf_b[BUF_SIZE]; static uint8_t *play_buf buf_a; static uint8_t *load_buf buf_b; // 定时器中断服务函数按采样率触发 void TIMER_IRQHandler(void) { static uint16_t idx 0; if (idx BUF_SIZE) { // 当前缓冲播完切换 play_buf load_buf; idx 0; // 触发下一块预读置标志在主循环里读 Flash preload_needed 1; } uint8_t sample play_buf[idx]; set_pwm_duty(sample); // 输出到 PWM/DAC }用 PWM 还是 DACPWM 更省事成本低一片 RC 低通滤波就能出声音质对提示音够用。DAC 音质好但要额外外设而且工作时电流比 PWM 高。我选的是 PWM理由是成本和功耗双优音质在语音提示场景不是瓶颈。定时器中断的频率要精确匹配采样率。8kHz 采样就是 8kHz 中断这意味着一秒 8000 次中断每次中断的执行时间必须远小于 125μs否则会丢样本。这就是为什么播放引擎必须精简绝不能在里面做 Flash 读取或复杂运算。实操心得中断里只做取一个样本、写 PWM 寄存器这两件事其他全部放到主循环。我见过有人在中断里做 Flash 读结果声音全是断断续续的就是这个原因。中断服务函数的执行时间要尽量控制在 10μs 以内。4.4 播报与睡眠的状态机整个设备的行为可以用一个状态机描述这个设计直接决定功耗[深度睡眠] --按键/中断-- [广播中] --App连接-- [连接态] ^ | | | 收到播报指令 | v | [播报中] | | |----------播报完成超时无活动----------------|各状态的功耗和处理逻辑状态功耗进入条件退出条件深度睡眠 10μA无事件按键或中断广播中100~300μA唤醒后连接或 30 秒超时连接态30~60μAApp 连接断连或播报指令播报中25~35mA收到播报指令播放完毕关键设计是播报时射频是否关闭。如果播报期间保持连接射频还得维持功耗上去了。我的做法是播报期间保留连接但不主动收发射频由协议栈按连接间隔自动调度应用层不干预播报完立即回到连接态。如果连接间隔是 500ms播报 3 秒期间也就几个连接事件影响很小。有个更激进的做法是播报时暂停连接gap_disconnect然后播报完重连但重连要时间而且用户体验上会有设备消失的错觉。除非播报很长10 秒以上否则不推荐。4.5 语音编号映射与动态更新语音条目不能写死在代码里要支持动态更新这是产线最容易遇到的需求。我的做法是映射表里留一个版本号字段设备启动时读映射表版本如果和固件里记录的不一致就重新加载。更新映射表的流程App 通过指令写特征进入配置模式一条特殊指令。逐条发送语音数据走专用数据特征分包传输。设备写入 Flash 对应地址更新映射表最后校验整体 CRC。App 发送退出配置模式设备重启生效。这个流程要处理的核心问题是传输中断的恢复。如果配置到一半断连了设备必须能恢复到上一个完整版本不能处于半更新状态。我的做法是双区备份映射表有两个扇区A 区是当前生效的B 区是更新中的。更新完成并校验通过后才把 B 区标记为生效。这个原子切换的思路和很多固件 OTA 方案是一样的可靠性有保障。5. 低功耗细节与平台差异坑位实录5.1 MCU 侧的低功耗模式选择不同 MCU 的低功耗模式差异很大我拿三个常见的系列对比这是我在实际项目中用过或测过的芯片深度睡眠电流唤醒时间BLE 集成HC32L196约 1~2μARTC 运行几十μs需外挂 BLEHC32F460约 5μA几十μs需外挂 BLEESP32 系列约 20μA轻度睡眠数百μs~ms内置 BLEnRF 系列约 1~2μA几十μs内置 BLE这个表里的数字是量级参考实际要看你的外设开多少。选型上的核心权衡是内置 BLE 省事但深度睡眠电流高ESP32 这类外挂 BLE 极致省电但增加成本和板子面积HC32L196 独立 BLE。ESP32 的轻度睡眠Light Sleep能开 BLE 保持连接实测深度睡眠模式下 BLE 是断的轻度睡眠下 BLE 连接维持的功耗在 1mA 上下这个数字对追求极致续航的产品偏高。所以如果你的目标是 100μA 级平均电流外挂 BLE 方案更现实。HC32L196 这类 MCU 本身的深度睡眠做到 1~2μA 很轻松关键是外设要全部关掉// 进入深度睡眠前的外设清理伪代码按实际寄存器操作 disable_adc(); disable_uart(); disable_spi_flash_cs_hold(); // 确保 Flash 片选不被误拉 switch_off_led(); enter_deep_sleep();漏电流的几个常见来源未配置的 GPIO 悬空导致漏电、Flash 片选悬空导致 Flash 进入活动态、LDO 静态电流过大。这三点我在不同项目里都踩过。GPIO 一定要么配置为输出低电平要么配置为带上拉的输入不能浮空。Flash 片选在不访问时必须拉高。注意LDO 的静态电流Quiescent Current经常被忽略。一颗普通 LDO 的静态电流可能是几十微安比你 MCU 深度睡眠的电流还大。选型时要专门看这个参数选低静态电流的型号。我用过一颗 LDO标称静态电流 1μA实测在轻载下确实低这个细节直接决定了能不能达到目标续航。5.2 iOS 与 Android 的 BLE 行为差异这是做 App 端最容易崩溃的地方我把踩过的坑整理出来。iOS 侧的核心差异iOS 对 BLE 后台运行限制很严。App 退到后台后BLE 连接能维持但扫描和广播能力受限。如果 App 需要在后台接收设备的通知必须在 Xcode 里勾选bluetooth-central后台模式否则连接会被系统挂起。连接参数上iOS 不太接受 App 提出的参数更新请求它自己有一套策略。实测下来要引导 iOS 接受你的参数得用CBPeripheralManager的setDesiredConnectionLatency接口而且CBCentralManagerScanOptionAllowDuplicatesKey这类扫描选项会影响功耗和发现行为。还有一个典型问题iOS 连接时对设备地址的感知。iOS 出于隐私考虑对设备的 MAC 地址做了随机化处理App 拿到的不是真实 MAC而是系统生成的一个 UUID。所以如果你的 App 逻辑依赖 MAC 地址区分设备iOS 上会失效。解决办法是用设备广播里的自定义数据段manufacturer data或其他自定义标识。Android 侧的核心差异Android 的连接参数更新接口是requestConnectionPriority可选CONNECTION_PRIORITY_HIGH、BALANCED、LOW_POWER三档。LOW_POWER 档对应较大的连接间隔适合我们这种低功耗场景。但 Android 的问题是碎片化不同厂商、不同系统版本对 BLE 的实现差异很大。有设备在扫描时对重复广播去重很激进导致发现不到设备有的在连接后对参数更新响应很慢。我的应对办法是在 App 端加重试和超时机制不要假设一次调用就成功。跨平台框架的坑用 uni-app、Flutter 这类跨平台框架做 BLEiOS 上的问题往往比 Android 多。Flutter 的 BLE 插件在 iOS 上后台连接和通知的稳定性需要额外配置deviceId在 iOS 上是系统 UUID不能用它和真实设备一一对应。如果 App 需要根据设备 ID 建立连接在 iOS 上必须用扫描阶段缓存下来的CBPeripheral对象而不是拿一个 ID 去连。实操心得跨平台 BLE 方案在 iOS 上的逻辑尽量用官方原生接口兜底。我给一个项目的做法是主要逻辑用跨平台框架但在 iOS 上遇到连接不稳时直接切到原生CoreBluetooth处理连接和通知绕开框架的封装问题。这个降级策略救过好几次场。5.3 常见问题速查表项目做下来我整理了一份问题速查表按现象 → 可能原因 → 排查方法组织现象可能原因排查方法播报有杂音/爆音功放静态偏置不对、PWM 滤波不足示波器看输出波形检查 RC 参数声音卡顿中断里做 Flash 读取、缓冲太小加大缓冲、中断精简连接后收不到通知CCCD 未开启、重连后重置检查订阅、重连后重新订阅待机电流偏高GPIO 悬空、Flash 未休眠、LDO 静态电流大逐一断开外设测量重连耗时长绑定信息丢失、参数更新失败检查绑定存储、延迟发参数更新广播发现不到广播间隔过大、信道太少缩短间隔、加广播信道播报一半断连监督超时设置过短按公式重新算超时值iOS 后台收不到未开后台模式、参数不被接受检查 Xcode 配置、用延迟更新参数这张表里的每一条都是我或同事真实遇到的不是凭空写的。比如连接后收不到通知这条最隐蔽的情况是重连后系统自动清了 CCCD 订阅App 端以为还在订阅状态实际早断了。解决办法是 App 端在每次连接成功后的发现服务流程中重新写一次 CCCD。5.4 实测功耗数据与优化路径最后给一组我实际项目的实测数据作为优化参考。测试条件HC32L196 外挂 BLE连接间隔 500ms从机延迟 43 秒语音播报每天 50 次。测试项实测值说明深度睡眠电流1.8μARTC 运行其他外设全关连接态平均电流42μA500ms 间隔 4 从机延迟播报态平均电流28mAPWM 输出MCU 全速整机平均电流约 55μA按每天 50 次播报计算500mAh 电池预估续航约 378 天500 / 0.055 / 24从纵向上看优化的路径按收益排序是连接参数优化收益最大 外设漏电流清理 播报时长和频率控制 MCU 低功耗模式。很多人一上来就折腾 MCU 的睡眠模式其实连接参数的收益比这大得多。我一开始也是先啃 MCU 手册后来发现把连接间隔从 100ms 调到 500ms电流直接降了一半多这个是最快的。关于播放时的电流如果对续航有极限要求可以考虑降低播放功率。PWM 输出的音量大可以接受小一点音量的话功放或者 PWM 驱动电流能降下来。这不是无脑降要保证在目标使用环境下能听清。我用的是固定音量的功放实测在安静环境 28mA 够嘈杂环境要提到 40mA 以上这个要在产品定义阶段就明确使用场景。后续这套方案还能往几个方向扩一是加入本地语音识别做成关键词唤醒配合指令播报但这会显著增加功耗要评估二是多设备场景下用 BLE Mesh但 Mesh 的功耗模型和点对点不一样不能直接套三是语音条目做云端增量更新配合差分升级减少传输量。这几个方向我还在摸索等跑出实测数据再单独整理。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价