4、语音合成芯片入门:SYN6288 数据手册解读、UART 通信协议、基本控制指令格式
好,咱们进入第四章。这一章要啃的,是语音合成芯片 SYN6288。说实话,这芯片我用了好多年,从早期的项目一直跟到现在。它不算新,但胜在稳定、便宜、资料全。做嵌入式药盒,用它来报时、提醒吃药,再合适不过了。
你拿到一个芯片,第一件事是什么?别急着焊板子。先看数据手册。我见过太多人,上来就抄网上的代码,结果连波特率都配错了。嗯,咱们一步步来。
4.1 SYN6288 数据手册解读
SYN6288 是中科蓝讯推出的一款中高端语音合成芯片。它支持中文、英文混读,内置了 16 位 DAC 输出,可以直接驱动喇叭。我个人习惯,拿到数据手册先翻到“电气特性”那一页,看看供电电压和电流。
关键参数速览:
- 供电电压:3.3V(注意,不是 5V!我曾经在调试时不小心接了 5V,芯片直接冒烟了...)
- 工作电流:典型 40mA,待机小于 5mA
- UART 波特率:默认 9600bps(可配置为 19200)
- 语音合成方式:TTS(Text To Speech),支持 GB2312 编码
数据手册里还有引脚定义。SYN6288 是 SOP16 封装,引脚不多。我重点说几个:
- VDD(3.3V) 和 GND:电源,别搞反了。
- RXD 和 TXD:UART 通信口。注意,RXD 接单片机的 TXD,TXD 接单片机的 RXD。交叉连接,这是新手最容易犯的错。
- BUSY:忙信号输出。高电平表示芯片正在合成语音,低电平表示空闲。这个引脚很有用,可以用来判断是否播放完毕。
- SPK+ 和 SPK-:喇叭输出,直接接 8 欧姆喇叭就行,不用加功放。
我的小技巧: 调试时,把 BUSY 引脚接到一个 LED 上。芯片忙时 LED 亮,空闲时灭。这样一眼就能看出芯片状态,比看串口日志直观多了。
4.2 UART 通信协议
SYN6288 通过 UART 接收指令。说白了,就是单片机发一串十六进制数据过去,芯片解析后合成语音。协议很简单,但格式必须严格,错一个字节都不行。
数据帧格式如下:
| 帧头 | 数据长度 | 命令字 | 数据区 | 校验和 |
|---|---|---|---|---|
| 0xFD | 1 字节 | 1 字节 | N 字节 | 1 字节 |
帧头固定是 0xFD,这是 SYN6288 的识别码。数据长度是指从命令字开始到校验和之前的所有字节数。命令字决定了你要做什么,比如合成语音、停止播放、设置音量等。
校验和的计算方式:从帧头开始,到数据区最后一个字节,所有字节累加,取低 8 位。嗯,这里要注意,校验和是 累加和取反再加 1,也就是补码。我刚开始写代码时,直接用了累加和,结果芯片死活没反应。后来查了半天才发现是校验和算错了。
避坑指南: 我曾经在项目中,因为 UART 波特率设置不匹配,导致芯片一直没响应。SYN6288 默认是 9600bps,8 位数据,1 位停止位,无校验。如果你用 115200 去发,它根本不理你。所以,先确认波特率。
4.3 基本控制指令格式
咱们直接看几个最常用的指令。学会了这些,药盒的语音提示功能就基本能跑起来了。
4.3.1 合成语音指令
这是最核心的指令。格式如下:
帧头: 0xFD
数据长度: 0x?? (从命令字到数据区结束的字节数)
命令字: 0x01 (合成语音)
数据区: 待合成的文本,GB2312 编码
校验和: 累加和取反+1
举个例子,让芯片说“请吃药”:
// "请吃药" 的 GB2312 编码
// 请: 0xC7 0xEB
// 吃: 0xB3 0xD4
// 药: 0xD2 0xA9
// 数据帧:
0xFD, 0x07, 0x01, 0xC7, 0xEB, 0xB3, 0xD4, 0xD2, 0xA9, 校验和
// 计算校验和:
// 0xFD + 0x07 + 0x01 + 0xC7 + 0xEB + 0xB3 + 0xD4 + 0xD2 + 0xA9 = 0x5A5
// 取低8位: 0xA5
// 取反: 0x5A
// 加1: 0x5B
// 所以校验和是 0x5B
// 完整数据帧:
0xFD, 0x07, 0x01, 0xC7, 0xEB, 0xB3, 0xD4, 0xD2, 0xA9, 0x5B
注意: 数据长度是 0x07,它包含了命令字 0x01 和后面的 6 个字节数据(3 个汉字,每个汉字 2 字节)。别算错了,否则芯片会忽略这条指令。
4.3.2 停止播放指令
有时候需要立即停止当前语音,比如用户按了取消键。指令如下:
0xFD, 0x01, 0x02, 校验和
// 校验和计算:
// 0xFD + 0x01 + 0x02 = 0x100
// 取低8位: 0x00
// 取反: 0xFF
// 加1: 0x00 (溢出)
// 所以校验和是 0x00
这个指令只有 4 个字节,非常简单。数据长度是 0x01,只包含命令字本身。
4.3.3 设置音量指令
药盒在不同场景下可能需要不同音量。比如白天可以大点声,晚上就小点。指令格式:
0xFD, 0x02, 0x03, 音量值, 校验和
// 音量值范围: 0x00 ~ 0x0F (0 最小,15 最大)
// 例如设置音量为 10:
0xFD, 0x02, 0x03, 0x0A, 校验和
// 校验和计算:
// 0xFD + 0x02 + 0x03 + 0x0A = 0x10C
// 取低8位: 0x0C
// 取反: 0xF3
// 加1: 0xF4
// 所以校验和是 0xF4
我的经验: 音量不要设到最大(0x0F),因为 SYN6288 的功放部分会有轻微失真。我一般设到 0x0C(12)左右,声音清晰又不刺耳。你可以在项目里做个音量调节功能,让用户自己选。
4.4 实战:让芯片说一句话
好了,理论讲完了。咱们写个简单的 C 代码片段,演示如何发送合成语音指令。假设你用的是 STM32 或类似的单片机。
// 发送合成语音指令
void SYN6288_Speak(uint8_t *text, uint8_t len)
{
uint8_t i;
uint8_t checksum = 0;
uint8_t frame[50]; // 假设文本不超过 50 字节
// 构建帧头
frame[0] = 0xFD;
frame[1] = len + 1; // 数据长度 = 命令字(1) + 文本长度(len)
frame[2] = 0x01; // 命令字:合成语音
// 复制文本数据
for(i = 0; i < len; i++)
{
frame[3 + i] = text[i];
}
// 计算校验和
for(i = 0; i < (3 + len); i++)
{
checksum += frame[i];
}
checksum = ~checksum + 1; // 取反加1
// 添加校验和
frame[3 + len] = checksum;
// 通过 UART 发送
UART_Send(frame, 4 + len);
}
// 调用示例
uint8_t text[] = {0xC7, 0xEB, 0xB3, 0xD4, 0xD2, 0xA9}; // "请吃药"
SYN6288_Speak(text, 6);
这段代码很直白。你只需要把待合成的文本转换成 GB2312 编码,然后调用 SYN6288_Speak 函数就行。注意,文本长度是字节数,不是汉字个数。一个汉字占 2 个字节。
又一个坑: 文本编码必须是 GB2312,不是 UTF-8。如果你在 PC 上写代码,编辑器默认可能是 UTF-8,直接复制到单片机里,芯片会合成出乱码。我建议你在代码里直接写十六进制数组,或者用专门的编码转换工具。
嗯,这一章的内容就这些。SYN6288 其实还有很多高级功能,比如控制语速、语调、添加数字播报等。但咱们做药盒,掌握上面这些就够用了。下一章,我会带你把这些指令封装成一个驱动库,方便后续调用。
记住,芯片不复杂,复杂的是细节。多读几遍数据手册,多动手写代码,很快你就能玩转它。