串口通信协议说明
Oldwu-StudioDSP产品串口通信协议V2.2
本文档适用于Oldwu-Studio山景BP10系带串口通信功能的固件,目前公版支持该协议的有音乐串口固件和K歌串口固件,如需定制请联系我
本文档为标准版文档,仅提供基础控制和基本信息获取,如需拓展更多功能如音效控制等,请联系作者索取文档
注意
版权声明:任何人不得以任何形式 (如:电子的、机械的、手书的、光学存储的或以其它语言表述的形式,等等) 复制、复印或存储本文件的全部或一部分内容,除非得到作者的书面同意。如有人在作者未经允许的情况下传播、分发该文档,必要时将追究刑事责任!
版本历史
| 版本 | 日期 | 变更内容 |
|---|---|---|
| 2.1 | 2025年09月03日 | 文档编写 |
| 2.2 | 2025年09月20日 | 增加媒体信息获取协议,删除串口通信下部分无用的回包内容 |
1. 协议约定
1.1 版本号约定
规约版本号是对本规约不同版本的标识,由大版本、中版本和小版本三部分组成。例如'00 01 00'代表V0.1.0。
1.2 通讯方式约定
采用以用户应用程序主动发起设置参数和请求参数值的方式。
数据域内的2字节参数按小端格式存储。
2. 通讯模式
UART模式
UART参数配置如下表格:
| UART参数 | 值 |
|---|---|
| 波特率 | 115200 |
| 数据位 | 8 bits |
| 停止位 | 1 bit |
| 校验位 | 无 |
数据发送和接收均为透明传输,例如通过UART查询固件版本号,直接发送A5 5A 00 00 16.
3. 数据帧格式
3.1 帧结构
数据帧包含起始码、控制字、数据长度、数据域、结束码。
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 2字节 | 1字节 | 1字节 | 变长 | 1字节 |
3.2 字节定义
- 起始码:2字节,该值定义为
0xA5, 0x5A; - 控制字:1字节,该类型码用于区分不同的控制命令;
- 数据长度:1字节,若值为0表示无数据域;
- 数据域:存放数据的区域,2字节参数按小端存储;
- 结束码:1字节,该值定义为
0x16。
4. 控制字定义
控制字具体定义见下表:
Read代表只读属性,不可操作;Write代表只写入属性(一般为控制指令);R/W代表可读取又可以写入的指令,一般用于音效控制
| 控制字 | 含义 | 类型 |
|---|---|---|
| 0xEB | 媒体信息参数 | Read |
| 0xEF | 获取可用系统模式 | Read |
| 0xF0 | 设备控制参数 | Write |
| 0xF1 | 音效配置文件查询 | Read |
| 0xF8 | 系统状态参数 | Read |
5. 控制字格式
0xEB:媒体信息参数
本功能的歌曲信息获取功能仅在蓝牙模式和媒体播放(U盘、TF卡)模式下可用。蓝牙歌词需要播放器支持(例网易云音乐需要打开车载蓝牙歌词功能),媒体播放的歌词信息需要在储存器中放入同名lrc歌词文件,播放时会自动解析。
请求参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xEB | 0x01 | 查询类型(1字节) | 0x16 |
查询类型说明
| 值 | 说明 |
|---|---|
| 0 | 获取概览信息 |
| 1 | 获取歌词 |
| 2 | 获取标题 |
| 3 | 获取专辑 |
响应参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xEB | 1字节 | 见参数内容说明,参数不定长 | 0x16 |
参数内容
版本号机制:歌词、标题和专辑信息各有独立的版本号,当内容更新时版本号会变化,可用于判断信息是否需要重新获取,因此正确的做法是先判断版本号是否变化,如果变化再去获取文本内容
文本编码:所有文本信息(歌词、标题、专辑)均使用GBK编码格式
查询类型0:概览信息响应
| 参数字节位置 | 参数名 | 说明 |
|---|---|---|
| 0(1字节) | 查询类型 | 回显请求的查询类型:0 |
| 1(1字节) | 当前是否支持媒体信息获取 | 0:不支持(仅支持播放状态) 1:支持 |
| 2(1字节) | 播放状态 | 0:未播放 1:播放中 |
| 3-4(2字节) | 当前播放时间 | 单位:秒(小端存储) |
| 5-6(2字节) | 总播放时间 | 单位:秒(小端存储) |
| 7-8(2字节) | 当前歌曲序号 | 当前播放的歌曲位置(小端存储) |
| 9-10(2字节) | 歌曲总数 | 总歌曲数量(小端存储) |
| 11(1字节) | 歌词版本号 | 歌词信息的版本号 |
| 12(1字节) | 标题版本号 | 标题信息的版本号 |
| 13(1字节) | 专辑版本号 | 专辑信息的版本号 |
注意:当不支持媒体信息时(参数1为0),参数3-13均为0
查询类型1:歌词信息响应
| 参数字节位置 | 参数名 | 说明 |
|---|---|---|
| 0(1字节) | 查询类型 | 回显请求的查询类型:1 |
| 1-n(变长) | 歌词内容 | GBK编码的歌词文本,长度由数据长度字段确定 |
查询类型2:标题信息响应
| 参数字节位置 | 参数名 | 说明 |
|---|---|---|
| 0(1字节) | 查询类型 | 回显请求的查询类型:2 |
| 1-n(变长) | 标题内容 | GBK编码的标题文本,长度由数据长度字段确定 |
查询类型3:专辑信息响应
| 参数字节位置 | 参数名 | 说明 |
|---|---|---|
| 0(1字节) | 查询类型 | 回显请求的查询类型:3 |
| 1-n(变长) | 专辑内容 | GBK编码的专辑文本,长度由数据长度字段确定 |
示例1:获取概览信息
请求内容
A5 5A EB 01 00 16响应内容
A5 5A EB 0E 00 01 01 04 00 EB 00 06 00 0B 00 04 04 04 16解析内容
"A5 5A" -> 起始码
"EB" -> 控制字(媒体信息参数)
"0E" -> 数据长度:14字节
"00" -> 参数0(查询类型):0(概览信息)
"01" -> 参数1(是否支持媒体信息):1(支持)
"01" -> 参数2(播放状态):1(播放中)
"04 00" -> 参数3-4(当前播放时间):4秒
"EB 00" -> 参数5-6(总播放时间):235秒
"06 00" -> 参数7-8(当前歌曲序号):第6首
"0B 00" -> 参数9-10(歌曲总数):共11首
"04" -> 参数11(歌词版本号):4
"04" -> 参数12(标题版本号):4
"04" -> 参数13(专辑版本号):4
"16" -> 结束码示例2:获取歌词
请求内容
A5 5A EB 01 01 16响应内容
A5 5A EB 12 01 CE D2 B5 C4 CF C8 CC EC B1 BB D1 B5 C1 B7 B9 FD 0D 16解析内容
"A5 5A" -> 起始码
"EB" -> 控制字(媒体信息参数)
"12" -> 数据长度:18字节
"01" -> 参数0(查询类型):1(歌词)
"CE D2 B5 C4 CF C8 CC EC B1 BB D1 B5 C1 B7 B9 FD 0D" -> 歌词内容(GBK编码):"我的先天被训练过\r"
"16" -> 结束码示例3:获取标题
请求内容
A5 5A EB 01 02 16响应内容
A5 5A EB 19 02 47 2E 45 2E 4D 2E B5 CB D7 CF C6 E5 20 2D 20 BE E4 BA C5 2E 46 4C 41 43 16解析内容
"A5 5A" -> 起始码
"EB" -> 控制字(媒体信息参数)
"19" -> 数据长度:25字节
"02" -> 参数0(查询类型):2(标题)
"47 2E 45 2E 4D 2E B5 CB D7 CF C6 E5 20 2D 20 BE E4 BA C5 2E 46 4C 41 43" -> 标题内容(GBK编码):"G.E.M.邓紫棋 - 句号.FLAC"
"16" -> 结束码示例4:获取专辑
请求内容
A5 5A EB 01 03 16响应内容
A5 5A EB 01 03 16解析内容
"A5 5A" -> 起始码
"EB" -> 控制字(媒体信息参数)
"01" -> 数据长度:1字节
"03" -> 参数0(查询类型):3(专辑)
"16" -> 结束码注意:当文本内容为空时,仅返回查询类型字段
0xEF:获取可用系统模式
请求参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xEF | 0x00 | 无 | 0x16 |
响应参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xEF | 变长 | 见参数内容说明 | 0x16 |
参数内容
| 参数字节位置 | 参数名 |
|---|---|
| 0(1字节) | 可用模式数量 |
| 1-N(变长) | 可用模式ID列表,每个模式占1字节,参数枚举见系统模式枚举 |
示例:获取可用系统模式
请求内容
A5 5A EF 00 16响应内容
A5 5A EF 06 05 03 04 06 0A 0D 16解析内容
"A5 5A" -> 起始码
"EF" -> 控制字(获取可用系统模式)
"06" -> 数据长度:6字节
"05" -> 可用模式数量:5个
"03" -> 模式ID:3(AUX输入)
"04" -> 模式ID:4(TF卡播放)
"06" -> 模式ID:6(蓝牙音乐)
"0A" -> 模式ID:10(USB声卡)
"0D" -> 模式ID:13(光纤模式)
"16" -> 结束码0xF0:设备控制参数
请求参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xF0 | 0x03 | 控制类型(1字节) + 参数值(2字节) | 0x16 |
响应参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xF0 | 0x02 | 控制类型(1字节) + 状态码(1字节) | 0x16 |
参数内容
| 参数字节位置 | 参数名 | 参数定义 |
|---|---|---|
| 0(1字节) | 控制类型 | 设备控制类型,参见设备控制类型枚举 |
| 1-2(2字节) | 参数值 | 控制参数值,小端存储 |
响应状态码定义
| 状态码 | 含义 |
|---|---|
| 0 | 执行失败 |
| 1 | 执行成功 |
| 2 | 未找到指令 |
| 其他 | 功能自定义状态 |
注意部分指令并不会返回状态码,比如重启和恢复出厂设置,成功后MCU直接重置了
示例:修改音乐音量为8
请求内容
A5 5A F0 03 00 08 00 16响应内容
A5 5A F0 02 00 01 16请求内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"03" -> 数据长度:3字节
"00" -> 控制类型:0x00(音乐音量控制)
"08 00" -> 参数值:8(小端存储,音量值为8)
"16" -> 结束码响应内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"02" -> 数据长度:2字节
"00" -> 控制类型:0x00(音乐音量控制)
"01" -> 状态码:1(执行成功)
"16" -> 结束码示例:切换到音效模式3
请求内容
A5 5A F0 03 10 03 00 16响应内容
A5 5A F0 02 10 01 16请求内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"03" -> 数据长度:3字节
"10" -> 控制类型:0x10(音效模式控制)
"03 00" -> 参数值:3(小端存储,切换到音效模式3)
"16" -> 结束码响应内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"02" -> 数据长度:2字节
"10" -> 控制类型:0x10(音效模式控制)
"01" -> 状态码:1(执行成功)
"16" -> 结束码示例:设置麦克风混响值为20
请求内容
A5 5A F0 03 26 14 00 16响应内容
A5 5A F0 02 26 01 16请求内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"03" -> 数据长度:3字节
"26" -> 控制类型:0x26(麦克风混响)
"14 00" -> 参数值:20(小端存储,混响值为20)
"16" -> 结束码响应内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"02" -> 数据长度:2字节
"26" -> 控制类型:0x26(麦克风混响)
"01" -> 状态码:1(执行成功)
"16" -> 结束码示例:重启MCU
请求内容
A5 5A F0 03 FF 00 00 16请求内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"03" -> 数据长度:3字节
"FF" -> 控制类型:0xFF(重启MCU)
"00 00" -> 参数值:0(小端存储,无参数值)
"16" -> 结束码示例:未知控制类型
请求内容
A5 5A F0 03 AA 05 00 16响应内容
A5 5A F0 02 AA 02 16请求内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"03" -> 数据长度:3字节
"AA" -> 控制类型:0xAA(未定义的控制类型)
"05 00" -> 参数值:5(小端存储)
"16" -> 结束码响应内容解析
"A5 5A" -> 起始码
"F0" -> 控制字(设备控制参数)
"02" -> 数据长度:2字节
"AA" -> 控制类型:0xAA(未定义的控制类型)
"02" -> 状态码:2(未找到指令)
"16" -> 结束码0xF1:音效配置文件查询
请求参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xF1 | 0x00 | 无 | 0x16 |
响应参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xF1 | 变长字节 | 见参数内容说明,参数不定长 | 0x16 |
参数内容
| 参数字节位置 | 参数名 |
|---|---|
| 0(1字节) | 音效配置文件总数,范围:0-255 |
| 1-N(变长) | 音效名称数据,格式:长度+名称内容 |
音效名称数据格式说明
每个音效名称的数据结构:
- 第1字节:音效名称长度(字节数)
- 后续字节:音效名称内容(UTF-8编码)
示例:获取音效配置文件列表
请求内容
A5 5A F1 00 16响应内容
A5 5A F1 3D 06 09 45 66 66 65 63 74 31 5F 46 09 45 66 66 65 63 74 32 5F 46 09 45 66 66 65 63 74 33 5F 46 09 45 66 66 65 63 74 34 5F 46 09 45 66 66 65 63 74 35 5F 46 09 45 66 66 65 63 74 36 5F 46 16解析内容
"A5 5A" -> 起始码
"F1" -> 控制字(音效配置文件查询)
"3D" -> 数据长度:61字节
"06" -> 音效配置文件总数:6个
音效1:
"09" -> 名称长度:9字节
"45 66 66 65 63 74 31 5F 46" -> 名称内容:"Effect1_F"
音效2:
"09" -> 名称长度:9字节
"45 66 66 65 63 74 32 5F 46" -> 名称内容:"Effect2_F"
音效3:
"09" -> 名称长度:9字节
"45 66 66 65 63 74 33 5F 46" -> 名称内容:"Effect3_F"
音效4:
"09" -> 名称长度:9字节
"45 66 66 65 63 74 34 5F 46" -> 名称内容:"Effect4_F"
音效5:
"09" -> 名称长度:9字节
"45 66 66 65 63 74 35 5F 46" -> 名称内容:"Effect5_F"
音效6:
"09" -> 名称长度:9字节
"45 66 66 65 63 74 36 5F 46" -> 名称内容:"Effect6_F"
"16" -> 结束码0xF8:系统状态参数
请求参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xF8 | 0x00 | 无 | 0x16 |
响应参数
| 起始码 | 控制字 | 数据长度 | 数据域 | 结束码 |
|---|---|---|---|---|
| 0xA5 | 0x5A | 0xF8 | 1 字节 | 见参数内容说明,参数不定长 | 0x16 |
参数内容
| 参数字节位置 | 参数名 |
|---|---|
| 0-1(2字节) | 已使用内存,单位KB |
| 2-3(2字节) | 已使用CPU,单位Mips |
| 4-5(2字节) | CPU最大频率,单位Mips |
| 6-7(2字节) | 最大内存值,单位KB |
| 8(1字节) | 当前系统模式,参数枚举见系统模式枚举 |
| 9(1字节) | 音乐音量值,范围:0-32 |
| 10(1字节) | 蓝牙HF通话音量值,范围:0-32 |
| 11(1字节) | 麦克风音量值,范围:0-32 |
| 12(1字节) | 当前音效配置文件索引,范围由音效个数配置决定(默认0-5) |
| 13-14(2字节) | 电源检测电压值,单位毫伏mv |
| 15(1字节) | 计算的电池容量百分比,范围:0-100 |
| 16(1字节) | 是否正常充电,0未充电 1正在充电。仅带充电检测功能的固件可用 |
| 17(1字节) | 音乐低音值,范围0-31,db对应关系见高低音调节增益表 |
| 18(1字节) | 音乐中音值,范围0-31,db对应关系见高低音调节增益表 |
| 19(1字节) | 音乐高音值,范围0-31,db对应关系见高低音调节增益表 |
| 20(1字节) | 麦克风低音值,范围0-31,db对应关系见高低音调节增益表。仅K歌固件可用 |
| 21(1字节) | 麦克风中音值,范围0-31,db对应关系见高低音调节增益表。仅K歌固件可用 |
| 22(1字节) | 麦克风高值,范围0-31,db对应关系见高低音调节增益表。仅K歌固件可用 |
| 23(1字节) | 麦克风回声混响值,范围0-31。仅K歌固件可用 |
| 24(1字节) | 麦克风回声值,范围0-31。仅K歌固件可用 |
示例:获取配置
请求内容
A5 5A F8 00 16响应内容
A5 5A F8 19 0C 01 27 00 40 01 40 01 0D 0C 0F 20 00 A3 0F 56 00 0F 0F 0F 00 00 00 1F 1F 16解析内容
"A5 5A" -> 起始码
"F8" -> 控制字(系统状态参数)
"19" -> 数据长度:25字节
"0C 01" -> 参数0-1(已使用内存):268 KB
"27 00" -> 参数2-3(已使用CPU):39 Mips
"40 01" -> 参数4-5(CPU最大频率):320 Mips
"40 01" -> 参数6-7(最大内存值):320 KB
"0D" -> 参数8(当前系统模式):13(光纤模式)
"0C" -> 参数9(音乐音量值):12
"0F" -> 参数10(蓝牙HF通话音量值):15
"20" -> 参数11(麦克风音量值):32
"00" -> 参数12(当前音效配置文件索引):0
"A3 0F" -> 参数13-14(电源检测电压值):4003 mv
"56" -> 参数15(电池容量百分比):86%
"00" -> 参数16(是否正常充电):0(未充电)
"0F" -> 参数17(音乐低音值):15
"0F" -> 参数18(音乐中音值):15
"0F" -> 参数19(音乐高音值):15
"00" -> 参数20(麦克风低音值):0
"00" -> 参数21(麦克风中音值):0
"00" -> 参数22(麦克风高音值):0
"1F" -> 参数23(麦克风回声混响值):31
"1F" -> 参数24(麦克风回声值):31
"16" -> 结束码典型案例
公用函数实现
1. 串口通信基础函数,需要根据自己的平台去实现
#include <stdint.h>
#include <string.h>
// 串口发送函数(需要根据具体单片机平台实现)
void uart_send_bytes(uint8_t* data, uint16_t len);
// 串口接收函数(需要根据具体单片机平台实现)
uint16_t uart_receive_bytes(uint8_t* buffer, uint16_t max_len, uint32_t timeout_ms);2. 协议帧结构定义
// 协议帧头尾定义
#define FRAME_START_1 0xA5
#define FRAME_START_2 0x5A
#define FRAME_END 0x16
// 控制字定义
#define CMD_SYSTEM_STATUS 0xF8 // 系统状态参数
#define CMD_DEVICE_CONTROL 0xF0 // 设备控制参数
// 设备控制类型定义
#define CTRL_MUSIC_VOLUME 0x00 // 音乐音量控制
#define CTRL_MIC_VOLUME 0x01 // 麦克风音量控制
// 最大帧长度
#define MAX_FRAME_SIZE 256
typedef struct {
uint8_t start[2]; // 起始码 0xA5 0x5A
uint8_t control; // 控制字
uint8_t length; // 数据长度
uint8_t data[MAX_FRAME_SIZE]; // 数据域
uint8_t end; // 结束码 0x16
} protocol_frame_t;3. 发送协议帧函数
/**
* 发送协议帧
* @param control: 控制字
* @param data: 数据指针,可为NULL
* @param data_len: 数据长度
* @return: 0-成功,其他-失败
*/
int send_protocol_frame(uint8_t control, uint8_t* data, uint8_t data_len) {
uint8_t frame[MAX_FRAME_SIZE];
uint16_t frame_len = 0;
// 构建帧结构
frame[frame_len++] = FRAME_START_1; // 起始码1
frame[frame_len++] = FRAME_START_2; // 起始码2
frame[frame_len++] = control; // 控制字
frame[frame_len++] = data_len; // 数据长度
// 添加数据域
if(data != NULL && data_len > 0) {
memcpy(&frame[frame_len], data, data_len);
frame_len += data_len;
}
frame[frame_len++] = FRAME_END; // 结束码
// 发送帧数据
uart_send_bytes(frame, frame_len);
return 0;
}4. 接收协议帧函数
/**
* 接收协议帧
* @param response: 接收缓冲区
* @param timeout_ms: 超时时间(毫秒)
* @return: 接收到的数据长度,0表示失败
*/
int receive_protocol_frame(protocol_frame_t* response, uint32_t timeout_ms) {
uint8_t buffer[MAX_FRAME_SIZE];
uint16_t received_len;
// 接收数据
received_len = uart_receive_bytes(buffer, MAX_FRAME_SIZE, timeout_ms);
if(received_len < 5) { // 最小帧长度检查
return 0;
}
// 检查帧头
if(buffer[0] != FRAME_START_1 || buffer[1] != FRAME_START_2) {
return 0;
}
// 检查帧尾
if(buffer[received_len - 1] != FRAME_END) {
return 0;
}
// 解析帧结构
response->start[0] = buffer[0];
response->start[1] = buffer[1];
response->control = buffer[2];
response->length = buffer[3];
// 拷贝数据域
if(response->length > 0) {
memcpy(response->data, &buffer[4], response->length);
}
response->end = buffer[received_len - 1];
return received_len;
}案例1:读取并控制音量
使用到的控制字有下面两个:
0xF8: 系统状态参数
0xF0: 设备控制参数
读取系统状态函数
/**
* 读取系统状态,获取当前音量信息
* @param music_volume: 返回音乐音量值(0-32)
* @param mic_volume: 返回麦克风音量值(0-32)
* @return: 0-成功,其他-失败
*/
int read_system_status(uint8_t* music_volume, uint8_t* mic_volume) {
protocol_frame_t response;
// 发送系统状态查询命令
printf("发送系统状态查询命令...\n");
if(send_protocol_frame(CMD_SYSTEM_STATUS, NULL, 0) != 0) {
printf("发送命令失败\n");
return -1;
}
// 等待响应
if(receive_protocol_frame(&response, 1000) == 0) {
printf("接收响应超时\n");
return -2;
}
// 检查响应
if(response.control != CMD_SYSTEM_STATUS) {
printf("响应控制字错误: 0x%02X\n", response.control);
return -3;
}
if(response.length < 25) { // 系统状态参数至少25字节
printf("响应数据长度不足: %d\n", response.length);
return -4;
}
// 解析系统状态数据
// 参数9:音乐音量值(第9个字节,索引8)
*music_volume = response.data[8];
// 参数11:麦克风音量值(第11个字节,索引10)
*mic_volume = response.data[10];
printf("当前音乐音量: %d\n", *music_volume);
printf("当前麦克风音量: %d\n", *mic_volume);
return 0;
}设置音量函数
/**
* 设置音乐音量
* @param volume: 音量值(0-32)
* @return: 0-成功,其他-失败
*/
int set_music_volume(uint8_t volume) {
protocol_frame_t response;
uint8_t cmd_data[3];
// 检查音量范围
if(volume > 32) {
printf("音量值超出范围,最大值为32\n");
return -1;
}
// 构建控制数据
cmd_data[0] = CTRL_MUSIC_VOLUME; // 控制类型:音乐音量控制
cmd_data[1] = volume; // 音量值(小端存储低字节)
cmd_data[2] = 0x00; // 音量值(小端存储高字节)
printf("设置音乐音量为: %d\n", volume);
// 发送设置命令
if(send_protocol_frame(CMD_DEVICE_CONTROL, cmd_data, 3) != 0) {
printf("发送设置命令失败\n");
return -2;
}
// 等待响应
if(receive_protocol_frame(&response, 1000) == 0) {
printf("接收响应超时\n");
return -3;
}
// 检查响应
if(response.control != CMD_DEVICE_CONTROL) {
printf("响应控制字错误: 0x%02X\n", response.control);
return -4;
}
if(response.length != 2) {
printf("响应数据长度错误: %d\n", response.length);
return -5;
}
// 检查控制类型和状态码
if(response.data[0] != CTRL_MUSIC_VOLUME) {
printf("响应控制类型错误: 0x%02X\n", response.data[0]);
return -6;
}
if(response.data[1] != 0x01) { // 状态码1表示执行成功
printf("设置失败,状态码: 0x%02X\n", response.data[1]);
return -7;
}
printf("音乐音量设置成功\n");
return 0;
}
/**
* 设置麦克风音量
* @param volume: 音量值(0-32)
* @return: 0-成功,其他-失败
*/
int set_mic_volume(uint8_t volume) {
protocol_frame_t response;
uint8_t cmd_data[3];
// 检查音量范围
if(volume > 32) {
printf("音量值超出范围,最大值为32\n");
return -1;
}
// 构建控制数据
cmd_data[0] = CTRL_MIC_VOLUME; // 控制类型:麦克风音量控制
cmd_data[1] = volume; // 音量值(小端存储低字节)
cmd_data[2] = 0x00; // 音量值(小端存储高字节)
printf("设置麦克风音量为: %d\n", volume);
// 发送设置命令
if(send_protocol_frame(CMD_DEVICE_CONTROL, cmd_data, 3) != 0) {
printf("发送设置命令失败\n");
return -2;
}
// 等待响应
if(receive_protocol_frame(&response, 1000) == 0) {
printf("接收响应超时\n");
return -3;
}
// 验证响应(与音乐音量设置类似)
if(response.control != CMD_DEVICE_CONTROL ||
response.length != 2 ||
response.data[0] != CTRL_MIC_VOLUME ||
response.data[1] != 0x01) {
printf("麦克风音量设置失败\n");
return -4;
}
printf("麦克风音量设置成功\n");
return 0;
}案例2:音乐播放控制(上一曲、下一曲、播放/暂停)
使用到的控制字:
- 0xF0: 设备控制参数
- 控制类型: 0xFD(设备控制)
系统控制指令定义
// 系统控制指令枚举
#define SYS_CTRL_PLAY_PAUSE 0x7F2F // 播放/暂停
#define SYS_CTRL_PREV_TRACK 0x7F3A // 上一曲
#define SYS_CTRL_NEXT_TRACK 0x7F3B // 下一曲
#define SYS_CTRL_VOICE_CANCEL 0x7F6C // 人声消除启用/关闭
#define SYS_CTRL_MUTE_TOGGLE 0x7F6D // 静音/取消静音
#define SYS_CTRL_BT_DISCONNECT 0x7F78 // 断开蓝牙连接
#define SYS_CTRL_BATTERY_REPORT 0x7F7B // 电池电量播报
#define SYS_CTRL_TWS_PAIR 0x7F7E // TWS配对
// 设备控制类型
#define CTRL_DEVICE_CONTROL 0xFD // 设备控制通用设备控制函数
/**
* 发送设备控制指令
* @param control_cmd: 控制指令值(16位小端存储)
* @return: 0-成功,其他-失败
*/
int send_device_control(uint16_t control_cmd) {
protocol_frame_t response;
uint8_t cmd_data[3];
// 构建控制数据
cmd_data[0] = CTRL_DEVICE_CONTROL; // 控制类型:设备控制
cmd_data[1] = (uint8_t)(control_cmd & 0xFF); // 控制指令低字节
cmd_data[2] = (uint8_t)((control_cmd >> 8) & 0xFF); // 控制指令高字节
printf("发送设备控制指令: 0x%04X\n", control_cmd);
// 发送控制命令
if(send_protocol_frame(CMD_DEVICE_CONTROL, cmd_data, 3) != 0) {
printf("发送控制命令失败\n");
return -1;
}
// 等待响应
if(receive_protocol_frame(&response, 1000) == 0) {
printf("接收响应超时\n");
return -2;
}
// 检查响应
if(response.control != CMD_DEVICE_CONTROL) {
printf("响应控制字错误: 0x%02X\n", response.control);
return -3;
}
if(response.length != 2) {
printf("响应数据长度错误: %d\n", response.length);
return -4;
}
// 检查控制类型和状态码
if(response.data[0] != CTRL_DEVICE_CONTROL) {
printf("响应控制类型错误: 0x%02X\n", response.data[0]);
return -5;
}
if(response.data[1] != 0x01) { // 状态码1表示执行成功
printf("控制指令执行失败,状态码: 0x%02X\n", response.data[1]);
return -6;
}
printf("设备控制指令执行成功\n");
return 0;
}音乐播放控制函数
/**
* 播放上一曲
* @return: 0-成功,其他-失败
*/
int music_prev_track(void) {
printf("切换到上一曲...\n");
return send_device_control(SYS_CTRL_PREV_TRACK);
}
/**
* 播放下一曲
* @return: 0-成功,其他-失败
*/
int music_next_track(void) {
printf("切换到下一曲...\n");
return send_device_control(SYS_CTRL_NEXT_TRACK);
}
/**
* 播放/暂停切换
* @return: 0-成功,其他-失败
*/
int music_play_pause(void) {
printf("播放/暂停切换...\n");
return send_device_control(SYS_CTRL_PLAY_PAUSE);
}
/**
* 静音/取消静音切换
* @return: 0-成功,其他-失败
*/
int music_mute_toggle(void) {
printf("静音/取消静音切换...\n");
return send_device_control(SYS_CTRL_MUTE_TOGGLE);
}
/**
* 人声消除启用/关闭切换
* @return: 0-成功,其他-失败
*/
int music_voice_cancel_toggle(void) {
printf("人声消除启用/关闭切换...\n");
return send_device_control(SYS_CTRL_VOICE_CANCEL);
}枚举
系统模式枚举
| 值 | 说明 |
|---|---|
| 0 | 空闲模式 |
| 1 | 空闲模式 |
| 2 | 空闲模式 |
| 3 | AUX输入 |
| 4 | TF卡播放 |
| 5 | U盘播放 |
| 6 | 蓝牙音乐 |
| 7 | 蓝牙通话 |
| 8 | 保留 |
| 9 | HDMI播放 |
| 10 | USB声卡 |
| 11 | USB通话 |
| 12 | 收音机 |
| 13 | 光纤模式 |
| 14 | 同轴模式 |
| 15 | I2S输入 |
| 16 | 保留 |
| 17 | 保留 |
| 18 | 保留 |
| 19 | 保留 |
| 20 | TWS从机 |
系统控制指令枚举
| 值 | 功能描述 |
|---|---|
| 0x0A05 | 收音机扫描 |
| 0x7F1E | 软开关关机 |
| 0x7F2F | 播放/暂停 |
| 0x7F3A | 上一曲 |
| 0x7F3B | 下一曲 |
| 0x7F6C | 人声消除启用/关闭 |
| 0x7F6D | 静音/取消静音 |
| 0x7F78 | 断开蓝牙连接 |
| 0x7F7B | 电池电量播报 |
| 0x7F7E | TWS配对 |
部分功能仅指定固件可用
设备控制类型枚举
| 控制类型值 | 说明 |
|---|---|
| 0x00 | 音乐音量控制 |
| 0x01 | 麦克风音量控制 |
| 0x10 | 音效模式控制(索引从0开始) |
| 0x11 | APP模式控制,传入值见系统模式枚举 |
| 0x20 | 音乐低音 |
| 0x21 | 音乐中音 |
| 0x22 | 音乐高音 |
| 0x23 | 麦克风低音 |
| 0x24 | 麦克风中音 |
| 0x25 | 麦克风高音 |
| 0x26 | 麦克风混响 |
| 0x27 | 麦克风回声 |
| 0xFD | 设备控制,传入值见系统控制指令枚举 |
| 0xFE | 将设备所有配置恢复出厂设置 |
| 0xFF | 重启MCU |
附录
高低音调节增益表
| 索引 | 增益 (dB) |
|---|---|
| 0 | -7.5 |
| 1 | -7.0 |
| 2 | -6.5 |
| 3 | -6.0 |
| 4 | -5.5 |
| 5 | -5.0 |
| 6 | -4.5 |
| 7 | -4.0 |
| 8 | -3.5 |
| 9 | -3.0 |
| 10 | -2.5 |
| 11 | -2.0 |
| 12 | -1.5 |
| 13 | -1.0 |
| 14 | -0.5 |
| 15 | 0.0 |
| 16 | +0.5 |
| 17 | +1.0 |
| 18 | +1.5 |
| 19 | +2.0 |
| 20 | +2.5 |
| 21 | +3.0 |
| 22 | +3.5 |
| 23 | +4.0 |
| 24 | +4.5 |
| 25 | +5.0 |
| 26 | +5.5 |
| 27 | +6.0 |
| 28 | +6.5 |
| 29 | +7.0 |
| 30 | +7.5 |
| 31 | +8.0 |
Oldwu-Studio©2025 版权所有,违者必究