一款低成本高效的语音识别方案
前言
随着 AI 应用的普及,语音交互已成为终端设备的核心能力之一。语音采集与音频数据传输,是这条交互链路上的核心环节。
对实际的产品来说,需求是多样的:有的走 USB 有线,有的要蓝牙,有的用私有 2.4G,而常见做法是——一颗主 MCU,外挂一颗专用音频芯片;如果需要无线传输,还得再加一颗负责无线的芯片。传输通路每多一种,BOM 上就多一颗料,成本、PCB 面积和功耗都得往上抬。
有没有办法用一颗芯片把这几条路都走通?
本文给出的思路是:基于沁恒青稞 RISC-V 无线系列 MCU(CH58x/CH59x),提供一套低成本的语音采样方案设计。单芯片即可实现 USB UAC 音频、蓝牙音频、2.4G 无线音频 三大传输通路,覆盖有线与无线全场景的语音交互需求,适配语音遥控器、无线麦克风、会议拾音棒、USB 语音声卡、便携语音采集终端等各类产品。
目录
一、语音采样基础
1.1 语音采样流程
完整的语音链路步骤如下:
收音 → 偏置/放大 → ADC 采样 → 数字音频流 → 编码(可选) → 传输 → 解码(可选)
收音
由麦克风把声波转换为电信号。目前主流是两种:
| 类型 | 输出 | 特点 |
|---|---|---|
| ECM(驻极体电容麦克风) | 模拟信号 | 成本极低、使用广泛;需要外部偏置电路,相对来说一致性与抗干扰能力一般 |
| MEMS 麦克风 | 模拟或数字 | 体积小、一致性好、抗 RF 干扰强,适合小型化和量产; 数字输出成本相对较高,本文不考虑 |
偏置/放大
MIC 头子输出信号幅度只有毫伏级,必须先放大到 ADC 的有效输入范围。
对于 驻极体 MIC 语音采集电路,我们需要加个偏置电路进入到运放 ,如果是硅麦的话,可以省偏置电阻,直接进入到放大电路。
这一步的增益设计很关键:增益过小,信号淹没在量化噪声里,底噪明显;增益过大,大音量时波形削顶失真 。
一款通用的 MIC 采样放大电路如下:

这个通用的方案是可靠并且可以实际使用的,只需要根据自己需求调节好增益,但是本文我们最求的是低成本,所以我们会采用一套三极管搭建的方案,下文硬件实现会有说明。
ADC 采样
ADC 采样使用芯片自带 ADC 即可。
把连续的模拟信号离散成数字量,连续的声音能够采集播放的原理就像:高速连拍照片,连起来就是视频。快速播放一串按时间排列的电压数字。
比如 每 1/16000 秒(16K采样率 )采样一次电压,把电压通过 ADC 转成数字,这些数字排成一串就是 PCM 数据,PCM 就是原始的数字音频编码方式。
编解码(可选)
PCM 直传的数据量偏大,很一些场景在传输前需要压缩。
嵌入式领域常见的编解码如下表格:

1.2 几个关键参数
对于做语音采样设计,有几个关键的参数。
本节内容和上面表格参考来自博文:嵌入式语音开发应用基础说明
1.2.1 采样率
人声的主要能量集中在 300 Hz – 3.4 kHz,按奈奎斯特采样定理,采样率需不低于信号最高频率的 2 倍。
所以传统传统通话标准 (G.711 标准)使用的 8KHz 的采样率。
现在 主流 AI 语音的标准采样率 16KHz ,更高的采样率保留的声音听起来更加自然。
采样率直接关系到芯片 ADC 的采样周期配置。
1.2.2 位深/声道
位深 = 每个采样点用多少位(bit)来存储幅度值,一般就是 8bit 和 16bit 。
16 位深的数据量相比 8 位直接翻倍。
单声道 / 双声道:
对于语音来说,单声道完全够用,双声道几乎不提升效果,只会徒增数据量(也是翻倍)、带宽、功耗;只有音乐 / 立体音效场景,双声道才有意义。
1.2.3 码率
码率(也叫比特率),是指音频在播放或传输时,一秒钟要消耗/产生多少个“比特(bit)”的数据。
是决定 传输带宽够不的那个量:
码率 = 采样率 × 位深 × 声道数
它同时是后面选择传输通路、判断要不要编码的依据。
现在的主流 AI 语音标准:
参数:采样率 16kHz、位深 16bit、单声道
码率=16000×16×1=256000 bps=256 Kbps
语音应用中,可以使用编码压缩的方式减少码率,以获得更小的资源需求 。
二、方案说明
上面讲解了一下基础知识,接下来介绍一下本文说要讲解的方案: 基于沁恒 CH58x/CH59x 低功耗蓝牙MCU, 应用框图如下:

采样芯片可使用 CH59x/CH58x,集成12位ADC采集外部模拟MIC信号,支持16 kHz 采样率。芯片兼容BLE5.4规范,支持最高2Mbps速率,-95dBm 灵敏度和最高 +9dBm 发射功率可有效满足室内通讯要求,保障数据传输稳定性,提升识别准确率 。
2.1 硬件实现
得益于沁恒蓝牙芯片,自带 USB ,蓝牙,所以我们只需要芯片的最小系统,加上音频采样电路,就可以实现我们的功能。
2.1.1 芯片最小系统
对于不同系列的芯片,沁恒都会在 EVT 里面提供 开发板的原理图和 PCB,最小系统没有什么难度 。
比如我们想用 CH585 ,可以直接在官网搜索CH585 :

然后解压出来 PCB 原理图在 PUB 目录下,里面会提供 PCB 设计注意事项文档说明以及 开发板的原理图 :

我们可以看到官方给出的 EVT 板子,然后参照官方给的原理图自己画最小系统(下图因为 CH585功能比较多, 具有 NFC 和 高速 USB,实际使用不需要的就不用画):

2.1.2 语音采样电路
本方案提供一个低成本的采样电路,只需要一个三极管加上几个阻容便可实现:

对于此电路的分析,可参考博文:语音采样电路说明测试
2.2 软件实现
对于使用示例,本文实现了一个方便测试的 USB UAC 设备,即插即用 。软件部分我们只看几个典型的关键部分。
ADC 采样配置:
void mic_start_record(uint16_t *buffer_start, uint16_t *buffer_end)
{
MIC_POWER_ON();
mic_data_fifo_reset();
ADC_ExtSingleChSampInit(SampleFreq_4_or_2, ADC_PGA_1_2);
ADC_ChannelCfg(2);
ADC_AutoConverCycle(12); // (256-22)*16 16025.6 HZuint8_t8K (256-139)*16 32.051Kuint16_t
ADC_DMACfg(ENABLE, (uint32_t)buffer_start, (uint32_t)buffer_end, ADC_Mode_LOOP);
tmos_start_task(halTaskID, HAL_MICS_EVENT, 8);
}
数据搬运至缓冲区:
//定时器没1ms 执行一次搬运
__INTERRUPT
__HIGH_CODE
void TMR2_IRQHandler(void) // TMR0
{
if(TMR2_GetITFlag(TMR0_3_IT_CYC_END))
{
TMR2_ClearITFlag(TMR0_3_IT_CYC_END); //
extern void mic_produce(void);
mic_produce();
}
}
/*
mic_produce()
├─ 从 record_buffer 取 ADC 原始值
├─ 数据处理
├─ 存入局部 pcm_buf[16]
└─ 调用 usb_mic_push_samples(pcm_buf, cnt) ──→ mic_ring[] 写入
*/
__HIGH_CODE
void mic_produce(void)
{
uint16_t dma_idx = (R32_ADC_DMA_NOW - R32_ADC_DMA_BEG) / 4;
uint16_t avail = (dma_idx - g_mic_prod_idx) & (RB_SIZE - 1);
uint16_t pcm_buf[16];
uint16_t cnt = 0;
/* One sample per record_buffer entry (ADC ~8kHz matches the 8kHz USB consumer).
Each entry holds a differential pair [0]/[1]; average them. No 2:1 decimation
(ADC is already ~8kHz, not 16kHz; decimating caused ring underrun -> zero fill -> noise). */
while (avail >= 1)
{
uint32_t avg = ((uint32_t)record_buffer[g_mic_prod_idx][0] + record_buffer[g_mic_prod_idx][1]) / 2;
int16_t pcm = (int16_t)(avg - 2048) << 4; /* center -> 16-bit signed */
pcm_buf[cnt++] = (uint16_t)pcm;
g_mic_prod_idx = (g_mic_prod_idx + 1) & (RB_SIZE - 1);
avail -= 1;
if (cnt >= (sizeof(pcm_buf) / sizeof(pcm_buf[0]))) /* flush if local buffer full */
{
usb_mic_push_samples(pcm_buf, cnt);
cnt = 0;
}
}
if (cnt)
{
usb_mic_push_samples(pcm_buf, cnt);
}
/* Drive EP1 ISO IN re-arm every 1ms: UIS_TOKEN_IN does not reliably fire for ISO,
so pump a fresh frame into EP1 from this TMR2 1ms tick. */
if (usb_mic_streaming)
{
usb_mic_load_frame();
}
}
//上面处理 ADC 数据调用下面搬运函数
__HIGH_CODE
void usb_mic_push_samples(const uint16_t *samples, uint16_t n)
{
uint16_t next;
while (n--)
{
next = (mic_ring_head + 1) & MIC_RING_MASK;
if (next == mic_ring_tail)
{
return; /* full: drop remaining samples */
}
mic_ring[mic_ring_head] = *samples++;
mic_ring_head = next;
}
}
USB 传输部分:
__HIGH_CODE
void usb_mic_load_frame(void)
{
uint8_t i;
uint16_t *p = (uint16_t *)pEP1_IN_DataBuf;
int16_t s;
for (i = 0; i < MIC_FRAME_SAMPLES; i++)
{
s = 0; /* silence on underrun */
if (mic_ring_head != mic_ring_tail)
{
s = (int16_t)mic_ring[mic_ring_tail];
mic_ring_tail = (mic_ring_tail + 1) & MIC_RING_MASK;
}
p[i] = (uint16_t)s; /* RISC-V is little-endian: store directly = LE PCM */
}
DevEP1_IN_Deal(MIC_FRAME_BYTES); /* R8_UEP1_T_LEN=16 + TX ACK */
}
void DevEP1_IN_Deal(uint8_t l)
{
R8_UEP1_T_LEN = l; // 告诉硬件:要发 16 字节
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;// 告诉硬件:主机来问就回 ACK(给数据)
}
三、效果展示
3.1 测试步骤
1、 通过 USB 连接 PC 后,电脑端会自动识别到 USB 麦克风输入设备,无需额外安装驱动。在系统音频设置中,将默认输入设备切换为识别到的 USB MIC 设备(如果没有其他的 MIC 设备,系统会默认选择)。
2、 打开录音软件、音频测试工具或 AI 模型,直接对 MIC 说话即可。
3.2 实测效果
实测效果大家直接看视频即可:
语音采样测试效果
结语
本文展示了基于 CH58x 芯片的一种低成本语音识别方案,大家可以通过视频很直观的看到测试效果,完全能够满足目前各大 AI 语音识别的应用 。
对于实际应用中,需要使用无线的场合,要合理的根据应用场景,进行必要的编解码,以减小数据的码率。对于目前的沁恒的蓝牙芯片来说,传输速率是完全没有问题的。那这实际上就是软件层面的问题,这个后期我们可以进一步的探讨。
更多推荐


所有评论(0)