穿戴手表JL701N-入门到进阶开发指导
📎 原始文档:https://www.kdocs.cn/l/cqr0dt8Gazv5 穿戴手表JL701N-入门到进阶开发指导
📌杰理工具说明文档:
(程序开发工具、固件处理工具、量产相关工具)
欢迎使用杰理工具文档 — JL Project Documentation
📌杰理工具及开发板淘宝店
📌手表穿戴技术应用文档入口汇总
https://kdocs.cn/l/csRItfaUZijL
📂技术文档指引:
📌JL701N芯片型号规格:

📌JL701N源码开发 包(SDK、APP、补丁):
1、JL701N穿戴类补丁list
https://kdocs.cn/l/clysrollEaiR
2、OTA补丁list
https://kdocs.cn/l/ctD0GmkvdPUX
📌JL701N技术文档(功能模块、FAQ):
屏融合应用方案入口汇总.otl
内含杰理FAQ文档,积累了很多常见问题的解决方案,各位客户请遵循先自查后咨询的流程,提高技术咨询的效率和质量。
📌JL701N入门视频培训:
杰理JL701N SDK入门指南【培训】_哔哩哔哩_bilibili
杰理JL701N UI开发指南【培训】_哔哩哔哩_bilibili
杰理JL701N 硬件指南【培训】l_哔哩哔哩_bilibili
杰理JL7012A 小核应用培训【培训】_哔哩哔哩_bilibili
杰理JL7012A 智能手表APP开发【培训】_哔哩哔哩_bilibili
杰理JL7012A APP固件通信开发【培训】_哔哩哔哩_bilibili
📌杰理工具说明文档:
(程序开发工具、固件处理工具、量产相关工具)
欢迎使用杰理工具文档 — JL Project Documentation
杰理工具下载页面:
1. 工具最新版本 — JL Project Documentation (zh-jieli.com)
一、开发板指导
以下配置过程中遇到问题可以参考 杰理工具文档,本文章旨在进行通俗指导。
1.1 硬件环境
①强制升级工具(烧录器):拨两个位
先把盖子撬开:日常使用拨码打开第5、7位就可以
②AC701N开发板:接两根线
- RX改接PA4:日志输出 开发板要如果仅是强制升级工具供电,需要如下改接线:
- VUSB改接BAT+:USB供电(特别注意:不然下载开发板供电不对)

注意:若开发板屏幕已经更换了466*466新型号,需要更新屏幕驱动701N 开发板新屏幕驱动修改.otl
1.2 软件环境(window)
1.2.1 安装IDE
注意:Code::Blocks 或 vscode (IDE根据喜好二选其一,推荐vscode)
①安装Code::Blocks
在浏览器中打开链接:Code::Blocks Windows版本(点击此处下载)
双击下载后的 codeblocks-latest.exe ,按照提示进行安装即可。
注:打开安装好的 Code::Blocks 后,关闭 Code::Blocks (这是为了让Code::Blocks生成一些基础设置信息)
②安装vscode
在浏览器中打开链接:vscode Windows版本(点击此处下载)
下载并安装vscode,vscode内安装必要的插件
- Task Explorer
- C/C++


1.2.2 安装杰理工具链
下载并安装 最新版本的杰理Windows版工具链(点击此处下载)
注意:请勿更改默认安装路径,按照默认路径安装
1.3 编译步骤
1.3.1 编译准备
根据以上步骤准备好硬件和软件环境杰理工程环境的快速安装介绍.doc
板子USB和烧录器连接,烧录器接USB线到电脑上,能成功能识别
注意:没识别可能是你电脑没有CH340串口驱动,自行网络下载或联系杰理获取。
按下强制烧录工具“update”按键,烧录器绿灯灭。红灯常亮,表示进入烧录模式:


1.3.2 Code::Blocks编译
直接打开 SDK 目录下的 cbp 工程(cbp是Code::Blocks的工程文件类型)7789
编译
编译成功页面:
编译并下载完成后,需要对开发板断上电重启,然后绿灯闪烁,系统运行。
1.3.3 VSCode编译
使用 VSCode 打开 SDK 目录,注意必须在SDK文件夹下打开VSCode,否则编译出错。

编译成功页面:
编译报错页面:没有进入烧录模式,请按下烧录器按钮后(绿灯灭红灯常亮)重新编译烧录
编译并下载完成后,需要对开发板断上电重启,然后绿灯闪烁,系统运行。
1.4 新增/移除文件
1.4.1 Code::Blocks
新增源文件/库文件时,需要手动导入工程,否则不会编译进去。
①新增/移除文件(.h/.c):
②新增/移除库文件(.a):
鼠标选中工程,然后右键菜单,再点击编译选项。
添加好第三方库之后,点击“OK”。
以上就可以成功导入第三方库到当前工程中去。
1.4.2 VScode
新增/移除文件:新增源文件/库文件时,需要手动修改makefile,否则不会编译进去。



1.5 烧录工具串口配置
本节介绍用USB强制烧录工具,进行串口日志输出,无需外接其他USB串口,日志机制参考2.7.1
1.5.1 杰理串口驱动
安装杰理虚拟串口工具:强制升级工具4.0串口驱动(点击此处下载)
安装驱动后,需要重启电脑
打开杰理虚拟串口工具,进行端口绑定,步骤参考:虚拟串口绑定
该驱动主要是驱动烧录器上的串口,可以直接监听烧录器上的串口,充当串口调试器
完成以上步骤后,有两种串口连接方式
- 利用烧录器的RX串口引脚
- 利用烧录器的USB-DP引脚 ①利用烧录器的RX串口引脚
设置串口通讯参数
对应代码中的UART板级配置
②利用烧录器的USB-DP引脚
设置串口通讯参数
对应代码中的UART板级配置
1.5.2 串口监听软件
①XShell 非开源,自行网络下载安装包
参阅《Xshell带颜色打印说明文档》对xshell进行配置:
Xshell带颜色打印说明文档[已封装宏]
②Windterm
windterm是一款风格独特、开源、且完全免费的SSH/Telnet/Serial/Shell/Sftp 客户端
下载地址:https://github.com/kingToolbox/WindTerm/releases
③MobaXterm
MobaXterm 分免费开源版和收费专业版: 下载官网免费开源版
下载地址:https://mobaxterm.mobatek.net/download-home-edition.html
1.6 批量量产与调试工具
1.6.1批量量产工具 一拖二
1. 杰理科技一拖二烧录器用户手册 — JL Project Documentation
1.6.2批量量产工具 一拖八
2. 杰理科技一拖八烧录器用户手册 — JL Project Documentation
1.6.2调试工具 强制升级工具
6. 杰理科技强制升级工具4.0使用说明 — JL Project Documentation
1.7 穿戴生产烧录OTA和key文件添加使用说明
此文档主要介绍穿戴系列芯片的代码添加key 文件的demo操作,客户根据实际添加更换key 文件接口,key 文件属于客户的秘钥文件,配合烧录器使用的,key 文件请找代理商拿取。
穿戴生产烧录OTA和key文件添加使用说明
二、SDK架构流程
该章节只对SDK部分机制进行简单指导,详情请参阅SDK目录下的《701N_WATCH_SDK介绍》:
2.1 文件架构

2.2 板级配置
AC701N的WATCH_SDK中包含板级有三个:
板级配置宏在..\code\sdk\apps\watch\board\br28\board_config.h
//对应的宏开关(互斥,选其一)
#define CONFIG_BOARD_701N_DEMO
#define CONFIG_BOARD_7012A_DEMO
#define CONFIG_BOARD_7012A7_DEMO
#define CONFIG_BOARD_701N_LVGL_DEMO
#define CONFIG_BOARD_AD2802E_DEMO
//板级之间是互斥、每次只能应用其中一个。
//每个可共用对应的ui驱动代码,但是必须能够下载进去,
//否则需要根据实际需求修改裁剪,每次开发只能选择一种板级开发。
CONFIG_BOARD_701N_DEMO板级配置适用于所有701N系列芯片
以使用CONFIG_BOARD_701N_DEMO板级配置为例,打开board_ac701n_demo_cfg.h文件,该文件主要对芯片的外设功能及io进行配置。
2.3 软件流程
SDK启动流程:
- 程序的入口函数main( )位于init.c文件,而main主函数中调用setup_arch( )进行了内存/时钟等初始化,并创建了模式任务处理,并在任务处理app_task_handler( )中分别分别进行了任务的初始化app_init( )和任务的调度处理app_main( )。
- steup_arch( )函数:该函数主要进行内存的初始化、看门狗初始化、时钟的初始化、初始io及系统时间的初始化等芯片的初始化功能(大致理解为程序的运行环境做准备)。
- app_init( )函数:该函数则是为任务(模式)进行准备,进行解码初始化、按键开机检测和CUP复位部分操作等。
- app_main( )函数:任务主函数app_main则在app_mian.c中进行处理,其中比较重要的是对开机初始模式进行设置,并循环根据app_task_loop( )获取并设置的最新的模式任务。

2.4 任务管理
2.4.1 任务列表
任务信息统一由task_table.c的task_info_table任务列表进行管理:
参数(从左到右):
- 任务名 (名字长度不能超过configMAX_TASK_NAME_LEN字节)
- 任务优先级(0-7,越大优先级高,优先级数量由configMAX_PRIORITIES决定)
- 任务运行的位置(0:CPU0 1:CPU1)
- 任务的堆栈大小, 单位(u32)
- 任务的queue大小,单位(byte)
举个例子🌰:
利用task_create新建任务时
底层会根据传入的任务名称参数,扫描task_info_table导入对应的任务参数信息
2.4.2 主任务的模式切换
当开始通过app_main( )函数设置首任务或进行任务模式切换时,便会执行app_task_loop( )判定并开始相应模式的任务,当发生任务模式更改时,会根据变量app_curr_task跳转执行。
"app_core"的模式切换
2.5 事件管理
基于消耗型消息队列的事件处理机制,消息处理又分为模式消息处理和公共消息处理,当有消息事件推出时,先在当前模式进行处理响应的消息后,若不进行处理(返回false)后才会丢到公共事件中去判定处理。
事件处理机制:
举个例子🌰:以poweroff模式为例,当推送按键消息KEY_UI_POWEROFF出来后,会先在poweroff模式事件入口函数poweroff_sys_event_handler()中执行并判定消息是否已经处理,若未处理(返回false),则推送到公共事件处理函数app_default_event_deal()中的公共按键处理函数app_common_key_msg_deal( )进行处理。
2.6 低功耗机制
SLEEP模式 :浅度睡眠,唤醒速度快,保留更多系统状态,外设恢复快, 使用高精度晶振,但功耗相对较高;
DEEPSLEEP模式:深度睡眠,掉电更彻底,更多模块会被关闭,唤醒后需要更完整的初始化, 功耗最低,使用LRC晶振,但唤醒延迟稍长。
2.6.1 低功耗流程
低功耗检测节点状态是软件层面人为设置的条件。系统底层会一直检测低功耗节点链表,遍历检测所有注册的低功耗检测节点,如果所有低功耗检测节点都满足进入低功耗条件,则系统会进入低功耗模式。
若系统在低功耗模式中,检测到某节点被激活,则退出低功耗模式。
doc/software/驱动/低功耗流程.md · 珠海杰理科技FAE/IOT-AC630N - Gitee.com
① 注册低功耗检测节点
#define ALLOW_INTO_LP (TRUE) //1
#define NOT_ALLOW_INTO_LP (FALSE) //0
static volatile u8 lp_test_status = ALLOW_IN_LP; //默认允许进入低功耗
static u8 lp_idle_query(void) //低功耗检测节点检测回调
{
return lp_test_status;
}
REGISTER_LP_TARGET(lp_test_lp_target) = { //注册低功耗检测节点
.name = "lp_test",
.is_idle = lp_idle_query,
};
举个例子🌰:
② 低功耗检测节点链表打印
SLEEP检测链表可以开个定时器去打印低功耗检测节点的状态,全为1才运行进休眠,可以参考哪些模块在工作导致灭屏后进入不了休眠
sys_timer_add(NULL, lp_target_printf, 2000);
void lp_target_printf(){
struct lp_target *p;
list_for_each_lp_target(p){
printf("name:%s level:%d is_idle:%d",
p->name,
(p->level)?p->level():-1,
(p->is_idle)?p->is_idle():-1);
}
}
2.6.2 功耗调试指南
文档参考:功耗调试指导.otl
- 软件层面:
- 先排查软件层面,打印低功耗节点状态,判断是否有进入低功耗模式,以及哪个节点没满足进入低功耗的条件。如果进入了低功耗后,功耗仍然高,再排查硬件层面原因。
- 检查软件中定时器,是否存在频繁唤醒系统的定时器。例如心率,gsensor,等频繁唤醒的定时器。一般500ms定时器对系统影响较大
② 硬件层面:
- 注意SW引脚若未接电感,则电源模式只能选择LDO,选择LDO会增加平均功耗。

- 处理功耗问题,常见影响电流的外设TP,speaker,lcd。Speaker的mute脚排查是否为高有效。3ma左右底电流增加
- 用手触摸板子的io,查看是否存在漏电情况,单个io漏电约300ua
- 逐一拆除有影响的外设,排查具体模块影响
2.6.3待机功耗参考

2.7 日志机制
2.7.1 日志机制
①日志引脚配置
首先,要把串口打印模块使能(参考章节1.5),串口发送脚也要配置为对应的引脚,串口波特率默认为:1000000
②日志总开关
app_config.h里面的CONFIG_DEBUG_ENABLE(注释掉=关掉所有打印)
③库日志开关
app_config.h里面的LIB_DEBUG(0=关掉库打印)
④异常中断开关(断言)
lib_system_config.c里面的config_asser,异常中断打印信息分析,请参考章节2.7.3
注意:打开异常中断后,当异常发生时,会打印异常中断信息,且系统不会自动重启。
因此在生产时,务必关闭异常中断,使设备发生异常时系统能自动重启,不至于变砖。
关闭打印和关闭异常中断是两个开关,没关异常中断,只是关打印,系统异常死机一样不会自动重启。
⑤日志等级配置
在log.h里面,通过更改__LOG_LEVEL设置对应的打印等级
⑥日志着色
(需配合xshell软件使用)参阅1.5.2章节
2.7.2 常用日志接口
以下都属于库打印,需要打开库打印宏
内存打印:mem_printf
时钟打印:clock_dump
任务状态:task_info
不掉电ram实时打:mem_stats
掉电ram实时打印:mem_vlt_stats
系统堆栈打印开关:const int config_system_info = 1;
2.7.3 死机日志分析
①参阅《手表软件调试》:手表软件调试
②参阅《死机分析》:死机分析
③参阅《JL701N穿戴客述问题FAQ》第六章节:JL701N穿戴客述问题FAQ
2.8 SDK裁剪
SDK裁剪,缩小app.bin的大小
2.8.1 裁剪SDK功能
【金山文档 | WPS云文档】 noflash_noui
https://www.kdocs.cn/l/cg0r2g7GMS2Y
先把该文件下载到本地,重命名把后缀的.doc去掉,你用notepad++打开这个文件,可以看到着色对比,然后找到看上图的板级配置文件的部分,这个文件是去掉所有功能的,你参考这样配置宏,根据你的需求去裁剪SDK , 编译不过的,你看一下对应代码在哪里,自己处理一下,如果报错太多就不裁这个,裁别的功能 。
2.8.2 裁剪提示音
打开 SDK 对应的 ..\701n_watch_release_v2.X.X\code\cpu\br28\tools\AC701N_config_tool,进入配置工具入口—>选择编译前配置工具—>提示音配置
2.8.3 屏蔽打印
参考章节2.7.1
三、SDK功能模块
3.1 外设
本章节可参考《外设相关应用》:外设相关应用
3.1.1 TP
TP回调频繁且实时性要求高,在中断里面执行触摸事件判断,判断完触摸事件后再外传线程
以公版bl6133.c触控驱动为例:
TP驱动修改:
根据屏厂给的驱动文件和数据手册,修改触摸屏的IIC地址,如HYN_I2C_ADDR 0x15,那么设备的写寄存器地址就是0x15<<1( 0x2A),读地址为 (0x15<<1 + 1)0x2B。
IIC的读写寄存器的函数接口:i2c_read_regs()和CTP_FLASH_I2C_READ()、i2c_write_regs和CTP_FLASH_I2C_WRITE(),在IIC读写寄存器函数的内部对设备的IIC地址进行了偏移操作,只需根据屏厂提供的驱动的设备地址和寄存器地址进行填写和修改即可
屏厂提供的驱动文件
修改设备IIC地址
在调试TP的时候,可以先配置TP的中断、复位引脚和IIC驱动引脚:
读取TP芯片额ID,方便确认IC是否正常通信。
TP的休眠和唤醒:配置中断唤醒引脚&休眠和退出休眠寄存器->注册唤醒源->使能唤醒源



注意:若是获取到ID,获取不到报点,大概率是TP固件的问题,需要联系屏厂,更新固件;
3.1.2 LCD
SDK内部内置了部分型号的屏幕驱动,并通过宏进行管理,只能启用一个屏驱,否则有编译问题。
可以通过全局搜索屏驱的宏,定位驱动文件的位置、引脚配置的位置,如屏幕引脚配置:
屏幕驱动介绍:
上图中列举了部分屏幕参数,其中:
LCD_DRIVE_CONFIG::推屏时序
如QSPI_RGB565_SUBMODE2_1T2B对应的是QSPI时序,数据结构为RGB565、1个周期发2字节数据;
具体可以参阅《701N屏幕驱动配置说明》:..\701n_watch_release_v2.X.X\doc\固件资料\UI
SCR_X、SCR_Y:屏幕x轴和y轴偏移,不需要偏移的话默认填0即可。
SCR_W、SCR_H、LCD_W和LCD_H:屏驱宽高,一般填屏幕分辨率即可。
LCD_BLOCK_W:分块buf的宽度,一般是按行分块,宽度设置为跟LCD_W一致即可。
LCD_BLOCK_H:分块buf高度,可以根据需求修改。
BUF_NUM:buf数量默认设置2,一般不需要修改。
LCD_FORMAT:推屏数据格式,默认设置RGB565,一般不需要修改。
以上提及的数据,一般只需要修改SCR_W、SCR_H、LCD_W和LCD_H和LCD_BLOCK_W即可。
屏幕初始化命令如上图所示,用户添加新的屏驱时需要按照一定规则去修改屏驱初始化命令,其中_BEGIN_和_END_分别为开始标志位和结束标志位,这两个标志位跟实际上推屏数据无关,只是作为杰理lcd模块用于控制数据发送的信号。
BEGIN_后的第一个参数是命令,后续的则是数据,如_BEGIN, 0xc0, 0x5a, 0x5a, _END_中,命令是0xc0,数据是0x5a, 0x5a。
可以理解为,以上命令是屏厂驱动的SPI_WriteComm(0xc0);SPI_WriteData(0x5a);SPI_WriteData(0x5a);转换而来。
fps:fps为设置的帧率,默认为60,底层会根据fps算出合适的时钟速率,如果想要了解fps和时钟速率的一个对应关系,可以将app_config.c里面的log_tag_const_d_UI AT(.LOG_TAG_CONST)设置为true,在打印中搜索fps相关打印即可找到两者直接的对应关系。
debug_mode_en:debug模式开关,置为true后不会推合成后的数据,而是根据debug_mode_color设定的颜色值去显示,一般用于推屏数据的排查。
debug_mode_color:debug模式时显示的颜色值。
注册lcd设备,在这个步骤中,会将屏驱相关信息注册进去,用户可以根据需求修改logo以及名称。
注意:ST77903系列屏幕,需要PSRAM参与驱动,请确认目前的主控芯片是否内置PSRAM,或硬件上是否外挂PSRAM。
3.1.3 传感器
传感器数据处理流程,参阅《传感器数据处理》:传感器数据处理.pdf
3.1.4 编码器
参阅FAQ编码器相关内容:JL701N穿戴客述问题FAQ
3.1.5 按键
按键配置:
- iokey就是独立按键
- adkey就是adc按键
- irkey就是红外按键
- tocuh key就是触控按键
- rdec_key就是编码器按键
在不同主任务模式下,每种key都有不同的映射表 :
体现在task_key.c文件里面:
按键检测通过定时器轮训:
按键事件类型判断逻辑在key_driver.c里面:
为了更快地响应响应单击,SDK默认关闭双击判断,可通过以下宏配置:
举个例子🌰:
假设主任务在蓝牙模式(bt模式)下,我按下独立按键为例,bt模式的iokey table如下:
上面二维数组,表示了4个按键(4行),对应了下图板级配置文件下的4个iokey配置,
每个按键都有四种状态(4列)表示按键状态触发时向主任务发送的事件,为空则不发。
比如,我单击按键KEY0,按键驱动判断是单击事件,然后索引到be_key_io_table[0][0],然后往主任务发送KEY_UI_HOME事件,然后在主任务里,实现KEY_UI_HOME响应,处理KEY_UI_HOME事件。
3.2 中断
中断相关接口在hwi.h
中断优先级:0-7(越大优先级高,7为不可屏蔽中断)
注意:注册不可屏蔽中断,需先使能CONFIG_CPU_UNMASK_IRQ_ENABLE
硬件I/O中断参数通过wk_param配置
在wk_param里和自定义的port_wakeup建立映射,port_wakeup为中断触发参数配置
硬件中断相关接口在power_wakeup.h
- 不带a代表数字输入IO相关
- 带a代表模拟输入IO相关
//数字输入IO相关接口
void power_wakeup_index_enable(u8 index, u8 enable); //基于wk_param配置项使能中断IO
void power_wakeup_gpio_enable(u8 gpio, u8 enable); //基于引脚号使能中断IO
void power_wakeup_gpio_edge(u8 gpio, POWER_WKUP_EDGE edge); //配置中断IO触发方式
//模拟输入IO相关接口
void power_awakeup_index_enable(u8 index, u8 enable);
void power_awakeup_gpio_enable(u8 gpio, u8 enable);
void power_awakeup_gpio_edge(u8 gpio, POWER_WKUP_EDGE edge);
void power_awakeup_gpio_filter(u8 gpio, POWER_WKUP_FLT filter);
//数字输入IO中断响应注册接口
void power_wakeup_set_callback(void (*wakeup_callback)(u8 index, u8 gpio));
//模拟输入IO中断响应注册接口
void power_awakeup_set_callback(void (*wakeup_callback)(u8 index, u8 gpio, POWER_WKUP_EDGE edge));
//数字输入IO中断响应注册接口(基于wk_param配置项索引)
void port_edge_wkup_set_callback_by_index(u8 index, void (*wakeup_callback)(u8 index, u8 gpio));
//模拟输入IO中断响应注册接口(基于wk_param配置项索引)
void aport_edge_wkup_set_callback_by_index(u8 index, void (*wakeup_callback)(u8 index, u8 gpio, POWER_WKUP_EDGE edge));
//wk_param配置初始化
void power_wakeup_init(const struct wakeup_param *param);
//唤醒源判断
u8 is_wakeup_source(enum WAKEUP_REASON index);
//唤醒源打印
void power_wakeup_reason_dump();
//ldo唤醒判断
u8 is_ldo5v_wakeup(void);
注意:
3.3 定时器
中断相关接口在timer.h
🚧待施工
3.4 FLASH(分区、批处理)
3.4.1 FLASH 选型
避免出现FLASH异常问题,建议使用验证过的FLASH
701N_707N_WATCH_外设推荐.docx
3.4.2 FLASH 分区说明

| FLASH分区 | 容量大小配置 | 分区文件 | 分区说明 |
|---|---|---|---|
| 保留区域 | 固定8K | 记忆本地蓝牙信息等 | |
| 内置VM区域 | 最小100K,默认128K 配置大小: TCFG_UI_VM_INSERT_FLASH_SIZE | 系统信息记忆 客户信息记忆 | |
| 资源空间 | 配置大小: CONFIG_RULE_INSERT_FLASH_SIZE | 批处理中添加的内容 内置flash资源文件:new_res.bin | 资源文件、提示音等 |
| FAT虚拟文件系统空间 | 配置大小: TCFG_VIRFAT_INSERT_FLASH_SIZE | app.bin(SDK编译后生成的代码)(主要) cfg_tool.bin(蓝牙配置【编译前配置工具】生成的文件) | 代码、配置工具文件 |
外置FLASH方案,主要配置外置FLASH分区参数,内置2M FLASH自动分区
| 内置FLASH分区 | 分区大小 | 分区文件 | 分区说明 |
|---|---|---|---|
| 保留区域 | 固定8K(无需配置) | 记忆本地蓝牙信息等 | |
| 内置VM区域 | 最小100K,默认100K(无需配置) | 系统信息记忆 | |
| FAT虚拟文件系统空间 | 内置FLASH除去内置VM区域+8k保留区域,剩余的空间为FAT虚拟文件系统空间 | app.bin(主要) (SDK编译后生成的代码) cfg_tool.bin (蓝牙配置【编译前配置工具】生成的文件) | 代码、配置工具文件 |
| 外置FLASH分区 | 分区大小 | 分区文件 | 分区说明 |
| 外置VM区域 | 最小100K,默认128K 配置大小: CONFIG_EXTERN_USER_VM_FLASH_SIZE | 客户信息记忆 | |
| 资源空间 | 外置FLASH除去外置VM区域剩余的空间为资源空间 配置大小: 例如外挂flash 16M,外置VM 128K,那么资源空间为1610241024 - 128*1024 = 0xfe0000, download.bat中的配置需要和该配置对应上!!! download.bat配置为: fat_comm.exe ...... -mark-bad-after 0xfe0000 ...... | 批处理中添加的内容 外挂flash资源文件:res.bin | 资源文件、提示音等 |
VM区域实际大小:
固件烧录后,若FLASH其他分区存在多余空间,将会自动分配给VM区域,因此VM区域的实际大小一般情况下会大于配置大小
3.4.3 批处理文件说明
批处理是指烧录前资源整合的过程
手表SDK批处理文件位置:cpu\br28\tools\download\watch
内置flash烧录:download_insert.bat,一般有**insert.bat字样
外置flash烧录:download.bat
编译烧录时,会代码中根据不同的配置,调用不同的批处理脚本,如下图:
在批处理文件当中,通常会看到调用如图这几个可执行文件
- packres.exe:顾名思义,就是把资源文件们,整合打包成res文件 关键指令介绍:
| -n re | 输出res资源格式 |
|---|---|
| -o name | 输出资源文件名 |
- fat_comm.exe:顾名思义,该操作打包的是FAT(虚拟文件系统)资源文件 关键指令介绍:
| -out | 输出资源文件名 |
|---|---|
| -image-size | flash大小(单位:MB)(内置FLASH方案填内置FLASH大小,外置FLASH方案填外置FLASH大小) |
| -filelist | 资源列表,打包的资源列表,最后资源列表的所有资源都会打包到-out指定的输出文件中 |
| -mark-bad-after | 资源分区大小,要和代码分配的对应上,否真会出现代码访问异常 |
| -key | 指定烧录key文件,key文件要放在和批处理文件相同目录下![]() |
- isd_download.exe :启动烧录,将代码文件、免开发配置文件、下载到内/外置flash 关键指令介绍:
| -tonorflash -dev br28 -boot 0x120000 -div8 -wait 300 | 都是系统参数,具体作用无需了解,没了会usb烧录失败 |
|---|---|
| -uboot | 指定uboot文件 |
| -app | 指定app区域文件: app.bin(SDK编译后生成的代码) cfg_tool.bin(蓝牙配置[编译前配置工具生成的文件]) |
| -res | 内部flash的res区域,给sdk调用的存放在内置flash的资源 |
| -uboot_compress | 指定当前uboot.boot文件是一个加了压缩的文件 |
| -key | 指定烧录key文件,key文件要放在和批处理文件相同目录下![]() |
| -ex_flash | 指定外挂flash资源(内置flash方案,无需该命令和参数) |
| -reboot 100 | usb线烧完成100ms后,会自动退出烧录模式 |
| -format all | usb线烧时,先全擦flash |
| -format vm | usb线烧时,先擦除VM区域 |
补充:
isd_download.exe会隐式地调用isd_config.ini,即如果isd_download.exe没有指定特定的ini文件,就使用同目录下地名为isd_config.ini文件
指定ini文件只需要把这个文件放到isd_download.exe后面即可,例如:test.ini,则这样添加:isd_download.exe test.ini .......
注意:参数重复会导致异常,务必检查!
如:....\isd_download.exe -key abc.key -key 123.key,是错误的❌
如:....\isd_download.exe -key abc.key 123.key,才是正确的✔
3.4.4 内置FLASH配置
以内置8M FLASH为例:
①方案开关
内置FLASH虚拟文件系统宏:TCFG_VIRFAT_INSERT_FLASH_ENABLE打开
外置FLASH虚拟文件系统宏:TCFG_NORFLASH_SFC_DEV_ENABLE关闭
②空间分配
匹配值内置flash大小:CONFIG_FLASH_SIZE
然后计算出各分区的划分数据:
③批处理修改
内置FLASH,调用的是download_**_insert.bat
在fat_comm.exe命令中的-image-size所带参数要改为内置flash大小
在fat_comm.exe命令中的-mark-bad-after所带参数要改为资源分区实际大小:
TCFG_VIRFAT_INSERT_FLASH_SIZE
在fat_comm.exe命令中,检查如果有-key %CHIPKEY%,则去除-key %CHIPKEY%:
案例参考:JL7014F5芯片调试注意事项.pdf
3.4.5 外挂FLASH配置
以外置16M FLASH为例:
①方案开关
内置FLASH虚拟文件系统宏:TCFG_VIRFAT_INSERT_FLASH_ENABLE关闭
外置FLASH虚拟文件系统宏:TCFG_NORFLASH_SFC_DEV_ENABLE打开
②空间分配
匹配内置flash大小:CONFIG_FLASH_SIZE
匹配外置flash大小:CONFIG_EXTERN_FLASH_SIZE
然后是配置外置VM的大小:CONFIG_EXTERN_USER_VM_FLASH_SIZE
- 批处理修改 外置FLASH方案,调用的是download.bat
在fat_comm.exe命令中的-image-size所带参数要改为外置flash大小
在fat_comm.exe命令中的-mark-bad-after所带参数要改为资源分区实际大小
外挂FLASH单独烧录
有些客户为了生产便利,主控内置flash和外挂flash分开单独烧录,下面是具体的修改操作:
①内置flash资源单独烧录
批处理文件里,-ex_flash是下载到外部flash的参数,需要去除,然后不会烧录到外置flash
②外置flash资源单独烧录
把new_res.bin发给flash厂,用flash厂的专用工具单独烧录到外置flash。
注意:是new_res.bin,不是res.bin。
3.4.6 常见分区编译异常
代码文件(app.bin)超出FAT虚拟文件空间大小,适当扩大FAT分区容量或裁剪代码。
资源文件(***res.bin)超出资源分区大小,适当扩大资源分区容量或裁剪资源体积。
固件文件(jl_isd.bin)超出flash大小,适当裁剪代码体积或裁剪资源体积。
开机后,日志报打开资源失败:代码flash配置不当,或批处理文件没有按要求修改
3.4.7 SD/TF卡配置
- 检测方式:I/O检测、CLK检测(需要硬件支持)、CMD检测 ②热拔插/热插拔配置

3.4.8 FLASH FAQ
①参阅文档《701N_WATCH_SDK介绍》中的内存相关章节:
②FAQ中的FLASH常见问题部分:
3.5 RTC
3.5.1 内置RTC
JL7012 支持免 32K 晶体,使用内部 LRC 作为 RTC 时钟,对比外部 32.768k 晶体,内部 RTC 受温漂影响较大,误差一天 5s 以内。
①硬件修改
免 32.768KHz 晶振方案时,对应接口 PB6 和 PB7 可以做 GPIO 口使用。
②软件修改
3.5.2 外置RTC

3.5.3 系统时间
默认时间
🚧待施工
3.6 蓝牙
3.6.1 BT
① 蓝牙基础接口使用:【金山文档】蓝牙接口使用说明
② 蓝牙音乐调试:蓝牙音乐播放调试.docx
3.6.2 BLE
① 客户接入自定义协议:【金山文档】 ble 开发流程
② BLE-HID
注意:目前该功能在安卓手机上与一键连接功能互斥。如果需要使用一键连接与该功能共存,安卓还要ble主动发起配对,会弹两次配对框,并且有些手机不会去读取hid的profile!!!!
【金山文档】 BLE-HID 控制抖音
【金山文档】 BLE-HID 调试文档
3.6.3连接流程
3.6.4 APP接入和交互
① 接入
APP端定义服务、特征值、属性等信息,在profile生成工具中按照说明文档添加对应信息后,生成profile和对应的handle,然后替换SDK内的profile结构体和handle,通过handle去区分数据通道,该部分参考工具使用文档《make_gatt_services工具说明.pdf》。
解压..\701n_watch_release_v2.X.X\doc\固件资料\蓝牙文件夹下的make_gatt_services_v1.2.0.rar
② 交互
参阅《701N_WATCH_SDK_APP固件通信流程介绍》:
..\701n_watch_release_v2.X.X\doc\固件资料\APP固件通信
3.6.5 蓝牙接口文档
参阅《手表穿戴技术应用文档入口汇总》中的蓝牙部分文档:
常用接口实例:
获取本机蓝牙名字:
bt_get_local_name()
获取蓝牙通话状态:
get_call_status()
获取蓝牙链接状态:
get_bt_connect_status()
拨打电话:
user_send_cmd_prepare(USER_CTRL_DIAL_NUMBER, 号码长度,号码);
接听电话:
user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
启动搜索蓝牙设备:
bt_emitter_start_search_device();
停止搜索:
bt_emitter_stop_search_device();
根据mac地址连接耳机:
emitter_bt_connect(mac);
获取当前连接从设备地址:
get_cur_connect_emitter_mac_addr();
获取当前连接手机地址:
get_cur_connect_phone_mac_addr(void);
断开从设备:
user_emitter_cmd_prepare(USER_CTRL_DISCONNECTION_HCI, 0, NULL);
断开主设备:
user_send_cmd_prepare(USER_CTRL_DISCONNECTION_HCI, 0, NULL);
①参阅文档《701N_WATCH_SDK介绍》中的蓝牙模式章节:

②参阅SDK路径..\701n_watch_release_v2.X.X\doc\固件资料\蓝牙目录下的蓝牙文档:
③FAQ中的蓝牙常见问题部分
3.7 ADC
🚧待施工
3.7.1 录音
3.8 DAC
3.8.1 DAC参数配置
数字模拟转换器(DAC)的系统中,LP和LN通常指的是左声道正负输出端。当DAC输出左声道音频信号时,是否同时使用LP和LN取决于DAC所采用的信号输出方式:
①单端输出: 如果DAC采用单端输出方式,它通常只提供一个输出端口来传输音频信号,表示为L(Left)或LP。在这种情况下,左声道音频信号仅通过一个端子输出,而没有对应的负端(LN)。单端输出时,只需连接LP到左声道功放或扬声器的正极即可。
②差分输出: 在某些专业音频设备或要求更高信噪比、抗干扰能力的应用中,DAC可能采用平衡输出。平衡输出提供了两个端口,分别对应信号的正极(LP,如Left Positive)和负极(LN,如Left Negative)。这两个端子共同传输左声道音频信号,但相位相反。在接收端(如功放或有源音箱),同样需要两个输入端口来接收这两个互补的信号。平衡连接可以有效抑制共模噪声,提高音频质量。
综上所述,当DAC输出左声道音频时:
- 如果是单端输出,只会用到LP,不会用到LN。
- 如果是差分输出,则会同时用到LP和LN,它们分别代表左声道信号的正负极,共同构成完整的左声道信号。

| DAC硬件上的连接方式 | DAC的输出模式 | DAC信号输出引脚 |
|---|---|---|
| 左声道(单声道) | 单端输出 | LP |
| 差分输出 | LP、LN | |
| 右声道(单声道) | 单端输出 | RP |
| 差分输出 | RP、RN | |
| 左右差分(双声道) | 单端输出 | LP、RP |
| 立体声(四声道) | 单端输出 | LP、RP |
| 差分输出 | LP、LN、RP、RN |
举个例子🌰:
7014F只有RP和LP引脚,只有P端,因此只能选择单端输出
DAC连接方案:
单声道方案:
A方案-左声道单端输出(只用LP)✅
B方案-右声道单端输出(只用RP)✅
双声道方案:
C方案-双声道单端输出(用LP和RP)✅
D方案-双声道差分输出(用LP、LN和RP、RN)❌(选差分N端也会打开导致功耗大)
3.8.2 系统音量配置
cpu\br28\audio_config.h
#define SYS_MAX_VOL MAX_DIG_VOL //最大音量值
#define SYS_DEFAULT_VOL 0 //系统默认音量
#define SYS_DEFAULT_TONE_VOL 8 //提示音默认音量
#define SYS_DEFAULT_SIN_VOL 6 //音乐默认音量
3.8.3 提示音测试
提示音的配置,需通过配置工具,进行配置
code\sdk\cpu\br28\tools\AC701N_config_tool
保存后编译即可,提示音设置会保存在tone.cfg,跟随批处理下载到flash
可在SDK中调用tone_play_by_path播放
void tone_test_play(){
int err = tone_play_by_path(SDFILE_RES_ROOT_PATH"tone/vol_max.*", 0);
// int err = tone_play_by_path(TONE_NORMAL, 0); //播放一段正弦波
if(err){
printf("tone test fail!\n");
}else{
printf("tone test succ!\n");
}
}
注意:提示音可以被抢断,后播会覆盖前播,若出现提示音没播,可以排查是否提示音冲突。
3.9 GPIO
3.9.1 状态说明
- 方向:有输入,有输出,无开漏。
- 上下拉:所有IO都有上下拉, 电阻固定, 但不同芯片, 或不同引脚的阻值是有差异的, 具体看芯片的规格书。输入状态才有上下拉。
- 水平:输出高(电压接近于VDDIO电压),输出低(相当于地,灌电流形式)
- 能力:普通输出、强输出、超强输出,3种输出能力。超强输出只有极少IO有此能力。
- 状态:数字态,模拟态,2种状态。输入状态下AD检测才用模拟态。
- 读取:输入数字态,可以读取IO的电压高低。 IO的承受电压不能高于VDDIO,否则会有倒灌,从而影响其他IO的检测
3.9.2 接口说明
第一个参数都是IO的宏定义, 如:IO_PORTA_00,指 PA0
- gpio_set_direction() 设置IO的方向,第二个参数:1输入,0输出
- gpio_set_pull_up() 设置上拉电阻的使能,第二个参数:1开启,0关闭
- gpio_set_pull_down() 设置下拉电阻的使能,第二个参数:1开启,0关闭
- gpio_set_output_value() 设置输出电压水平,第二个参数:1高,0低
- gpio_set_die(), gpio_set_dieh() 设置IO的状态,第二个参数:1数字态,0模拟态
- gpio_set_hd0(), gpio_set_hd() 设置IO的能力,第二个参数:1强输出,0普通输出
- gpio_read() 输入数字态下读取电压水平,返回值:1是高,0是低
3.9.4 寄存器说明
typedef struct {
__RW __u32 OUT; //gpio_set_output_value
__RO __u32 IN; //gpio_read
__RW __u32 DIR; //gpio_set_direction
__RW __u32 DIE; //gpio_set_die
__RW __u32 PU; //gpio_set_pull_up
__RW __u32 PD; //gpio_set_pull_down
__RW __u32 HD0; //gpio_set_hd0
__RW __u32 HD; //gpio_set_hd
__RW __u32 DIEH; //gpio_set_dieh
} JL_PORT_FLASH_TypeDef;
3.9.5 GPIO设置范例
设置输出高低
u32 gpio = IO_PORTA_00;//指定IO
gpio_set_pull_down(gpio, 0);
gpio_set_pull_up(gpio, 0);
gpio_set_die(gpio, 1);
gpio_set_hd(gpio, 0);//看需求是否需要开启强推,会导致芯片功耗大
gpio_set_hd0(gpio, 0);
gpio_set_direction(gpio, 0);
gpio_set_output_value(gpio, 1); //1高0低
设置输入读取IO高低
u32 gpio = IO_PORTA_00;//指定IO
gpio_set_pull_down(gpio, 0);//看需求是否需要开内部下拉
gpio_set_pull_up(gpio, 0);//看需求是否需要开内部上拉
gpio_set_die(gpio, 1);
gpio_set_direction(gpio, 1);
delay(100);//设置方向寄存器后,不能立马读电压
int level = gpio_read(gpio);
设置输入模拟检测电压
u32 gpio = IO_PORTA_00;//指定IO
gpio_set_pull_down(gpio, 0);//看需求是否需要开内部下拉
gpio_set_pull_up(gpio, 0);//看需求是否需要开内部上拉
gpio_set_die(gpio, 0);
gpio_set_direction(gpio, 1);
可视化SDK 同时设置上下拉
u32 port = PORTA;//指定IO
u32 pin = PORT_PIN_2;
gpio_hw_set_direction(port, pin, 1);//0:out, 1:in
gpio_hw_set_die(port, pin, 0);
gpio_hw_set_dieh(port, pin, 0);
gpio_hw_set_pull_up(port, pin, GPIO_PULLUP_10K);
gpio_hw_set_pull_down(port, pin, GPIO_PULLDOWN_10K);
3.9.6 打印监控IO状态
JL_PORT_FLASH_TypeDef *PORT = JL_PORTA; //指定组口
u8 bit = 0; //指定位口,组合起来,即 PA0 == IO_PORTA_00
printf("port:DIR-%d,PU-%d,PD-%d,DIE-%d,DIEH-%d,HD0-%d,HD-%d,OUT-%d,IN-%d\n",
(PORT->DIR &BIT(bit))?1:0,
(PORT->PU &BIT(bit))?1:0,
(PORT->PD &BIT(bit))?1:0,
(PORT->DIE &BIT(bit))?1:0,
(PORT->DIEH&BIT(bit))?1:0,
(PORT->HD0 &BIT(bit))?1:0,
(PORT->HD &BIT(bit))?1:0,
(PORT->OUT &BIT(bit))?1:0,
(PORT->IN &BIT(bit))?1:0
);
3.9.7 IO强驱
先确认该IO支持强驱才行
3.10 文件系统📂
文件系统相关接口在fs.h
🚧待施工
3.10.1 fscan扫描参数
* @brief 文件扫描
*
* @param path 路径
* @param arg 扫描方式
* @param max_deepth 扫描深度,最大为9
*
* @return vfscan句柄 / 失败返回NULL
*/
/* ----------------------------------------------------------------------------*/
struct vfscan *fscan(const char *path, const char *arg, u8 max_deepth); //扫描接口,参数配置如上。
arg扫描参数
-t 文件类型
-r 包含子目录
-d 扫描文件夹
-a 文件属性 r: 读, /: 非
-s 排序方式, t:按时间排序, n:按文件号排序

3.11 电源管理🔋
3.11.1 放电配置
放电相关配置:apps\watch\include\app_power_manage.h
🚧待施工
3.11.2 充电配置
充电相关配置:..\apps\watch\power_manage\app_power_manage.c
若电池充电过程中电量显示不准,需要修正电池充电曲线,首先找电池原厂拿到电池的充放电数据
😃示例文档:锂锐771430-300mAh 1C充0.5C放曲线图.xlsx
在充电过程中采集20个点数据,然后修正SDK中原本的电压-容量百分比曲线
四、杰理UI框架
4.1 UI 编辑工具
本章节意在简单介绍上手,工具的详细配置以及使用说明,请参阅以下文档:
参阅《UI布局工具使用说明》:
..\701n_watch_release_v2.X.X\code\sdk\cpu\br28\tools\UI工程\doc
参阅《701N_UI编辑工具用户手册》和《UI工具快速使用说明》(表盘操作):
..\701n_watch_release_v2.X.X \doc\固件资料\UI
SDK的UI工程在以下路径:
..\701n_watch_release_v2.X.X\code\sdk\cpu\br28\tools\UI工程
- doc:存放工具的相关说明文档
- UITools:存放相关的 UI 工具链
- 字库文件:主要是负责UI中多语言文字编码
- ui_454x454_watch:为 ui 工程主目录(新建 ui 工程需要参考该目录结构,也可以直接拷贝该文件夹,在该文件夹的基础上进行修改)
运行 UI 编辑工具,直接双击下图的”step1-打开 UI 绘图工具.bat”,通过脚本调用打开:
UI 编辑工具主界面如下图:
UI 编辑完成后,直接双击”资源编译”,生成相关的资源文件

4.2 UI 控件
4.2.1 控件的映射
杰理 UI 基本流程:下图为UI编译工具链的工作流程,UI工程=Json文件+资源文件,Json文件上记录了UI参数信息(位置、尺寸等等)和资源索引地址,我们从UI编辑工具上改UI最后无非就是修改了Json文件内的内容而已,当然我们从脚本打开UI编辑工具时是自动读取读取Json文件参数来呈现。

4.2.2 控件的响应
编译后,控件映射为SDK内的一个宏ID:
我们可以根据UI工具编译出的控件宏ID,给该控件注册一些响应逻辑,UI内核提供 3 种响应注册接口:
自己实现响应逻辑的接口,然后在代码里注册到UI内核,例如我在屏幕上触控某个UI控件,就会调用你给该控件注册的.ontouch接口。
注意:
在调用响应注册接口REGISTER_UI_EVENT_HANDLER 时,
必须在当前源文件定义#define STYLE_NAME JL,否则控件响应会注册失败且编译不会报错,
因为STYLE_NAME是REGISTER_UI_EVENT_HANDLER的隐含参数。
4.2.3 控件的属性
各类控件属性请参阅《UI控件结构体成员说明》:
UI控件结构体成员说明.pdf
每种控件都有自己的属性结构体(控件结构体 = 公共属性成员 + 私有属性成员)
比如文字控件的属性结构体定义在ui_text.h里面;
比如图片控件的属性结构体定义在ui_pic.h里面;
比如列表控件的属性结构体定义在ui_grid.h里面;
比如列表控件的属性结构体定义在ui_grid.h里面;
比如按键控件的属性结构体定义在ui_button.h里面;
...........其他控件 以此类推...........
举个例子🌰:按键控件
4.3 UI 消息类型

4.3.1 显示消息
注意:不要在onchange里面调用ui_XXX_by_id()、ui_show()、ui_hide(),这些接口会带有重绘(刷新)操作,因为onchange本身就会刷新,onchange里面调用重绘的接口会一直触发刷新(可能会导致卡顿死机)
建议:
1、想在onchange里面更新控件数据,用不带_by_id()后缀的接口,一般控件都会带有配套的接口;
2、想在onchange里面设置隐藏显示控件的话,编辑控件css属性里的invisible属性
(隐藏控件invisible = 1;显示控件invisible = 0;)
4.3.2 触摸消息
触控唤醒IO设置:
收发响应接口:
4.3.3 按键消息
控件默认不响应硬件按键,如果硬件按键想要操作UI,需要在硬件按键的公共事件处理里面接管,然后把按键消息转发到UI线程.onkey处理
①被控控件,需要在初始化阶段设置接管按键消息
②硬件按键公共事件处理,会先检测有没有想接管的UI控件
③完成以上步骤,.onkey响应接口才会接收到事件消息
4.4 UI 消息传递机制
详情参阅《消息流程》:消息流程
注意:显示消息的ON_CHANGE_INIT传递顺序有特殊调整:子控件》控件》布局》图层,其他显示消息不变。
4.8.1 焦点控件
什么是焦点控件?焦点控件就是获取到焦点的控件,焦点可以灵活地在控件上转移,且有且只有一个焦点控件。控件成为焦点控件后,UI内核传递消息直接传达且只传达到焦点控件上,不会再传递到其他控件上。
设置焦点控件有两种方式:
①在控件初始化阶段锁定焦点在本控件
②暂时接管,通过return true设置焦点,return false释放焦点
注意:特殊调整
- 显示类控件(文字、图片):默认不接收抬起事件,如要接收抬起事件,自行在down事件内return true;
- 按键控件:会自动设置为焦点控件
4.5 UI 接口
参考《UI接口设计说明书》:..\701n_watch_release_v2.X.X\doc\固件资料\UI
4.6 UI 字库
在杰理UI框架中,多国语言表用于系统标题、菜单标题等固定词条的多语言管理和显示,而字库用于短信、来电等文字的解析显示。
4.6.1 多国语言表
参阅《多国语言及字库使用指南》:多国语言及字库使用指南.otl
参阅《多国语言字库驱动使用说明》:..\701n_watch_release_v2.X.X\doc\固件资料\UI
4.6.2 字库制作
详情参阅《字模提取工具说明》:字模提取工具说明
4.6.3 字库裁剪
🚧待施工
4.7 UI工程工具
先把原来的UI工程复制一份,重命名
然后打开UI工程工具:

4.7.1 UI工程缩放
两个流程:工程尺寸的缩放、图标资源的缩放:
①工程尺寸的缩放:
②图标资源的缩放:
工程下的每个文件夹,都走一遍这两个流程!!!!!
操作完上面步骤后,每个文件夹里面的ui工程都先重新资源编译一遍,再重新烧录,才能生效。
4.7.2 其他功能说明
参阅《UI工程源文件工具使用》:UI工程源文件工具使用
参阅《UI工程源文件升级工具使用说明》:..\701n_watch_release_v2.X.X\doc\固件资料\UI
4.8 UI 进阶教程
4.8.1 自定义绘图
①自定义绘图接口
参考..\code\sdk\include_lib\system\ui_new\ui\ui.h
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_remove_backcolor 删除控件的背景颜色
*
* @param elm 待删除颜色的控件句柄
*/
/* ------------------------------------------------------------------------------------*/
void ui_remove_backcolor(struct element *elm);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_remove_backimage 删除控件的背景图
*
* @param elm 待删除背景图的控件句柄
*/
/* ------------------------------------------------------------------------------------*/
void ui_remove_backimage(struct element *elm);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_remove_border 删除控件的边框
*
* @param elm 待删除边框的控件句柄
*/
/* ------------------------------------------------------------------------------------*/
void ui_remove_border(struct element *elm);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_fill_rect ui填充矩形
*
* @param dc UI框架句柄
* @param left 矩形left坐标
* @param top 矩形top坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param acolor 填充颜色(带透明度)
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int ui_fill_rect(struct draw_context *dc, int left, int top, int width, int height, u32 acolor);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_image 自定义绘图方式显示图片
*
* @param dc 待显示的上下文句柄
* @param page 待显示图片所在页面
* @param id 待显示图片所在控件ID
* @param x 待显示图片将显示的X坐标
* @param y 待显示图片将显示的Y坐标
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int ui_draw_image(struct draw_context *dc, int page, int id, int x, int y);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_image_large 大图片截取显示
*
* @param dc 显示上下文
* @param page 页面号
* @param id 图片索引
* @param x 显示的X坐标(相对屏幕)
* @param y 显示的Y坐标(相对屏幕)
* @param width 显示宽度
* @param height 显示高度
* @param image_x 图片的X坐标(相对图片)
* @param image_y 图片的Y坐标(相对图片)
*
* @return -1 失败,0 正常
* @note 大图片显示具有尺寸限制,请留意工具或者代码提示信息
*/
/* ------------------------------------------------------------------------------------*/
int ui_draw_image_large(struct draw_context *dc, int page, int id, int x, int y, int width, int height, int image_x, int image_y);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_ascii 自定义合成ascii字符串显示
*
* @param dc 显示上下文
* @param str 字符串指针
* @param strlen 字符串长度
* @param x 字符串X坐标
* @param y 字符串Y坐标
* @param color 字符串显示颜色
*
* @return 0 正常,-1 失败
*/
/* ------------------------------------------------------------------------------------*/
int ui_draw_ascii(struct draw_context *dc, char *str, int strlen, int x, int y, int color);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_text 自定义显示字符串
*
* @param dc 显示上下文
* @param encode 编码格式
* @param endian 大小端
* @param str 字符串指针
* @param strlen 字符串长度
* @param x 显示X坐标
* @param y 显示Y坐标
* @param color 显示颜色
*
* @return 0 正常,-1 失败
*/
/* ------------------------------------------------------------------------------------*/
int ui_draw_text(struct draw_context *dc, int encode, int endian, char *str, int strlen, int x, int y, int color);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_strpic 显示多国语言excel表文本
*
* @param dc 显示上下文
* @param id 文本控件ID
* @param x 显示X坐标
* @param y 显示Y坐标
* @param color 文本颜色
*
* @return 0 正常,-1 失败
*/
/* ------------------------------------------------------------------------------------*/
int ui_draw_strpic(struct draw_context *dc, int id, int x, int y, int color);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_line 绘制直线
*
* @param _dc 显示上下文
* @param x0 直线起点X坐标
* @param y0 直线起点Y坐标
* @param x1 直线终点X坐标
* @param y1 直线终点Y坐标
* @param color 直线颜色
*/
/* ------------------------------------------------------------------------------------*/
void ui_draw_line(void *_dc, int x0, int y0, int x1, int y1, int color);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_line_by_angle 绘制指定角度的直线
*
* @param _dc 显示上下文
* @param x 直线起点X坐标
* @param y 直线起点Y坐标
* @param length 直线长度
* @param angle 直线角度
* @param color 直线颜色
*/
/* ------------------------------------------------------------------------------------*/
void ui_draw_line_by_angle(void *_dc, int x, int y, int length, int angle, int color);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_rect 绘制矩形填充
*
* @param _dc 显示上下文
* @param x 矩形左上角X坐标
* @param y 矩形左上角Y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param color 填充颜色
*/
/* ------------------------------------------------------------------------------------*/
void ui_draw_rect(void *_dc, int x, int y, int width, int height, int color);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_circle 绘制圆环
*
* @param dc 显示上下文
* @param center_x 圆环中心X坐标
* @param center_y 圆环中心Y坐标
* @param radius_big 圆环外径
* @param radius_small 圆环内径
* @param angle_begin 起始角度
* @param angle_end 结束角度
* @param color 圆环颜色
* @param percent 绘制百分比
*/
/* ------------------------------------------------------------------------------------*/
void ui_draw_circle(struct draw_context *dc, int center_x, int center_y,
int radius_big, int radius_small, int angle_begin,
int angle_end, int color, int percent);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_ring 绘制圆
*
* @param _dc 显示上下文
* @param x 圆心X坐标
* @param y 圆心Y坐标
* @param radius_big 圆形外径
* @param radius_small 圆形内径
* @param angle_begin 起始角度
* @param angle_end 结束角度
* @param color 颜色
* @param percent 绘制百分比
*/
/* ------------------------------------------------------------------------------------*/
void ui_draw_ring(void *_dc, int x, int y, int radius_big, int radius_small, int angle_begin, int angle_end, int color, int percent);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_bar 绘制水平进度条
*
* @param _dc 显示上下文句柄
* @param x 绘制的X坐标(左上角)
* @param y 绘制的Y坐标(右上角)
* @param width 绘制宽度
* @param height 绘制高度
* @param color 高亮颜色
* @param percent 高亮百分比
*/
/* ------------------------------------------------------------------------------------*/
void ui_draw_bar(void *_dc, int x, int y, int width, int height, int color, int percent);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_alpha_bar 透明度圆环
*
* @param _dc
* @param x
* @param y
* @param width
* @param height
* @param color
* @param percent (0-100)
* @param alpha (0-255)
*/
/* ------------------------------------------------------------------------------------*/
void ui_draw_alpha_bar(void *_dc, int x, int y, int width, int height, int color, int percent, int alpha);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_draw_get_mixed_pixel 颜色混合(ARGB565)
*
* @param backcolor 背景色
* @param forecolor 前景色
* @param alpha 透明度
*
* @return u16 混合后的颜色值
*/
/* ------------------------------------------------------------------------------------*/
u16 ui_draw_get_mixed_pixel(u16 backcolor, u16 forecolor, u8 alpha);
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_custom_draw_clear 清空自定义绘图
*
* @param dc 显示上下文
*/
/* ------------------------------------------------------------------------------------*/
void ui_custom_draw_clear(struct draw_context *dc);
②自定义绘图Demo
参考..\apps\watch\ui\lcd\STYLE_WATCH_NEW\ui_action_watch.c下的Demo:
static int DRAW_DEMO_onchange(void *_ctrl, enum element_change_event event, void *arg)
{
struct element *elm = (struct element *)_ctrl;
struct draw_context *dc = (struct draw_context *)arg;
struct rect rect = {0};
struct rect r = {0};
struct image_file f;
struct rect r1;
int angle;
int id;
int i;
switch (event) {
case ON_CHANGE_INIT:
break;
case ON_CHANGE_SHOW:
#if defined(TCFG_UI_ENABLE_DEMO) && TCFG_UI_ENABLE_DEMO
/*根据需要调用以下三个接口:ui_remove_backcolor,ui_remove_backimage,ui_remove_border*/
ui_remove_backcolor(elm);//移除控件背景颜色
ui_remove_backimage(elm);//移除控件背景图像
ui_remove_border(elm);//移除控件边界
#endif
break;
case ON_CHANGE_SHOW_POST:
#if defined(TCFG_UI_ENABLE_DEMO) && TCFG_UI_ENABLE_DEMO
ui_custom_draw_clear(dc);
ui_core_get_element_abs_rect(elm->dc->elm, &r); //跟随控件移动,注释掉这句则不跟随控件移动
ui_core_get_element_abs_rect(elm, &rect); //跟随控件移动,注释掉这句则不跟随控件移动
rect.left -= r.left;
rect.top -= r.top;
/*
* 以下绘图函数只能在该控件的范围内显示,超出控件区域不显示
* */
/* 矩形填充 */
ui_fill_rect(dc, 100, 100, 254, 254, 0xffff);
/* 指定角度画直线 */
for (angle = 0; angle <= 360; angle += 45) {
ui_draw_line_by_angle(dc, 227, 227, 100, angle, 0xf800);
}
/* 画矩形 */
ui_draw_rect(dc, 125, 125, 204, 204, 0xf800);
/* 画线段 */
ui_draw_line(dc, 120, 120, 333, 120, 0x07e0);
ui_draw_line(dc, 333, 120, 333, 333, 0x07e0);
ui_draw_line(dc, 333, 333, 120, 333, 0x07e0);
ui_draw_line(dc, 120, 333, 120, 120, 0x07e0);
/* 画圆 */
ui_draw_ring(dc, 227, 227, 102, 90, 0, 360, 0x003f, 100);
/* 画圆环 */
ui_draw_ring(dc, 227, 227, 117, 105, 0 + 135, 270 + 135, 0xc618, 100);
ui_draw_ring(dc, 227, 227, 117, 105, 0 + 135, 270 + 135, 0xf800, 75);
/* 画进度条 */
ui_draw_bar(dc, 120, 380, 200, 25, RGB565(58, 63, 72), 100);
ui_draw_bar(dc, 120, 380, 200, 25, 0xf800, 50);
/* 显示缓存叠加图片 */
ui_draw_custom_rgb565(dc, rect.left + 100, rect.top + 100, 48, 49, icon_48x49_rgb565, sizeof(icon_48x49_rgb565));
/* 显示缓存叠加图片(带alpha) */
ui_draw_custom_argb8565(dc, rect.left + 220, rect.top + 100, 48, 49, icon_48x49_argb8565, sizeof(icon_48x49_argb8565));
/* 显示图片id到指定坐标 */
id = PAGE17_3ec1_01_MENU_ICON_TRAINING_SEL_S5;
open_image_by_id(0, NULL, &f, id & 0xffff, id >> 16);
ui_draw_image(dc, id >> 16, id & 0xffff, (r.width - f.width) / 2, (r.height - f.height) / 2); //屏幕居中显示
/* 显示多国语言文本 */
ui_draw_strpic(dc, M26, 200, 280, RGB565(0, 0, 0));
/* 显示ascii文本 */
char *ascii = "0123456789";
ui_draw_ascii(dc, ascii, strlen(ascii), 200, 296, RGB565(255, 0, 0));
/* 显示字库文本 */
char *text = "字库文本测试";
ui_draw_text(dc, FONT_ENCODE_UTF8, 0, text, strlen(text), 200, 322, RGB565(255, 0, 0));
#endif
break;
case ON_CHANGE_RELEASE:
break;
default:
break;
}
return false;
}
问得比较多的案例:平角、圆角柱形
平角柱状用矩形填充
/* ------------------------------------------------------------------------------------*/
/**
* @brief ui_fill_rect ui填充矩形
*
* @param dc UI框架句柄
* @param left 矩形left坐标
* @param top 矩形top坐标
* @param width 矩形宽度
* @param height 矩形高度
* @param acolor 填充颜色(带透明度)
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int ui_fill_rect(struct draw_context *dc, int left, int top, int width, int height, u32 acolor);
圆角柱状用进度条模拟
• * @param _dc 显示上下文句柄
• * @param x 绘制的X坐标(左上角)
• * @param y 绘制的Y坐标(右上角)
• * @param width 绘制宽度
• * @param height 绘制高度
• * @param color 高亮颜色
• * @param percent 高亮百分比
void ui_draw_bar(void *_dc, int x, int y, int width, int height, int color, int percent);
可以用画进度条的ui_draw_bar来实现,只要把进度条参数percent固定设置为100%(完全填充),width和height就是矩形的宽高。
4.8.2 表盘制作
①新增表盘工程
②表盘新增控件
想做纯数字时钟表盘?表盘上新增控件显示运动参数?往下看:
表盘工程有点特殊,特殊在哪里?
现在的SDK对所有表盘工程,都是公用同一套响应代码逻辑,也就是说你现在可以看到每个表盘工程的ID都是公用的,比如下图:
现在教你如何正确在表盘工程上DIY控件!
我们在自定义表盘的过程中,除了共用响应逻辑的控件可以同名(如),其他DIY的控件可能会有命名冲突,因此我们在表盘工程新增控件时,不能用控件ID,用控件数据源名称,来对不同表盘工程下的控件进行响应注册
举个例子🌰:如我想在一个表盘上单独添加一个控件,注册自己的onchange响应

其他onkey、ontouch响应同理
③表盘APP传输
【金山文档】杰理表盘制作和上传服务器
【金山文档】表盘传输APP层的压缩算法
APP自定义流程
【金山文档】 app自定义表盘背景流程说明
APP下发和固件端显示流程
【金山文档】自定义表盘的背景图和预览图(APP传输图片、固件显示)
4.8.3 页面回退管理
UI开发过程中,通常会用到页面回退,相关代码逻辑主要在lcd_ui_return_page.c
页面回退管理的数据结构模拟栈结构,前进=压栈,回退=弹栈
普通页面和抢断页面,分开不同的两个栈进行管理,接口也分开两套:
普通页面翻页记录在page_return_tab数组内
抢断页面翻页记录在page_preemption数组内
//普通页面
//压栈:用于处理页面返回时,返回的页面存储在page_return_tab
#define UI_WINDOW_BACK_PUSH(a) ui_return_page_push(a)
//弹栈:用于处理当前页面左右滑动时是返回上一级页面还是直接滑屏切换页面
#define UI_WINDOW_BACK_SHOW(a) ui_return_page_pop(a)
//用于处理当前页面左右滑动时是返回上一级页面还是直接滑屏切换页面
#define UI_WINDOW_BACK_SPEC_SHOW(a) ui_return_page_pop_spec(a)
//用于清除页面返回记录
#define UI_WINDOW_BACK_CLEAN() ui_return_page_clear()
//用于从page_return_tab表中回退1
#define UI_WINDOW_BACK_SUB() ui_return_page_sub()
//用于获取当前page_return_tab索引值
#define UI_WINDOW_BACK_INDEX() get_return_index()
//用于删除页面返回记录
#define UI_WINDOW_BACK_DEL(a) ui_return_page_del(a)
//抢断页面
#define UI_WINDOW_PREEMPTION_POSH(a,b,c,d) ui_preemption_page_push(a,b,c,d)
#define UI_WINDOW_PREEMPTION_POP(a) ui_preemption_page_pop(a)
#define UI_WINDOW_PREEMPTION_DEL(a) ui_preemption_page_del(a)
#define UI_WINDOW_PREEMPTION_CHECK() ui_preemption_page_check()
4.8.4 特效
参考《AC701n_UI特效使用简介》和《AC701N旋转缩放接口使用说明》:..\701n_watch_release_v2.X.X\doc\固件资料\UI
4.8.5 2D图像硬件加速
参考《AC701N 2D图形硬件加速接口》:..\701n_watch_release_v2.X.X\doc\固件资料\UI
4.9 UI FAQ(常见问题处理方案)
参阅《JL701N穿戴客述问题FAQ》:JL701N穿戴客述问题FAQ
参阅《UI开发常见问题及处理方法》:UI开发常见问题及处理方法
五、OTA相关
欢迎使用杰理OTA升级(iOS)开发说明 — 杰理OTA升级开发文档(iOS) v2.0.0 文档
欢迎使用杰理OTA外接库开发文档(Android) — 杰理OTA外接库开发文档(Android) 1.6.0 documentation
欢迎使用杰理OTA外接库开发文档(微信小程序) — 杰理OTA外接库开发文档(微信小程序) 1.0.0 documentation

