音箱入门到进阶指导文档(编写中)
📎 原始文档:https://www.kdocs.cn/l/ch1ltD1hA38s 音箱入门到进阶指导文档(编写中)
本文档为第一次接触杰理方案音箱开发的新手设计,聚焦“能上手、能操作”,省略复杂底层原理,只讲入门必备的核心知识和实操步骤,帮助新手快速搭建开发环境、完成第一个简单工程。
一、入门准备(必看)
新手入门前,需准备好硬件、软件和相关资料,避免操作中因缺少物品卡壳。
1.1 硬件准备(核心必备)
杰理音频系列开发板/demo板(如AC706N、JL701N型号):我们的开发板底板是共用的,不同的型号只需要替换中间的顶板即可。

公头USB线(用于开发板与电脑连接、供电)

开关电源(备用,部分开发板需外部供电)

强制升级工具

USB转TTL模块(如CH340、CP2102,用于串口调试,后续调试必用)
杜邦线(若干,用于连接开发板与USB转TTL模块)
1.2 软件准备(按顺序安装)
- JL Studio可视化开发平台(核心工具,需联系杰理获取安装包,无线上下载渠道)
- 杰理Windows版工具链(需联系杰理获取安装包,安装时请勿修改默认路径)
- IDE集成开发环境(二选一,新手推荐VS Code,操作更友好;不推荐Code::Blocks)
- 辅助工具:xshell(用于串口调试信息调试)、Beyond Compare(用于文件对比,后续补丁更新需用)
1.3 常用资料获取(新手必存)
- 杰理工具说明文档:欢迎使用杰理工具文档 — JL Project Documentation
- 硬件文档:通过点击打开——>杰理可视化配置工具——>帮助——>硬件资料 获得

- JLStudio 工具使用文档:通过点击打开——>杰理可视化配置工具——>帮助——>工具使用说明 获得

- 项目帮助文档:创建项目后可以获得项目帮助文档。 (需要取得对应的账号后新建项目后才能获取到该资料。账号联系对应代理获得)

- 补丁文档资料:音频类补丁汇总表.xlsx、对外特别发布开发注意点信息汇总.xlsx
二、核心基础(必懂)
在深入学习之前,有几个关键知识是必须理解的。这些问题通常也是在后续开发中可能会遭遇的。所以设置了一个特殊的章节,专门介绍注意事项,以帮助更好地掌握相关知识。
2.1 认识杰理芯片(快速识别型号)
杰理常用芯片丝印如AC706N、JL701N等芯片型号尾缀代表关键参数(重点看芯片型号、Flash大小和PSRAM):
- 特殊类型:内封PSRAM的芯片由尾缀决定 ① Production Batch
② Chip Model
③ Built-in DDR size
0 No Flash Memory
2 2Mbit flash
4 4Mbit flash
8 8Mbit flash
6 16Mbit flash
3 32Mbit flash
5 64Mbit flash
7 128Mbit flash
A 1Mx16 SDRAM
B 4Mx16 SDRAM
E 4Mx16bit DDR1
F 8Mx16bit DDR1
G 16Mx16bit DDR1
S 内封16Mbit PSRAM
T 内封64Mbit PSRAM
2.2 静态库基础(关键提醒)
必记:如果替换了静态库(比如修复漏洞、新增功能),必须重新编译工程,否则程序会继续使用旧代码,新修改无法生效。
我们在软件开发时,为了复用代码和提升开发效率,常把一些通用的代码封装成库。静态库(.a 文件)它在编译时会被完整地链接到可执行文件中。
在开发过程中如果遇到遇到替换静态库。例如修复了一些漏洞、添加了新功能等。需要重新编译才能,应用更新。若不重新编译,可执行文件依旧会使用旧的代码,这样新库的修改就无法更新到应用代码当中。
在实际的开发中,对静态库进行替换是时有发生的事情。比如:
当发现并修复了静态库中的某些漏洞,
或者为其增添了新的功能时,
若此时不重新编译应用程序,可执行文件仍然会沿用旧版本的代码逻辑。这就意味着,尽管静态库已经完成了更新,但应用程序却无法更新新库中的改进内容。
2.3 __weak语法
必记:不用深究代码,知道用法即可:
在 C 语言里,__weak 是一个编译器扩展特性,并非 C 标准的一部分,不过许多编译器(像 GCC 和 ARM GCC)都支持它。在我们的编译器是支持该用法,并弱符号常用于静态库里定义。具体SDK中表现为:函数在上层应用却没有搜索不到调用,但是实际是有执行。此时实际是静态库里面有调用,并在里面通过弱符号进行修饰。
__weak 主要用于定义弱符号,下面详细介绍它的用法。
基本概念
在 C 语言里,符号(函数或者变量)一般分为强符号和弱符号:
- 强符号:通常是函数的定义或者已初始化的全局变量。
- 弱符号:未初始化的全局变量或者用 __weak 修饰的函数定义。 编译器在链接时,对于相同名称的符号,会遵循如下规则:
- 当有多个强符号存在时,链接器会报错。
- 当存在一个强符号和多个弱符号时,链接器会选择强符号。
- 当只有弱符号存在时,链接器会选择其中一个弱符号。
__weak 的常见用法
1. 提供默认实现
在嵌入式开发中,常常会需要提供一些默认的中断处理函数。借助 __weak 可以定义默认的中断处理函数,用户可以在需要时提供自己的实现。
#include <stdio.h>
// 定义一个弱符号函数
__attribute__((weak)) void my_function() {
printf("This is the default implementation.\n");
}
// 主函数调用该函数
int main() {
my_function();
return 0;
}
在这个例子中,my_function 是一个弱符号函数。要是用户没有提供自己的 my_function 实现,那么就会调用默认的实现。要是用户提供了自己的实现,链接器会优先选择用户的实现。
2. 实现可替换的函数
在某些场景下,可能需要在不同的环境或者配置中使用不同的函数实现。通过 __weak 可以实现函数的可替换性。
include <stdio.h>
// 定义一个弱符号函数
__attribute__((weak)) int add(int a, int b) {
return a + b;
}
// 定义一个用户实现的函数
int add_custom(int a, int b) {
return a * b;
}
// 定义一个使用 add 函数的函数
int calculate(int a, int b) {
return add(a, b);
}
// 重定义 add 函数
#define add add_custom
int main() {
int result = calculate(2, 3);
printf("Result: %d\n", result);
return 0;
}
在这个例子中,add 是一个弱符号函数。通过宏定义 #define add add_custom,可以将 add 函数替换为 add_custom 函数。
3. 中断处理函数
在嵌入式系统里,中断处理函数通常会有默认的实现。借助 __weak 可以定义默认的中断处理函数,用户可以在需要时提供自己的实现。
// 定义一个弱符号的中断处理函数
__attribute__((weak)) void EXTI0_IRQHandler(void) {
// 默认的中断处理代码
}
// 用户可以提供自己的实现
void EXTI0_IRQHandler(void) {
// 用户自定义的中断处理代码
}
在这个例子中,EXTI0_IRQHandler 是一个弱符号的中断处理函数。要是用户没有提供自己的实现,就会调用默认的实现;要是用户提供了自己的实现,链接器会优先选择用户的实现。
2.4 printf 无法输出浮点数
为了缩减代码体积。目前大部分 SDK 中,并没有支持%f 格式化的输出。也就是并不会打印浮点数。为了处理这个问题,可有两个办法:
- 打印浮点数的内存。例如,float a; printf(“%x\n”, (uint32_t *)&a);
- 或者使用 put_float 函数单独打印浮点数。
三、实操步骤(核心环节)
按以下步骤操作,可快速完成第一个杰理音箱工程,每一步都搭配对应图片,对照操作即可。
3.1 搭建开发环境(已安装软件可跳过)
步骤1:安装JL Studio
- 打开杰理提供的JL Studio安装包,一路下一步,不修改默认安装路径;
- 安装完成后,打开软件,需扫码登录(杰理员工用钉钉,客户用微信)。
步骤2:安装工具链和IDE
- 下载最新杰理Windows版工具链,默认路径安装,安装后无需额外配置;
- 安装VS Code(官网下载即可),无需额外插件,用于代码编辑。
3.2 新建第一个工程(重点步骤)
步骤1:登录JL Studio并新建项目
登录JL Studio后,在软件界面找到新建项目的选项,按照提示填写项目相关信息,如项目名称、保存路径等,完成项目新建。
- 项目分组:默认 - 保存路径:选择电脑空文件夹(建议路径无中文,如G:客户支持) - 名称:自定义(如“first_speaker_project”) - 类型:音箱(开发音箱项目) - SDK:soundbox或le audio(一般选le_audio) 音箱的类型主要有以下几类(如果不清楚具体使用哪个可以咨询杰理技术支持):
le_audio: 这是一种常见的音箱类型,具有多种功能(le_audio、3in1),适用于不同的使用场景。目前比较常用的SDK。
sounbox: 适用于开发普通的音箱。
- 芯片:选择自己的开发板型号(如AC706N) - 版本:选择最新稳定版(如2.0.0) - 封装:对应开发板封装(如AC706N-demo) 注意:
- 新建工程需要先完成SDK下载的操作。
- 目前支持音箱SDK类型有(截止2026年3月5日) 如果没有看到对应芯片型号的SDK选项,说明账号没有该芯片对应的SDK权限,请联系杰理技术支持/助理或方案商申请开通对应权限
| SDK类型 | AC210N | AC706N | JL701N | JL703N | JL709N |
|---|---|---|---|---|---|
| le_audio | ✅ | ✅ | ✅ (推荐使用) | ✅ (推荐使用) | ✅ |
| soundbox | ❌ | ✅ | ✅ | ✅ | ❌ |
步骤2:打开工程
新建项目完成后,在JL Studio的项目列表中,找到新建的工程,点击“打开”,打开后的界面参考如下:
打开工程后,可查看工程的整体结构和相关配置
如果遇到以下情况:(图标中打开按钮是灰色,无法点击)说明该项目还不支持JL_STUDIO,需要点击工程目录下的的对应工程文件来,打开工程一般是.cbp后缀。后续开发需使用codeblock进行开发

3.3 编译与下载(关键一步)
此处小编建议:支持JL Studio的工程,使用JL Studio进行编译、下载等操作。能减少踩坑。
步骤1:编译工程
JL Studio编译
直接打开 SDK 目录下的 .jlproj 工程(.jlproj 是JL Studio的工程文件类型)
- 打开工程后,点击顶部“编译”,选择“编译”或“编译(rebuild)”:

- 编译:只编译改动的文件,速度快(日常开发用);
- 编译(rebuild):清空所有旧文件,重新编译所有文件,速度慢(替换静态库、修改链接文件后必用)。
- 等待编译完成,底部“编译输出”显示无错误,即为编译成功。

Code::Blocks编译 (适合没有JL Studio的工程使用,有JL Studio一般推荐使用JL Studio)
直接打开 SDK 目录下的 cbp 工程(cbp是Code::Blocks的工程文件类型)
编译
编译成功页面:
新增源文件/库文件时,需要手动导入工程,否则不会编译进去。
①新增/移除文件(.h/.c):

②新增/移除库文件(.a):
鼠标选中工程,然后右键菜单,再点击编译选项。

VS Code编译(建议熟悉makefile的工程师使用)
使用 VS Code 打开 SDK 目录,注意必须在SDK文件夹下打开VS Code,否则编译出错。

编译成功页面:
命令/脚本编译:这种编译方式同样适合熟悉makefile的工程师,具有一定的灵活性和高效性。
命令如下:
清除编译缓存:make clean
编译程序:make -j

- 把utils文件夹放入系统环境变量并重启电脑
- 这边先把utils复制到c盘然后把其对于的路径放入系统环境为例



- 这边先把utils复制到c盘然后把其对于的路径放入系统环境为例
- 编译代码

Makefile(VScode)
新增/移除文件:新增源文件/库文件时,需要手动修改makefile,否则不会编译进去。
添加文件




添加目录
#需要添加的文件存放文件夹 相对于makefile所在路径的相对路径
APP_PATH = user/
#添加头文件实在的文件夹
INCLUDES += \
-I$(APP_PATH)/
#添加APP_PATH下的五层目录下的所有c文件
c_SRC_FILES := $(wildcard $(APP_PATH)/*.c) \
$(wildcard $(APP_PATH)/*/*.c) \
$(wildcard $(APP_PATH)/*/*/*.c) \
$(wildcard $(APP_PATH)/*/*/*/*.c) \
$(wildcard $(APP_PATH)/*/*/*/*/*.c)
$(c_SRC_FILES)
#添加自己的库文件
LFLAGS += \

步骤2:开发板与电脑连接
- 用通过强制升级工具 4.0 连接样机进行升级,公头USB线,一端插入开发板,另一端插入电脑;(此处需要观察升级工具的拨档,如果是不拨,需要按一下按键->绿灯灭进入升级)
下载工具说明可查看https://doc.zh-jieli.com/Tools/zh-cn/dev_tools/forced_upgrade/upgrade_and_download.html 。 - 检查连接是否成功:打开电脑“设备管理器”→ 展开“磁盘驱动器”,若出现对应设备盘符,说明连接正常(无盘符则重新插拔USB线)。
在确认开发板与电脑成功连接后,就可以进行后续的下载操作了,
一、检查连接是否出盘(以 Windows 10 为例)
步骤 1:打开设备管理器
- 快捷键方式:按下键盘上的 Win + X 组合键,在弹出的菜单中选择 设备管理器。
- 若使用鼠标,右键点击桌面左下角的 开始按钮,同样选择 设备管理器。
- 运行命令方式:按下 Win + R 打开运行窗口,输入 devmgmt.msc 并回车。
步骤 2:查看磁盘驱动器
- 在设备管理器窗口中,找到并展开 磁盘驱动器 选项。此处会列出所有已识别的存储设备,包括硬盘、SSD、USB 驱动器等。查找有没有对应我们连接样机的设备如

步骤3:下载程序
- 编译成功后,点击JL Studio顶部“编译”→ “下载”;
- 等待下载完成,提示“下载成功”后,此时第一个工程已成功下载到开发板。
下载完成后,可检查开发板的运行状态,确认程序是否正常工作。
3.4 基础调试(入门级)
下载完成后,用USB转TTL模块进行简单调试,查看程序运行状态:
步骤1:硬件连接
用杜邦线将开发板与USB转TTL模块交叉连接(关键!不要接反):
- 开发板 RX → USB转TTL TX
- 开发板 TX → USB转TTL RX
- 开发板 GND → USB转TTL GND
步骤2:使能调试信息(默认打开)

- 在VS Code中打开工程,找到文件:apps/xxx/include/app_config.h;
- 确保系统打印总开关开启(新手无需修改,默认开启):查看该文件中是否有类似
\#define CONFIG_DEBUG_ENABLE 1的语句,若为1则表示开关开启。
步骤3:查看调试信息
- 将USB转TTL模块插入电脑,打开串口工具(如xshell);
- 配置串口参数(波特率2000000,与工程中“调试串口”波特率一致);
- 重启开发板,串口工具中会显示程序运行信息,说明调试正常。
完成上述基础调试后,若遇到调试信息异常,可参考本指南“入门常见问题”部分进行排查修复。
- 若仍无法解决问题,可联系技术支持获取进一步帮助。
- 在调试过程中,要仔细记录出现的问题和对应的现象,以便更准确地定位和解决。对记录的内容进行整理和分析,能更高效地与技术支持沟通问题。
为了提高问题信息反馈效率,请按照以下模板编辑文字发出来,谢谢
公司/代理商名称:【必填】
芯片型号:【必填】
项目名:
产品形态:
SDK版本:【软件问题必填:如:JL703N_le_audio_sdk_release_2.0.0_patch_01】
工程负责人:【必填】
联系电话:【必填】
是否批量:【生产问题请标明】
终端客户:
问题描述:(问题描述、测试方法、复现概率、硬件分析):【必填】
做过哪些分析:(按步骤提供:公版SDK验证、软件和硬件排查、log debug、查找过哪块资料参考)【必填】
【公版SDK能否复现:能复现提供公版的配置-公版SDK能复现问题优先处理】
【是否跟硬件有关,开发板/DEMO板能否复现 】
【软件问题请提供完整的打印,并指出出现问题时的打印在哪里】
【异常死机问题请提供完整的log以及对应的反汇编文件lst】
四、入门常见问题(新手必看)
- 问题1:电脑识别不到开发板? → 重新插拔USB线,检查USB线是否完好,或开发板供电是否正常。
- 问题2:串口无调试信息? → 检查杜邦线连接是否交叉,波特率是否与工程配置一致,调试开关是否开启。
五、学习建议
如果你能成功看到打印信息,说明你已成功入门,太棒了,那么你离成功开发一款音箱已经不远了。
可以按照以下建议进一步提升自己:这些建议将帮助你逐步深入了解和掌握杰理方案音箱开发的更多技能和知识。
- 合并补丁&特殊补丁 入门后,可通过JL Studio“帮助→视频”,学习“合并补丁”“工程配置”等进阶操作;
相关帮助文档资料
- 帮助文档:通过点击打开——>杰理可视化配置工具——>帮助——>工具使用说明 获得
打开链接有以下资料
- 帮助视频:通过点击打开——>杰理可视化配置工具——>帮助——>视频 获得
点击视频后,会有以下录制好的视频列表
新建工程
观看通过点击打开——>杰理可视化配置工具——>帮助——>视频:观看 新建项目部分
更新补丁
开始
↓
是否熟悉Git?
├─ 是 → 按官方SDK合并冲突方式合并 → 完成
↓
否 → 前期准备
├─ 准备:项目工程 / 已打补丁SDK / 原有SDK
├─ 安装:Beyond Compare
↓
获取已打补丁SDK
├─ 新建空白SDK(不修改)
├─ 点击最新版本
├─ 选择SDK → 合并补丁(多补丁按顺序)
└─ 得到完整补丁SDK
↓
Beyond Compare 对比升级
├─ 打开文件夹对比
├─ 对比新旧SDK
├─ 音频/配置文件:直接用补丁版 + 修改自定义参数
└─ 其他文件:按需合并
↓
完成
- 如果你熟悉使用git,可以观看我们的SDK 合并补丁冲突的方式进行合并
- 如果你不会使用git。 可参考以下方式:
前期准备:
1. 对应项目的工程, 已经打好补丁的SDK、当前工程的SDK 已经打好补丁的SDK可以参考一下方式获取- 新建对应工程的SDK(注意只创建就可以,内容不要做任何的修改)


- 点击最新版本
找到你想要升级的SDK(如下图:想把le_audio-AC706N-2.0.0-AC706N-demo-patch_07 SDK打最新的补丁,就找到对应的版本bugfix 信息->点击合并(如果有多个补丁需要按顺序点击合并)
点击合并后->会显示补丁合并完成。
如果还不是最新的版本,可以重复以上步骤:点击“最新版本”-“合并”
你就能得到一个打好补丁的SDK
- beyond compare 对比升级
- 打开beyond compare 文件夹比较功能

- 填入需要对比的工程进行差异对比。音频流/配置文件的如果出现差异,建议直接使用打好补丁的文件,然后修改自己的自定义参数即可,不要使用原有旧配置文件(避免功能出现不可预知的异常)。

- 新建对应工程的SDK(注意只创建就可以,内容不要做任何的修改)
特殊补丁:
特殊补丁我们会通过一个密钥提供:例如:htgqtlk8hkru
新建工程输入密钥,可以获取已经包含对应的补丁的SDK
如果是在原来的工程上更新补丁,可以参考上面更新补丁部分。
2. 调试方法 嵌入式软件调试是结合硬件环境、软件逻辑和调试工具的系统性工作,由于嵌入式系统通常资源受限且与硬件强耦合,调试步骤需兼顾 “软件逻辑验证” 和 “软硬件交互排查”。
软件常用的方法:
串口调试
在嵌入式平台开发中, 串口调试 以其依赖硬件结构简单和稳定可靠的优点,被誉为硬件状态和软件运行结果的 听诊器 ,成为调试软件的重要手段。SDK中串口可以输出的信息有:
常规调试信息
SDK发布时会附带一些基本的调试信息,比如输出上电流程的各个模块的基本信息和状态。
调试信息使能配置
- 打开lib库总开关 修改文件位置: apps/xxx/include/app_config.h
#ifndef APP_CONFIG_H
#define APP_CONFIG_H
/*
* 系统打印总开关
*/
#ifdef CONFIG_RELEASE_ENABLE
#define LIB_DEBUG 1
#else
#define LIB_DEBUG 1
#endif
#define CONFIG_DEBUG_LIB(x) (x & LIB_DEBUG)
#define CONFIG_DEBUG_ENABLE
软件调试相关方法(请点击跳转)
2. 遇到死机问题需要打开异常中断开关(断言) lib_system_config.c里面的config_asser,异常中断打印信息分析,请参考章节2.7.3
注意:打开异常中断后,当异常发生时,会打印异常中断信息,且系统不会自动重启。
因此在生产时,务必关闭异常中断,使设备发生异常时系统能自动重启,不至于变砖。
关闭打印和关闭异常中断是两个开关,没关异常中断,只是关打印,系统异常死机一样不会自动重启。
3. 希望得到更多的调试打印可以在log.h里面,通过更改__LOG_LEVEL设置对应的打印等级
4. 常用日志接口,给客户实际调试过程中需要打印对应资源内容时使用: 以下都属于库打印,需要打开库打印宏
内存打印:mem_printf
时钟打印:clock_dump
任务状态:task_info
不掉电ram实时打:mem_stats
掉电ram实时打印:mem_vlt_stats
系统堆栈打印开关:const int config_system_info = 1;
3. 遇到问题,优先查看对应芯片系列的“问题处理文档”或联系技术支持获取支持。
4. 后续关于更多模式功能的介绍可以看本指南后续章节。
SDK介绍以及常规功能开发
这部分可以看:项目帮助文档
4.3 蓝牙模式
4.3.1 EDR经典蓝牙基础知识介绍
EDR(Enhanced Data Rate,增强型数据速率)是蓝牙2.0及以上版本对经典蓝牙(BR,Basic Rate)的扩展。EDR通过更高效的调制方式(π/4-DQPSK、8DPSK)将最大物理层速率从BR的1Mbps提升到2Mbps、3Mbps。最高可达3Mbps(理论值),实际应用中常用2Mbps。
4.3.2 BLE基础知识介绍
BLE(Bluetooth Low Energy),也称为Bluetooth Smart,是蓝牙4.0规范中引入的一种低功耗蓝牙技术。与传统经典蓝牙(BR/EDR)相比,BLE具有以下特点:
- 低功耗:功耗仅为经典蓝牙的1/10到1/100
- 短距离:通信距离约10-100米
- 简单连接:快速配对,连接建立时间短
- 数据量小:适合传输少量数据
- 成本低:硬件成本较低
4.3.3 Auracast基础知识介绍
Auracast 是一种蓝牙广播音频技术,理论上允许无限数量的设备共享音频流。它是低功耗蓝牙音频技术的一部分。与传统蓝牙音频对比如下:
| 特性 | 传统蓝牙音频 | Auracast |
|---|---|---|
| 连接方式 | 点对点连接 | 广播模式 |
| 设备数量 | 1对1或1对2 | 1对多(理论上无限) |
| 延迟 | 较高 | 更低 |
| 功耗 | 较高 | 更低 |
| 音质 | 取决于编解码器 | LC3,质量更好 |
| 应用场景 | 个人音频 | 公共场所、多设备 |
4.3.4 TWS 基础知识介绍
TWS(True Wireless Stereo)即“真无线立体声”,是一种无线音频传输技术,最常见于蓝牙耳机和音箱。TWS技术允许左右两个耳机单元完全无线地与音源设备(如手机)和彼此通信,实现真正的立体声分离和无线体验。
TWS采用主从架构:
- 主机(Master):与手机等音源设备建立蓝牙连接,负责音频数据的接收和分发。
- 从机(Slave):与主机建立TWS专用连接,从主机接收音频数据。
- 主从切换:部分TWS支持主从自动切换,提高使用灵活性和稳定性。
4.3.5 TWS 连接机制
TWS连接主要流程包括:
- 配对:左右耳机首次使用时通过TWS协议进行配对,确定主从角色,并保存配对信息。
- 回连:下次开机时,主机会自动发起对耳连接,从机等待连接,实现快速自动回连。
- 链路建立:主机与从机之间建立TWS专用链路,主机还与手机等音源设备建立蓝牙连接。
- 数据同步:主机将音频、音量、电量、按键等信息通过TWS链路同步给从机,保证两个设备协同工作。
- 主从切换:部分TWS支持主从自动切换,提升连接的稳定性和灵活性。
- 断开与重连:连接断开后,会自动尝试重连,保证使用体验。 流程图参考如下:

4.3.5.1 TWS 配对接口
1. 发起/等待配对接口
tws_api_auto_pair(int timeout_ms)
自动发起TWS配对,timeout_ms为超时时间(毫秒)。
用法:在使用开机自动配对时会调用此函数,通过预设的配对码进行配对,配对码设置一般在初始化中完成bt_tws_poweron(),timeout_ms为0表示不超时。
tws_api_wait_pair_by_code(u16 code, const char *name, int timeout_ms)
通过配对码等待对耳配对,code为配对码,name为设备名,timeout_ms为超时时间。
用法:配对码和设备名设置为本机的,本机会广播信息等待被配对,只有配对码相同的设备才能配对成功,这个接口参数code暂无作用,name不为空会打开手机链路的可发现可连接,timeout_ms为0表示不超时。
tws_api_search_sibling_by_code()
主动搜索同配对码的对耳设备,发起配对。
用法:上面的tws_api_wait_pair_by_code为被动等待方,tws_api_search_sibling_by_code为主动搜索匹配的设备。
tws_api_wait_pair_when_phone_connect(int timeout_ms)
手机已连接时,等待对耳配对。
用法:当设备连接上手机时,调用这个接口去连接对耳,timeout_ms为0表示不超时。
tws_api_cancle_wait_pair()
取消等待配对状态。
用法:在配对超时的时候会调用这个接口去取消可发现可连接。
2. 配对信息管理接口
tws_api_set_pair_code(u16 pair_code)
设置TWS配对码。
用法:在tws开机初始化时,会读取之前已存储的配对码,然后设置为本机配对码。
tws_api_remove_pairs()
解除TWS配对关系。
用法:发送解除配对命令给对方,成功后会收到TWS_EVENT_REMOVE_PAIRS事件。
bt_tws_detach_and_remove_pairs()
断开并清除配对信息。
用法:如果使用的是公共地址,连接手机后无法取消配对,如果不使用公共地址,只能使用按键配对方式,但是连接手机后可以取消配对。
3. 配对状态查询接口
tws_api_get_tws_state()
获取TWS当前状态(如已配对、未配对、已连接等)。
用法:通过返回值看当前状态
图中1005为设备状态,可以对应tws_api.h中的tws状态,例如1005为TWS_STA_TWS_PAIRED | TWS_STA_SIBLING_DISCONNECTED | TWS_STA_PHONE_DISCONNECTED,即在配对状态,tws未连接,手机未连接
tws_api_is_connect()
查询TWS是否已连接。
用法:已连接会返回1,未连接返回0。
4. 配对流程常用辅助接口
tws_api_set_sibling_addr(u8 *addr)
设置对耳设备地址。
tws_api_get_sibling_addr(u8 *addr)
获取对耳设备地址。
tws_get_sibling_addr(u8 *addr, int *result)
获取存在vm区里面的对耳地址。
4.3.5.2 TWS 回连接口
1. 主动发起回连
tws_api_create_connection(int timeout)
主机调用此接口,主动向已配对的对耳设备发起TWS连接。
timeout:回连超时时间(单位ms,0表示不超时)。
用法:搜索并连接已经配对过的tws,返回值为0表示函数调用成功。
2. 等待对方回连
tws_api_wait_connection()
从机调用此接口,进入可被对耳设备连接的等待状态。
用法:相当于打开了可发现可连接,可以被手机和已配对过的tws连接。
3. 取消回连相关操作
tws_api_cancle_create_connection()
取消正在进行的TWS回连操作。
4. 辅助接口
tws_api_set_quick_connect_addr(u8 *addr)
设置快速回连的对耳地址。
4.3.5.3 TWS 其他相关接口
1. 主从角色相关
tws_api_get_role()
获取当前TWS设备的主从角色(主机/从机)。
用法:返回值0为主机,1为从机。
tws_api_role_switch()
手动发起主从角色切换。
用法:调用这个接口会切换主从角色,在连接手机时也可以切换,如果是主机,切换时会输出以下打印,等于1说明已经切换到从机了。与手机连接的情况,TWS之间可以根据程序底层策略自动选择哪边做主机哪边做从机,该功能只在使用公共地址的情况使用。
tws_api_auto_role_switch_enable()
使能自动主从切换。
tws_api_auto_role_switch_disable()
禁用自动主从切换。
2. 断开与解除配对
tws_api_detach(enum tws_detach_reason reason, int timeout)
断开TWS连接,reason为断开原因,任何情况返回值都为0。
用法:断开原因在tws_event.h中,通过 enum tws_detach_reason 指定,便于上层和底层做不同处理,具体内容和说明如下:
enum tws_detach_reason {
TWS_DETACH_BY_LOCAL = 0x01, // 本地主动断开
TWS_DETACH_BY_REMOTE = 0x02, // 对方断开
TWS_DETACH_BY_POWEROFF = 0x04, // 关机断开
TWS_DETACH_BY_SUPER_TIMEOUT = 0x08, // 超时断开
TWS_DETACH_BY_REMOVE_PAIRS = 0x10, // 解除配对断开
TWS_DETACH_BY_TESTBOX_CON = 0x20, // 测试盒断开
TWS_DETACH_SUSS = 0x40, // 断开成功
TWS_DETACH_BY_FORCE = 0x80, // 强制断开
TWS_DETACH_BY_USER = 0x100, // 用户操作断开
};
tws_api_remove_pairs()
解除TWS配对关系。
用法:发送解除配对命令给对方,成功后会收到TWS_EVENT_REMOVE_PAIRS事件。
3. 地址管理
tws_api_get_local_addr(u8 *addr)
获取本地TWS地址。
用法:在未连接对耳时,获取到的addr为本地地址。如果开启了使用公共地址,TWS配对过程根据远端和本地地址进行策略计算得到公共地址,两台设备使用该接口时都会显示公共地址;如果开启了不使用公共地址,使用该接口时两台设备都会显示按键发起配对的本地地址。
4. 数据/事件同步
TWS数据互发的原理和流程可参考:
TWS实现数据互发原理.otl
tws_api_send_data_to_sibling(void *data, u16 len, u32 func_id)
发送自定义数据到对耳。
tws_api_sync_call_by_uuid(int uuid, int priv, int delay_ms)
通过UUID同步调用对耳的函数(如LED、音量等同步)。
5. 声道与音频相关
tws_api_set_local_channel(char channel)
设置本地声道('L'左,'R'右,'U'双声道)。
用法:可以设置本地声道,但是如果不用syscfg_write存起来,下次开机时还是会读取之前记录的。
tws_api_get_local_channel()
获取本地声道。
bt_tws_get_local_channel()
获取存储的声道信息,可通过syscfg_read(CFG_TWS_CHANNEL, &channel, 1)读取,channel为读取到的数据,可用%c去打印。
6. 低功耗与特殊模式
tws_api_power_saving_mode_enable()
进入TWS省电模式。
tws_api_power_saving_mode_disable()
退出TWS省电模式。
7. 其他辅助接口
tws_api_get_mclkn()
获取TWS主时钟。
4.3.6 BLE开发相关接口
4.3.7 SPP开发相关接口
4.3.8 Auracast开发相关接口
4.4 音乐模式(播TF、U盘音频)
4.4.1 文件系统基础知识介绍
文件系统(File System)是操作系统或嵌入式固件用于管理和组织存储设备(如SD卡、U盘、闪存等)上数据的一套机制。它负责如何在存储介质上存储、命名、检索和管理文件。一般文件系统的操作主要有
- 格式化(Format):初始化存储介质,建立文件系统结构。
- 挂载/卸载(Mount/Unmount):使文件系统可用或断开。
- 打开/关闭文件(Open/Close):准备对文件进行操作。
- 读写文件(Read/Write):数据的输入输出。
- 创建/删除文件和目录(Create/Delete)。
- 查找/遍历(Find/List):获取目录下的文件列表。
4.4.2 文件解码接口
music_player_create(void) / music_player_init(struct file_player *player, void *file, struct audio_dec_breakpoint *dbp)
初始化和创建接口。
music_player_decode_start(struct music_player *player_hd, FILE *file, struct audio_dec_breakpoint *dbp)
解码器启动接口。
file_decoder_open(struct file_decoder *dec, ...)
file_decoder_close(struct file_decoder *dec)
file_decoder_set_output_channel(struct file_decoder *dec)
file_decoder_set_event_handler(struct file_decoder *dec, ...)
file_decoder_is_stop/play/pause(struct file_decoder *dec)
解码器操作接口。
4.4.3 音乐模式其他常用接口
1. 播放控制相关
music_file_play(FILE *file, struct audio_dec_breakpoint *dbp)
播放指定文件,支持断点。
music_file_play_callback(FILE *file, void *priv, music_player_cb_t callback, struct audio_dec_breakpoint *dbp)
播放文件并注册回调。
music_file_player_pp(struct file_player *music_player)
播放/暂停切换。
music_file_player_ff(u16 step_s, struct file_player *music_player)
快进。
music_file_player_fr(u16 step_s, struct file_player *music_player)
快退。
music_file_player_stop()
停止所有音乐播放。
2. 音量与音效调节
music_file_pitch_up(struct file_player *music_player)
升高音调。
music_file_pitch_down(struct file_player *music_player)
降低音调。
music_file_set_pitch(struct file_player *music_player, enum _pitch_level pitch_mode)
设置音调模式。
music_file_speed_up(struct file_player *music_player)
加快播放速度。
music_file_speed_down(struct file_player *music_player)
减慢播放速度。
music_file_set_speed(struct file_player *music_player, enum _speed_level speed_mode)
设置播放速度。
3. 断点与播放状态
music_file_get_breakpoints(struct audio_dec_breakpoint *bp, struct file_player *music_player)
获取当前播放断点。
music_file_get_player_status(struct file_player *music_player)
获取当前播放器状态(播放、暂停、停止)。
music_file_get_cur_time(struct file_player *music_player)
获取当前播放时间。
music_file_get_total_time(struct file_player *music_player)
获取文件总时长。
4. 设备管理
music_task_dev_online_start(char *in_logo)
设备上线后自动开始播放。
music_app_get_dev_cur(void)
获取当前播放设备标识。
dev_manager_set_active_by_logo(logo)
设置当前活动设备。
5. 其它辅助接口
music_player_runing()
查询是否有音乐正在播放。
get_music_file_player(void)
获取当前音乐播放器指针。
music_player_stop(struct music_player *player_hd, int fade)
停止指定播放器。
4.5 录音模式
4.5.1 录音功能基础知识介绍
录音,即音频采集,是将外部声音(如麦克风输入)通过模数转换(ADC)采集为数字信号,并保存为音频文件的过程。
主要流程包括:
声音信号 → 麦克风 → 模拟信号 → ADC采样 → 数字音频流 → 编码/压缩 → 存储为文件
4.5.2 录音模式其他常用接口
4.6 混响模式
4.6.1 混响功能基础知识介绍
4.6.2 录音模式其他常用接口
4.7 FM模式
4.7.1 FM功能基础知识介绍
FM功能(Frequency Modulation,频率调制)是指通过改变载波信号的频率来传输信息的一种调制技术。它是无线电广播、通信系统中常用的调制方式之一。
通常FM接收功能,分内置FM和外置FM两种,内置FM使用杰理芯片内部的射频模块进行数据的解调,最后将数据发送到DAC模块,从而输出声音,外置FM使用类似于RDA5807等芯片,经过该芯片解调后输出到DAC,杰理方案通过LINEIN/AUX的模块采集输出到DAC。
4.7.2 FM模式其他常用接口
搜台控制接口
void fm_scan_all(void)
功能:全自动搜台。
用法:调用时会停止当前搜台,然后重新从头开始搜台。
void fm_scan_up(void)
功能:向上搜台。
用法:从108到87.5,从当前频点开始搜台,搜到台后停止搜台,并播放当前台。
void fm_scan_down(void)
功能:向下搜台。
用法:从87.5到108,从当前频点开始搜台,搜到台后停止搜台,并播放当前台。
void fm_scan_stop(void)
功能:停止搜台。
void fm_clear_all_station(void)
功能:清除所有电台。
用法:调用后会清掉已经搜索到的电台。
void fm_delete_freq(void)
功能:删除当前频率。
用法:调用后会将当前电台从节点删除,调用切电台的接口将不会扫到。
频率控制接口
void fm_prev_freq(void)
功能:上一个频率。
用法:调用后会减少0.1真实频点。
void fm_next_freq(void)
功能:下一个频率。
用法:调用后会增加0.1真实频点。
void fm_prev_station(void)
功能:上一个电台。
用法:调用这个接口需要先进行电台搜索,需要搜索到有台才有效,调用后切到上一个电台。
void fm_next_station(void)
功能:下一个电台。
用法:调用这个接口需要先进行电台搜索,需要搜索到有台才有效,调用后切到下一个电台。
iic通信
在使用外挂收音时,需要使用IIC与样机通信。比如在使用RDA5807时,在RDA5807.c中就会有iic的读写函数,通过iic读写进行通信,比如在收音芯片初始化或者设置频点时都需进行读写操作通信,具体内容可去代码中查看。
vm存储接口
void fm_read_info(FM_INFO *info)
功能:读取FM信息。
用法:定义一个空结构体接收,会通过VM_FM_INFO存储号读取。
结构体定义参考:
#pragma pack(1)//不平台对齐编译
typedef struct _FM_INFO_ {
u16 mask; // 校验码,用于验证数据完整性
u16 curFreq; // 当前虚拟频率 (x-874)
u16 curChanel; // 当前台号 (1~206)
u16 total_chanel; // 总台数
u8 dat[MEM_FM_LEN]; // 电台位图数组
} FM_INFO;
#pragma pack()
void fm_save_info(FM_INFO *info)
功能:保存FM信息。
用法:将结构体内容存入VM区。
void fm_last_ch_save(u16 channel)
功能:保存最后频道。
用法:参数填入台号,下次进入收音模式时会进入这个台号播。
void fm_last_freq_save(u16 freq)
功能:保存最后频率。
用法:参数填入真实频率,下次进入收音模式会位于这个频率。
void fm_vm_check(void)
功能:检查VM数据。
用法:校验mask,不符合mask进行清0。
4.8 PC模式
4.8.1 PC功能基础知识介绍
PC功能是指设备作为USB音频设备连接到PC主机,实现音频输入输出和媒体控制的功能。这是一种常见的音频设备应用模式,广泛应用于耳机、音箱、麦克风等音频设备中。
主要流程包括:
PC主机 ←→ USB接口 ←→ 音频编解码器 ←→ 扬声器/麦克风
- 音频输出: PC音频流 → USB传输 → 设备扬声器
- 音频输入: 设备麦克风 → USB传输 → PC录音 代码框架参考:

4.8.2 PC模式其他常用接口
1.USB检测接口
u32 usb_otg_online(const usb_dev usb_id)
功能:USB连接状态检测。
参数:填0即可获取USB0当前模式。
用法:返回值为SLAVE_MODE, SLAVE_MODE_WAIT_CONFIRMATION, DISCONN_MODE等,如下
enum {
IDLE_MODE = 0, ///<空闲模式
DISCONN_MODE = 1, ///<断连模式
HOST_MODE = 2, ///<主机模式
PRE_SLAVE_MODE, ///<成为从机模式前的一个中间模式
SLAVE_MODE_WAIT_CONFIRMATION, ///<从机模式还需等待再次确认
SLAVE_MODE, ///<从机模式
CHARGE_MODE, ///<充电模式
OTG_USER_MODE, ///<用户模式,暂时未具体定义
};
static int app_pc_check(void)
功能:PC模式检查。
用法:返回值: true-可以进入PC模式, false-不能进入PC模式。
2.音频处理接口
int pc_spk_player_open(void)
功能:打开PC扬声器播放器。
用法:返回值: 0-成功, 其他-失败。
void pc_spk_player_close(void)
功能:关闭PC扬声器播放器。
用法:在pc音频播放时直接调用即可。
bool pc_spk_player_runing(void)
功能:PC模式检查。
用法:返回值: true-正在播放, false-未播放。
3.HID控制接口
void hid_key_handler(u8 report_id, u8 key_code)
功能:发送HID控制命令到PC。
参数:第一个参数为报告ID,填0表示使用默认的媒体控制报告,第二个参数为按键代码。
用法:调用可控制PC状态,按键代码定义如下:
#define USB_AUDIO_PP 0x01 // 播放/暂停
#define USB_AUDIO_NEXT 0x02 // 下一曲
#define USB_AUDIO_PREV 0x04 // 上一曲
#define USB_AUDIO_VOL_UP 0x08 // 音量增加
#define USB_AUDIO_VOL_DOWN 0x10 // 音量减少
#define USB_AUDIO_MUTE 0x20 // 静音
4.修改USB描述符方法
修改user_setup.c中的user_stirng数组,中文修改需要使用unicode编码:
第1位数据:描述符长度。这里填整个描述符数组的长度;
第2位数据:字符串述符,类型为0x03
第3~n位数据:数据
static const u8 user_stirng[] = {
24,
0x03,
'U', 0x00,
'S', 0x00,
'B', 0x00,
'A', 0x00,
'u', 0x00,
'd', 0x00,
'i', 0x00,
'o', 0x00,
'1', 0x00,
'.', 0x00,
'0', 0x00,
};
需要连接后在电脑的设备管理器中卸载设备,然后修改数组,重新下载程序,再进入从机模式就能修改成功。
4.9 RTC时钟模式
4.9.1 RTC时钟功能基础知识介绍
RTC (Real-Time Clock) 实时时钟,是一种能够持续记录时间的电子设备,即使在系统断电后也能保持时间信息。
RTC特点:
- 持续运行: 即使设备关机也能保持时间
- 高精度: 提供准确的时间基准
- 低功耗: 使用独立的电源或电池供电
- 多功能: 支持时间显示、闹钟、定时等功能
4.9.2 RTC时钟模式其他常用接口
时钟源类型选择
在app_config.h中的宏RTC_CLK_RES_SEL可以选择rtc时钟源。
enum RTC_CLK {
CLK_SEL_32K = 1, // 32K时钟 (32.768KHz) - 最常用
CLK_SEL_BTOSC_DIV1 = 2, // BTOSC/1 (24MHz)
CLK_SEL_12M = 2, // 12MHz时钟
CLK_SEL_BTOSC_DIV2 = 3, // BTOSC/2 (12MHz)
CLK_SEL_24M = 3, // 24MHz时钟
CLK_SEL_LRC = 4, // LRC时钟 (低频RC振荡器)
};
以701为例,需要选择外部时钟BTOSC/2,即CLK_SEL_BTOSC_DIV2,选择其他的会时间不准。
2. 时间读取和设置
dev_ioctl(dev_handle, IOCTL_GET_SYS_TIME, (u32)¤t_time)
功能:读取当前系统时间。
用法:具体可查看代码里用法。
rtc_update_time_api(&set_time)
功能:设置系统时间。
用法:在手动设置完时间后,需要调用这个接口去更新时间。
3. 闹钟管理
u8 alarm_add(PT_ALARM p, u8 index)
功能:添加闹钟。
用法:第一个参数可以自定义,第二个参数表示闹钟索引号(0~4),最多设置五个。
第一个参数结构体参考如下:
T_ALARM alarm = {0};
alarm.index = 0; // 闹钟索引0
alarm.sw = 1; // 使能闹钟
alarm.mode = E_ALARM_MODE_EVERY_DAY; // 每天重复
alarm.time.year = 2018; // 年份
alarm.time.month = 1; // 月份
alarm.time.day = 1; // 日期
alarm.time.hour = 1; // 小时
alarm.time.min = 1; // 分钟
alarm.time.sec = 0; // 秒钟
alarm.name_len = 0; // 名称长度
u8 alarm_del(u8 index)
功能:删除闹钟。
用法:参数为闹钟索引号。
void alarm_name_set(u8 *p, u8 index, u8 len)
功能:设置闹钟名字。
用法:参数可以参考代码类似结构去使用。
u8 alarm_get_info(PT_ALARM p, u8 index)
功能:获取闹钟信息。
用法:在手动设置完时间后,需要调用这个接口去更新时间。
4. 按键事件
set_rtc_up()
功能:增加当前设置位置的时间值。
用法:在调用set_rtc_pos()进行选择设置后进行加操作。
set_rtc_down()
功能:减少当前设置位置的时间值。
用法:在调用set_rtc_pos()进行选择设置后进行减操作。
set_rtc_sw()
功能:切换RTC设置模式。
用法:在时间设置和五个闹钟设置之间切换。
set_rtc_pos()
功能:切换当前设置的位置,在年、月、日、时、分之间切换。
用法:在手动设置完时间后,需要调用这个接口去更新时间。