BR1601Axx
BR1601A02 Mesh SDK说明
BR1601A02 Mesh应用笔记
BR1601A/Bxx资料汇总
-
+
home
BR1601A02 Mesh SDK说明
# 1. 概述 ## 1.1. SDK简介 - 功能与定位 此sdk为用户提供了灯控例程与外设例程,便于客户快速上手使用。 - 灯控例程 - Light_CTL(可调冷暖灯控) - Light_HSL(可调彩色灯控) - Light_Lightness(可调亮度灯控) ## 1.2. 版本信息 | 版本 | 日期 | 说明 | 作者 | | --- | --- | --- | --- | | v1.0 | 2026-5-12 |首次发布 |Tianlx | # 2. 快速上手 ## 2.1. 开发环境搭建 - 编译工具链安装 编译需安装Keil MDK,推荐版本v5.27。 - 下载工具安装 下载需安装JLink软件,并准备Jlink V9下载工具。 - 开发板 可使用BR1601A02柠檬开发板或i2616e模块。 - 串口工具 准备USB转TTL板,便于查看日志。 ## 2.2. 目录结构说明 | 目录 | 相对路径 | | --- | --- | | 说明文档 | \doc\ | | 灯控例程 | \examples\mesh\ | | 外设例程|\examples\peripheral\ | | 头文件|\libraries\include\ | | 库文件 |\libraries\lib\ | | 外设驱动 | \platform\br1601axx_driver\ | | 公共文件 | \platform\common\ | | 平台文件|\platform\system_core\ | | 工具目录 | \tools\ | ## 2.3. 第一个例程运行 ### 2.3.1. 例程编译 安装KEIL后,点击例程"light_lightness\MDK-ARM\mesh.uvprojx"工程文件  编译  ### 2.3.2. 烧录设置 - 烧录算法复制 将烧录算法"\tools\dfu\JLink\JLink_V632\Devices\Barrot\BR1601.FLM" 复制到Keil的目录"\Keil_v5\ARM\Flash\\" - 烧录配置   点击Add添加BR1601.FLM烧录算法文件,位置在\Keil_v5\ARM\Flash\  - 烧录接线  | 信号 | 接线 | | --- | --- | | VDD | 3.3V--JLINK PIN 1 | | PA4 | DIO--JLINK PIN7 | | PA5 | CLK--JLINK PIN9 | | GND | 地线--JLINK PIN4 | | RESET | 复位--JLINK PIN13 | >i **信息提示** > > 柠檬开发板有专门连接器将下载口引出。 > 使用i2616e模块,请查阅规格书中引脚序号。 - 组网控制 设备名为MESH_XXXX,使用Mesh APP或小程序对设备进行组网。 - 日志查看 日志引脚位于PB12,波特率912600,使用串口工具查看。 ``` 参考日志 Barrot SIG-MESH Demo Built:May 12 2026,17:11:48 lib:MESH_V1.1_0000_260422_r6030 [INF][main][Line:97] opt3 mac: 30 6C 78 41 50 34 0lxAP4 [6 bytes] mac:34 50 41 78 6C 30 Startup [INF][app_mesh][Line:169] mesh app init start [INF][app_mesh][Line:174] no uuid set,use default uuid [INF][app_mesh][Line:177] uuid: 20 55 AA 83 04 05 06 07 08 09 30 6C 78 41 50 34 U........0lxAP4 [16 bytes] [INF][app_mesh][Line:181] no name set,use default name [INF][app_mesh][Line:193] NAME:MESH_6C30 ``` # 3. 例程功能说明 ## 3.1 Light_Lightness 例程 * 简介 此例程提供单路亮度控制(PWM)输出。 * 核心的模型 * Lightness_server * Lightness_setup * Generic Onoff Client * Vendor Model * 输入信号 * 按键PB1,PB2发送开关灯指令 >i **信息提示** > > 默认低电平有效,引脚带上拉能力。 * 输出信号 * PWM输出PB4 * 使能信号输出PA6 * 状态指示PB11 >i **信息提示** > PWM输出,默认低电平有效 > 使能信号,默认低电平有效 > 状态指示,默认高电平有效 > 输出信号,极性独立可配置。 ## 3.2 Light_CTL 例程 * 简介 此例程提供可调双色(冷暖)灯控制功能。 * 核心的模型 * Lightness_CTL_Server * Lightness_CTL_Setup_Server * Lightness_CTL_CV_Delta_server * Lightness_Temperature_Setup_Server * Lightness_Temperature_Server * Lightness_Lightness_Server * Generic Onoff Client * Vendor Model * 输入信号 * 按键PB1,PB2 * 输出信号 * PWM输出PB4(接冷光灯) * PWM输出PB5(接暖光灯) * 使能信号输出PA6 * 状态指示PB11 ## 3.3 Light_HSL 例程 * 简介 此例程提供可调彩色(RGB)灯控制功能。 * 支持的模型 * lightness_hsl_server * lightness_hsl_setup * lightness_hue_server * lightness_saturation_setup * lightness_temperature * lightness_lightness_server * Generic Onoff Client * Vendor Model * 输入信号 * 按键PB1,PB2 * 输出信号 * 红灯PWM输出PB10(Red) * 绿灯PWM输出PB3(Green) * 蓝灯PWM输出PB0(Blue) * 使能信号输出PA6 * 状态指示PB11 # 5. 例程代码说明 以Light_lightness为例,详细说明代码。 ## 5.1 初始化流程图 ```mermaid sequenceDiagram main->>main:log_init(921600); main->>cm_backtrace:cm_backtrace_init(); main->>co_flash:co_flash_init(); main->>ble_lib: get_mac(mac) main->>ble_lib: cs_init(mac) main->>app_mesh: app_mesh_init() main->>app_button: app_usart_init() main->>app_button: app_button_init() main->>app_button: app_light_init() ``` ### 5.1.1 log_init() 输入目标波特率,初始化日志输出串口。 >w **警告提示** > > 由于系统中用到日志输出,因此不可删除。 > 建议用高波特率输出,比如921600。 - 日志原始打印函数 co_printf(fmt*,...); 类似printf功能。 >i **信息提示** > > `co_printf()`的缓冲区大小默认为1024,可在co_printf.c中调整。 > `static uint8_t s_dbg_tmp_buf[1024];` ### 5.1.2 cm_backtrace_init() 异常诊断初始化,当系统出现Hardfault时,cm_backtrace会打印CPU寄存器信息,供开发者分析。 ```C extern void (*user_HardFault_Handler)(void); user_HardFault_Handler = user_hardfault; cm_backtrace_init("APP", "Hardware", (const char *)mesh_lib_version); ``` 诊断问题时,复制打印的信息,将工程中编译生成的APP.dxf提取出来,按提示运行脚本调用工具分析。 ### 5.1.2 get_mac() 从芯片中读取蓝牙地址。 >i **信息提示** > > 读出结果低位在前,高位在后。 > 通常APP显示蓝牙地址是高位在前,低位在后。 ### 5.1.3 cs_init() 初始化蓝牙控制器,此函数输入MAC地址。 ### 5.1.3 app_mesh_init() 初始化mesh协议栈。 ### 5.1.4 app_light_init() 初始化输出使能、状态指示、PWM。 ### 5.1.5 app_button_init() (可选)初始化按键检测。 ### 5.1.4 app_usart_init() (可选)初始化指令串口。 ## 5.2 主循环 ```C while(1) { cs_schedule();//蓝牙协议栈事务处理函数 ....//其他应用层需要的处理函数 app_button_handle();//按键事务处理 app_uart_data();//串口数据处理 app_pwm_trans_handle();//灯光渐变刷新 } ``` >w **警告提示** > > while(1)中的函数及其调用的函数,避免阻塞式运行,这样会影响蓝牙的工作。 ## 5.3 事件回调 ### 5.3.1 应用层事件 - 入口`void mesh_event_callback()` 根据事件选择参数类型。 ``` void mesh_event_callback(tMESH_EVENT mesh_ev, void *p_arg) { union { void *pany; tMESH_RESULT *presult; tMESH_LightStateStru *plight_state; tMESH_AccessPduRecvStru *pdu_info; //添加其他类型 } pars; pars.pany = p_arg; switch (mesh_ev) { case MESHG_EV_INIT_DONE: mesh_app_init(mac); mesh_dev_state.ready = true; break; ``` >w **警告提示** > > 此函数中不可对p_arg进行内存释放! ### 5.3.2 事件定义 ``` tMESH_EVENT typedef enum { MESHG_EV_INIT_DONE, //parameter: NONE. MESHG_EV_GATT_CONNECTED, //parameter: NONE. MESHG_EV_GATT_DISCONNECTED, //parameter: NONE. MESHP_EV_PROVISIONING_START, //parameter: NONE. MESHP_EV_PROVISIONING_COMPLETE, //parameter: (tMESH_RESULT *). MESHP_EV_UNPROVISIONED, //Node is removed from the mesh network. parameter: NONE. MESHM_EV_LIGHT_STATE_CHANGED, //Remote client requires to change the light state(s). parameter: (tMESH_LightStateStru *). MESHM_EV_ALERTING, //Alert the user by beeping or flashing for a short while. parameter: NONE. MESHP_EV_AUTHEN_USER_ALPHANUMERIC_PROMPT, //During provisioing authentication stage, display alphanumeric string to be input on the peer. parameter: null terminated string. MESHP_EV_AUTHEN_USER_ACTION_PROMPT, //During provisioing authentication stage, produce the specified number of beep, blink or vibrations. parameter: UINT8 *number. MESHP_EV_AUTHEN_USER_PROMPT_STOP, //During provisioing authentication stage, stop displaying user prompt to take action on the peer. parameter: NONE. MESHP_EV_AUTHEN_USER_INPUT_REQUIRED, //During provisioing authentication stage, notify the user to take input action according the output status of the peer. parameter: NONE. MESHLP_EV_FRIEND_ESTABLISHED, MESHLP_EV_FRIEND_LOST, MESHM_EV_ACCESS_PDU_RECEIVED, //Access layer PDU received. parameter: (tMESH_AccessPduRecvStru *). MESH_EV_NONE = 0xFFFF } tMESH_EVENT, tBT_GapEvEnum; ``` - 关键事件说明 - MESHG_EV_INIT_DONE 蓝牙协议栈就绪,此处做mesh应用层初始化,即`mesh_app_init()` - MESHG_EV_GATT_CONNECTED/MESHG_EV_GATT_DISCONNECTED 蓝牙proxy被连接/断开 - MESHP_EV_UNPROVISIONED Mesh退出组网(主动或被动) - MESHM_EV_LIGHT_STATE_CHANGED Mesh节点灯控状态发生改变 - MESHM_EV_ACCESS_PDU_RECEIVED Mesh节点收到消息(用于充当网关) ### 5.3.3 状态改变报告 - 连接状态改变 ```C case MESHG_EV_GATT_CONNECTED: IOT_LOG_INF("CONNECTED"); mesh_dev_state.connected = true;//改变状态描述变量 app_status_led(EVT_CONNECTED);//状态指示灯切换模式 break; ``` - 灯光状态改变 ``` case MESHM_EV_LIGHT_STATE_CHANGED:/* p_arg: tMESH_LightStateStru* */ { if(pars.plight_state->light_on) { if(pars.plight_state->st_changed_flag & APK_LIGHT_STV_LIGHTNESSS) { app_pwm_cold_set(pars.plight_state->lightness);//lightness actual->linear app_light_output_enable(true); }else{ //choose the pwm correspond with light id app_pwm_cold_set(0); app_light_output_enable(false); } break; ``` 如果灯为开启状态,当亮度发生改变,则更新PWM值。 如果灯为熄灭状态,则PWM置为0,关灯,使能信号关闭。 >i **信息提示** > > 有些灯驱动器需要使能信号,`LIGHT_ENABLE_PIN`充当使能信号,其极性可配置。 ## 5.4 Mesh基础参数 以下内容参考app_mesh.c中`app_mesh_init()`。 ### 5.4.1 Device UUID 此UUID为16字节,由应用定义,用于识别此Mesh设备,一些物联接入规范会定义此内容,代码中的定义方式为: ``` //UUID shall be able to uniquely identify the device. The value used here is for demo only. tMESH_NodeInfoStru node_info = {APK_MESH_ROLE_LPN, {0x20, 0x55, 0xAA, 0x83, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x3f}}; if(!app_data_mesh_uuid(node_info.uuid, OP_READ))//从存储中加载 { memcpy(node_info.uuid+10,addr,6);//fix me IOT_LOG_INF("no uuid set,use default uuid"); } ``` ### 5.4.2 Mesh Name 蓝牙名称,位于扫描响应数据中,长度不超过28字节。 默认名称为MESH_XXXX或LPN_XXXX。 ``` if(!app_data_mesh_name(node_info.name, OP_READ)) { IOT_LOG_INF("no name set,use default name"); #ifdef LPN node_info.role = APK_MESH_ROLE_LPN; //create proxy scan response name for demo sprintf(node_info.name,"LPN_%02X%02X",addr[1],addr[0]); #else //create proxy scan response name for demo sprintf(node_info.name,"MESH_%02X%02X",addr[1],addr[0]);//mac address LSB->MSB node_info.role = APK_MESH_ROLE_RELAY; #endif } ``` ### 5.4.2 Mesh Features - APK_MESH_ROLE_LPN - APK_MESH_ROLE_RELAY 在`node_info.role = APK_MESH_ROLE_RELAY`中设置 ## 5.5 日志相关 ### 5.5.1 添加头部信息 请在文件中添加如下内容: ```C /* Log domain name */ #ifndef LOG_EX_HEAD #define LOG_EX_HEAD "module" #endif #define IOT_LOG_EX_LEVEL IOT_LOG_EX_LEVEL_DEBUG //default log level #include "iot_log_ex.h" ``` ### 5.5.2 日志级别 改变`IOT_LOG_EX_LEVEL`来实现不同级别的日志输出。 ```日志级别 #define IOT_LOG_EX_LEVEL_OFF 0 #define IOT_LOG_EX_LEVEL_ERROR 1 #define IOT_LOG_EX_LEVEL_WARNING 2 #define IOT_LOG_EX_LEVEL_INFO 3 #define IOT_LOG_EX_LEVEL_DEBUG 4 #define IOT_LOG_EX_LEVEL_VERBOSE 5 ``` ### 5.5.3 日志打印 ```C IOT_LOG_INF(format, ...)//类似co_printf,带"\r\n" IOT_LOG_INF_ARRAY(array, len)//顺序打印数组 IOT_LOG_INF_ARRAY_EX(note, array, len)//顺序打印数组带说明 IOT_LOG_INF_ARRAY_ANTI(array, len)//倒序打印数组 IOT_LOG_INF_ARRAY_ANTI_EX(note, array, len)//倒序打印数组带说明 IOT_LOG_INF_FUNC()//打印宏所在的函数 IOT_LOG_INF_NULL()//打印"\r\n"回车换行 ``` ### 5.5.4 日志模块整体配置 ```C #define CONFIG_LOG_EX_OUTPUT //全局开关日志模块 #define CONFIG_LOG_EX_LINE_OUTPUT 1//使能日志行输出 #define CONFIG_LOG_EX_ARRAY_EXT 1//使能打印数组的同时打印其中的可显示字符 ``` ### 5.5.5 日志初始化 在`main()`函数中尽早初始化`log_init(921600);` - 输出串口 PB12,无特殊情况,请不必修改。 ### 5.5.6 使用示例 ```C IOT_LOG_INF("test_timer:%d",ev); IOT_LOG_INF_ARRAY_EX("uuid",node_info.uuid,16); ``` # 6. 组件说明 | 组件| 名称 | | --- | --- | | app_data | 应用层非易失性数据存储管理 | | app_usart | 串口收发管理 | | app_pwm | 输出信号管理| | app_button | 按键识别管理 | ## 6.1 app_data 如需扩展参考app_data.c,流程如下: ### 6.1.1 容量检查 检查co_flash最大容量 `#define SECTOR_BLOCK_NUM 32`位于co_flash.c中,表示最大支持32条记录。 >w **警告提示** > SECTOR_BLOCK_NUM > 根据实际需要而调整,避免不必要的内存消耗。 > 当前mesh stack占据了9个地址。 ### 6.1.2 定义存储数据标签 位于co_flash_address.h中 ```C typedef enum { VADDR_PWR_ON = 100, VADDR_MESH_UUID, VADDR_MESH_NAME, VADDR_MESH_LPN, VADDR_MESH_OPOL, }app_v_addr_t; ``` >w **警告提示** > > 尽量是往后增加,尤其是产品发布后。 > 地址范围1-254 ### 6.1.3 定义存储结构 ```C typedef struct app_data_x { uint16_t adv_interval; uint16_t repeat_times; }app_data_x_t; ``` ### 6.1.4 添加读取写方法 ```C bool app_data_x(app_data_x_t *p,op_t op) { if(p == NULL) return false; bool ret; if(op == OP_WRITE) { ret = co_flash_write(VADDR_MESH_LPN, (uint8_t*)p, sizeof(app_misc_t)); } else { ret = co_flash_read(VADDR_MESH_LPN, (uint8_t*)p, sizeof(app_misc_t)); } return ret; } ``` ### 6.1.5 初始化方法(可选) ```C void app_data_x_init(app_data_x_t *p) { if(p) { p->adv_interval = DEFAULT_ADV_INTERVAL; p->repeat_times = DEFAULT_REPEAT_TIMES; } } ``` ### 6.1.6 清空操作 ```C void app_data_delete(void) { co_flash_erase(VADDR_MESH_X); } ``` >i **信息提示** > > app_data.c基于co_flash.c,使用接口函数的位置确保在co_flash_init()被调用后。 ## 6.2 app_pwm app_pwm模块封装了定时器TIM1,TIM3定时器pwm输出功能,同时初始化状态指示灯与输出使能,加载IO极性参数。 ### 6.2.1 接口简介 - void app_light_init(void);//初始化状态指示,输出使能,PWM - void app_pwm_status_led(bool on);//状态指示开关 - void app_pwm_status_led_toogle(void);//状态指示翻转 - void app_light_output_enable(bool on);//输出使能控制 - void app_pwm_cw_set(uint16_t c);//带渐变的PWM输出,uint16_t c表示0-65535对应0-100% - void app_pwm_cold_set_duty(uint8_t duty);//带渐变的PWM输出,uint8_t c表示0-100对应0-100% - void app_pwm_rgb_set(uint16_t rgb[3]);//带渐变的PWM输出,输入顺序R,G,B - void app_pwm_trans_handle(void);//渐变调光函数。 ### 6.2.2 PWM输出通道 | 引脚 | 通道 | 功能 | | --- | --- | --- | | PB4 | TIM3_CH1 | cold led(CTL例程)/Lightness例程 | | PB5 | TIM3_CH2 | warm led(CTL例程) | | PB10 | TIM1_CH3 | red led(HSL例程) | | PB3 | TIM1_CH4 | green led(HSL例程) | | PB0 | TIM1_CH1 | blue led(HSL例程) | ### 6.2.3 GPIO输出通道 | 引脚 | 通道 | 功能 | | --- | --- | --- | | PA6 | GPIO | enable pin | | PB11 | GPIO | status led | ### 6.2.4 PWM波频率 `#define PWM_FREQ (4000-1) //4000HZ`位于app_pwm.c ### 6.2.5 输出极性 `static uint8_t iopol = APP_IO_POL_DEFAULT;` APP_IO_POL_DEFAULT 位于 app_user_config.h ```C #define ACTIVE_LEVEL_CW 1 //active high #define ACTIVE_LEVEL_RGB 1 //active high #define ACTIVE_LEVEL_LIGHT_EN 1 //active high #define ACTIVE_LEVEL_STATUS_LED 1 //active high ``` 举例,通过app_light_init()加载 ```C void app_light_init(void) { if(!app_data_output_pol(&iopol, OP_READ)) { IOT_LOG_DBG("no io polarity,use default"); } IOT_LOG_DBG("io polarity:%x",iopol); LedInit(LIGHT_ENABLE_PORT,LIGHT_ENABLE_PIN);// power led LedInit(STATUS_LED_PORT,STATUS_LED_PIN);//connection state app_light_output_enable(false); app_pwm_status_led(false); app_pwm_cw_init(); app_pwm_rgb_init(); app_pwm_cw_enable(true); app_pwm_rgb_enable(true); } ``` ## 6.3 app_button ### 6.3.1 简介 app_button.h 和 app_button.c 是负责按键处理的模块,它实现了按键的初始化、中断处理、防抖、状态检测和事件上报功能。该模块支持两个独立按键(KEY1和KEY2),并能识别按下、松开和长按三种事件类型。 - 关键配置参数 | 参数 | 宏定义 | 默认值 | 说明 | |------|--------|--------|------| | 按键有效电平 | KEY_ACTIVE_LEVEL | 0 | 低电平有效 | | 长按判定时间 | KEY_LONG_PRESS_TIME | 3000ms | 长按触发时间 | | 扫描周期 | KEY_SCAN_INTERVAL | 50ms | 按键扫描间隔 | | 防抖时间 | KEY_DEBOUNCE_TIME | 50ms | 按键防抖时间 | - 引脚对应表 | 引脚 | 通道 | 功能 | | --- | --- | --- | | PB1 | GPIO | KEY1 | | PB2 | GPIO | KEY2 | - 硬件配置 ```C // 按键1配置 #define KEY1_INPUT_PORT GPIOB #define KEY1_INPUT_PIN GPIO_PIN_1 #define KEY1_INPUT_EXTI_LINE EXTI_LINE1 #define KEY1_INPUT_PORT_SOURCE GPIOB_PORT_SOURCE #define KEY1_INPUT_PIN_SOURCE GPIO_PIN_SOURCE1 #define KEY1_INPUT_IRQn EXTI0_1_IRQn // 按键2配置 #define KEY2_INPUT_PORT GPIOB #define KEY2_INPUT_PIN GPIO_PIN_2 #define KEY2_INPUT_EXTI_LINE EXTI_LINE2 #define KEY2_INPUT_PORT_SOURCE GPIOB_PORT_SOURCE #define KEY2_INPUT_PIN_SOURCE GPIO_PIN_SOURCE2 #define KEY2_INPUT_IRQn EXTI2_3_IRQn ``` >i **信息提示** > > 修改按键映射要结合BR1601A02《用户手册》来确定中断线与中断向量。 ### 6.3.2 代码说明 - 按键状态枚举 ```C typedef enum { KEY_STATE_IDLE, // 空闲(未按下) KEY_STATE_PRESSED, // 已按下(防抖后确认) KEY_STATE_LONG_PRESSED // 长按(达到长按时间) } KeyState; ``` - 初始化函数 ```C void app_button_init(key_event_cb_t *p_cb); ``` **功能**:初始化按键模块,配置GPIO、EXTI和NVIC **参数**: `p_cb`:按键事件回调函数指针 - 按键事务处理函数 ```C void app_button_handle(void); ``` **功能**:检测按键中断标志,必要时启动扫描定时器 **调用时机**:通常在主循环中定期调用 - 事件上报回调函数 ```c static void key_event_report(uint8_t key_idx, uint8_t event); ``` **功能**:将按键事件通过回调函数异步上报给应用层 **参数**: `key_idx`:按键索引(0:KEY1, 1:KEY2) `event`:按键事件类型(KEY_EVENT_PRESS/RELEASE/LONG_PRESS) - 中断处理函数 ```c void xEXTI0_1_IRQHandler(void); // KEY1中断处理 void xEXTI2_3_IRQHandler(void); // KEY2中断处理 ``` - 使用示例 ```c // 按键事件回调函数 static void app_key_event_handler(void* fi, uint8_t evt, void *para) { uint8_t key_id = evt & 0xF0; uint8_t event = evt & 0x0F; switch(key_id) { case KEY1: if(event == KEY_EVENT_PRESS) { // 处理KEY1按下事件 } else if(event == KEY_EVENT_RELEASE) { // 处理KEY1松开事件 } else if(event == KEY_EVENT_LONG_PRESS) { // 处理KEY1长按事件 } break; case KEY2: // 类似处理KEY2事件 break; } } ``` ```C // 初始化按键模块 app_button_init(app_key_event_handler); // 在主循环中处理按键 while(1) { app_button_handle(); // 其他任务... } ``` ## 6.4 app_uart app_usart.h 和 app_usart.c 是串口通信的模块,实现了基于 USART1的异步串口通信功能。 >i **信息提示** > > 此示例供用户参考与测试。 ### 6.4.1 核心数据结构 - **事件类型枚举** ```c typedef enum { USART_EVT_SEND_CMPL, // 发送完成事件 } usart_evt_t; ``` - **回调函数类型** ```c typedef void (usart_evt_cbk_t)(uint8_t evt, void* arg); // 事件回调函数类型 typedef void (usart_data_cbk_t)(uint8_t* data, uint32_t len); // 数据接收回调函数类型 ``` ### 6.4.2. 主要函数说明 - **初始化函数** ```c void app_usart_init(usart_evt_cbk_t *evt_cbk, usart_data_cbk_t *data_cbk); ``` **功能**:初始化串口模块,配置 GPIO、DMA、NVIC 和 USART 参数 **参数**:`evt_cbk`:事件回调函数指针(如发送完成) `data_cbk`:数据接收回调函数指针 - **去初始化函数** ```c void app_usart_deinit(void); ``` **功能**:禁用串口和 DMA,配置 GPIO 为模拟输入以节省功耗 **调用时机**:不需要串口通信时调用 - **同步发送函数** ```c bool app_usart_send(const uint8_t *p_data, uint32_t len); ``` **功能**:使用轮询方式发送数据 **参数**: `p_data`:要发送的数据指针 `len`:数据长度 **返回值**:发送成功返回 true,发送失败(如正在发送中)返回 false - **异步发送函数** ```c bool app_usart_send_async(const uint8_t *p_data, uint32_t len); ``` **功能**:使用 DMA 异步发送数据 **参数**: `p_data`:要发送的数据指针 `len`:数据长度 **返回值**:发送成功返回 true,发送失败(如正在发送中)返回 false ### 6.4.3. 硬件配置 - **USART1**:波特率 115200,8 位数据位,1 位停止位,无校验 - **GPIO**: - TX:GPIOB_PIN_6,复用功能推挽输出 - RX:GPIOB_PIN_7,复用功能推挽输出 - **DMA**: - 发送:DMA_CH1,非循环模式,内存到外设 - 接收:DMA_CH2,循环模式,外设到内存,缓冲区大小 128 字节 ### 6.4.4. 数据发送流程 同步发送:app_usart_send() → 轮询发送标志 → 逐个字节发送 异步发送:app_usart_send_async() → 配置DMA参数 → 启动DMA发送 → DMA发送完成中断 → 调用发送完成回调 ### 6.4.5. 数据接收流程 数据到达 → USART RX DMA 接收 → 接收半满或完成中断 / 空闲中断 → app_usart_rx_check_in_irq() → 计算数据长度 → 调用数据接收回调 ### 6.4.6. 硬件配置宏 ```c #define USART_RX_DMA_SIZE 128 // DMA 接收缓冲区大小 #define USARTx USART1 // 使用的 USART 实例 // GPIO 和 DMA 相关配置... ``` ### 6.4.7. 应用层使用示例 ```c // 发送完成事件回调 static void usart_evt_handler(uint8_t evt, void* arg) { if (evt == USART_EVT_SEND_CMPL) { // 处理发送完成事件 } } // 数据接收回调 static void usart_data_handler(uint8_t* data, uint32_t len) { // 处理接收到的数据 // 注意:此函数在中断上下文中调用,应避免执行耗时操作 } // 初始化串口 app_usart_init(usart_evt_handler, usart_data_handler); // 同步发送数据 uint8_t send_data[] = "Hello, UART!"; app_usart_send(send_data, sizeof(send_data)); // 异步发送数据 app_usart_send_async(send_data, sizeof(send_data)); // 不再使用串口时去初始化 app_usart_deinit(); ``` ## 6.5 co_flash co_flash 是一个基于块管理的 Flash 存储系统,实现了高效、可靠的非易失性数据存储功能。该模块采用双扇区交替存储机制,支持虚拟地址映射、CRC 校验等功能,为嵌入式存储提供小尺寸,高效,可靠的存储管理功能。 co_flash 操作两个主数据扇区(SECTOR0: 0x7E000, SECTOR1: 0x7F000)交替使用。 >w **警告提示** > > mesh stack也有数据存储在此区域,不可随意将所有数据全部擦除。 ### 6.5.1. 主要 API 函数 - **初始化与去初始化** ```c bool co_flash_init(void); ``` **功能**:初始化 Flash 系统,检测并加载映射表 **返回值**:初始化成功返回 true,失败返回 false - **数据读写操作** ```c bool co_flash_write(uint8_t address, uint8_t* p_data, uint32_t len); ``` **功能**:向指定虚拟地址写入数据 **参数**: `address`:8 位虚拟地址(0x00-0xFF) `p_data`:要写入的数据指针 `len`:数据长度(最大支持 256 字节) **返回值**:写入成功返回 true,失败返回 false ```c bool co_flash_read(uint8_t address, uint8_t* p_data, uint32_t len); ``` **功能**:从指定虚拟地址读取数据 **参数**: `address`:8 位虚拟地址(0x00-0xFF) `p_data`:存储读取数据的缓冲区指针 `len`:要读取的数据长度 **返回值**:读取成功返回 true,失败返回 false ```c uint32_t co_flash_get_len(uint8_t virt_addr); ``` **功能**:获取指定虚拟地址存储的数据长度 **参数**: `virt_addr`:8 位虚拟地址 **返回值**:数据长度,若地址无效返回 0 - **数据擦除操作** ```c bool co_flash_erase(uint8_t address); ``` **功能**:擦除指定虚拟地址的数据 **参数**: `address`:8 位虚拟地址 **返回值**:擦除成功返回 true,失败返回 false ### 6.5.2. 使用示例 - **基本读写操作** ```c #include "co_flash.h" // 定义虚拟地址 #define MY_DATA_ADDR 0x01 void flash_example(void) { uint8_t write_data[] = "Hello, Flash!"; uint8_t read_data[32] = {0}; uint32_t data_len; // 初始化 Flash 系统 if (co_flash_init() != true) { // 初始化失败处理 return; } // 写入数据 if (co_flash_write(MY_DATA_ADDR, write_data, sizeof(write_data)) != true) { // 写入失败处理 return; } // 获取数据长度 data_len = co_flash_get_len(MY_DATA_ADDR); // 读取数据 if (co_flash_read(MY_DATA_ADDR, read_data, data_len) != true) { // 读取失败处理 return; } // 使用读取的数据 // ... // 擦除数据(可选) co_flash_erase(MY_DATA_ADDR); } ``` ## 6.6 sdk_mesh ### 6.6.1. 简介 sdk_mesh 提供了Mesh 协议栈封装和应用层接口,支持多种照明模型(Light Lightness、Light CTL、Light HSL)。该模块负责 Mesh 网络的初始化、节点管理、状态同步、事件处理等核心功能,为上层应用提供简单易用的API 接口。 - **Mesh 网络初始化**:初始化 Mesh 协议栈、配置节点参数 - **多种照明模型支持**: - Light Lightness:基础亮度控制 - Light CTL:色温与亮度控制 - Light HSL:色相、饱和度与亮度控制 - **状态管理**:维护设备的各种状态(开关、亮度、色温、HSL值等) - **事件处理**:提供统一的事件回调机制,处理 Mesh 网络中的各种事件 - **Access PDU 处理**:接收和解析 Mesh Access 层协议数据单元 - **数据备份与恢复**:支持将 Mesh 网络配置和状态备份到 Flash,系统重启后恢复 ### 6.6.2. 主要数据结构 - 灯状态结构 ```c typedef struct { uint32_t light_id; // 灯设备ID uint8_t st_flag; // 状态有效性标志位 uint8_t st_changed_flag; // 状态变化标志位 uint8_t light_on; // 开关状态 uint16_t lightness; // 亮度值 uint16_t hue; // 色相值 uint16_t saturation; // 饱和度值 uint16_t temperature; // 色温值 } tMESH_LightStateStru; ``` - 灯信息结构 ```c typedef struct { uint32_t light_id; // 灯设备ID uint16_t light_name; // 灯名称(位置描述符) tMESH_MODELS features; // 支持的照明模型 uint8_t light_on; // 初始开关状态 uint16_t lightness; // 初始亮度 uint16_t hue; // 初始色相 uint16_t saturation; // 初始饱和度 uint16_t temperature; // 初始色温 } tMESH_LightInfoStru; ``` - Mesh 事件类型 ```c typedef enum { MESHG_EV_INIT_DONE, // 初始化完成 MESHP_EV_PROVISIONING_COMPLETE, // 配网完成 MESHM_EV_LIGHT_STATE_CHANGED, // 灯状态变化 MESHM_EV_ACCESS_PDU_RECEIVED, // 收到Access PDU // ... 其他事件 } tMESH_EVENT; ``` ### 6.6.3. 主要的API 函数 - 初始化相关 ```C void mesh_stack_init(void)//初始化协议栈 void meshn_ele_add_begin(tMESH_NodeInfoStru * node_info)//添加元件开始 void meshn_ele_add_light(tMESH_LightInfoStru * light_info)//添加灯 void meshn_ele_add_switch(tMESH_SwitchInfoStru * switch_info)//添加开关 void meshn_ele_add_data_trans(tMESH_DataTrasnInfoStru * data_info)//添加厂商自定义模型 void meshn_add_gateway(void)//添加access pdu收发处理 void meshn_ele_add_end(void)//添加元件完成 ``` - 网络相关 ``` uint8_t meshn_is_provisioned(void)//查询组网状态 uint16_t meshn_unicast_address(void)//查询设备地址 void meshn_reset(void)//强制复位mesh void meshn_lp_friend_request(void)//Friend关系请求 void meshn_lp_friend_reset()//Friend关系解除 void meshn_lp_friend_poll(void)//LPN查询消息 void sdk_Mesh_PendDataBackup(uint16_t mask)//mesh应用数据存储 ``` ``` void meshm_switch_state(uint32_t switch_id,uint8_t onoff)//开关状态设置 ``` - Access PDU ```c void meshn_access_pdu_recv_enable(uint8_t enable);// 启用/禁用 Access PDU 接收回调 // Access PDU 接收回调函数 static void sdk_Mesh_AccessPduRecvCallback(uint16_t src, uint16_t dst, uint32_t opcode, uint8_t *data, uint16_t len, uint8_t ttl, uint8_t rssi, uint16_t appindex, uint16_t netindex); // Access PDU 发送函数 int meshn_access_pdu_send(uint8_t *pdu, uint16_t len, uint16_t appkey_index, uint8_t ttl) ``` - Mesh 事件回调函数 ```c void mesh_event_callback(tMESH_EVENT mesh_ev, void *p_arg) { switch (mesh_ev) { case MESHG_EV_INIT_DONE: // Mesh 初始化完成,开始配网 sdk_Mesh_ProvisioningStart(); break; case MESHP_EV_PROVISIONING_COMPLETE: // 配网完成,设备已加入 Mesh 网络 break; case MESHM_EV_LIGHT_STATE_CHANGED: { // 灯状态变化,更新硬件 tMESH_LightStateStru *p_state = (tMESH_LightStateStru *)p_arg; // 根据状态更新LED硬件 break; } case MESHM_EV_ACCESS_PDU_RECEIVED: { // 收到 Access PDU,可进行自定义处理 tMESH_AccessPduRecvStru *pdu_info = (tMESH_AccessPduRecvStru *)p_arg; // 处理接收到的 PDU break; } } } ``` ## 6.7 app_dfu ### 6.7.1 简介 app_dfu是例程集成的固件空中升级功能。 >w **警告提示** > > 固件中应考虑通过mesh私有命令来开启与关闭空中升级功能,防止恶意操作。 ### 6.7.2 固件限制 | 固件升级 | 固件最大尺寸 | 说明 | | --- | --- | --- | | 选择 | 248KB | bootloader占据8KB,升级固件最大为248KB-256B | | 不选择 | 256KB | -- | >i **信息提示** > > 固件升级需要用到bootloader(大小8KB)。 > 固件升级缓存区域为248KB。 > 升级固件包含256字节头部信息。 ### 6.7.2 编译配置 选择带OTA的配置,如下所示:  >i **信息提示** > 带OTA功能的固件,须配合bootloader使用,因此首次务必使用脚本来烧录。 > 否则无法正常使用。 ### 6.7.3 Flash区域划分  >w **警告提示** > > 如果选择了固件升级功能,OTA_TEMP区域会被使用,用户使用此区域存储数据要慎重! ### 6.7.4 烧录说明 - bootloader 随着sdk一起发布,名为masterboot.bin,位于“tools\dfu\image\masterboot.bin” - APP.bin 编译带有OTA配置选项后,生成APP.bin会被复制到“tools\dfu\image\”目录。 - 首次烧录(masterboot+APP) 点击"\tools\dfu\ProgrammingAll.bat",通过JLINK烧录bootloader与APP.bin。 ### 6.7.5 升级文件 编译生成的APP.bin文件,要经过打包工具添加OTA头部信息,才能用于空中升级。同时此工具亦可将APP.bin与masterboot.bin拼接生成完整的烧录文件,用于量产烧录。 ### 6.7.6 升级APP 升级协议与工具请与我们联系。 ## 6.8 其他模块 - mesh_dep 协议栈依赖 - mesh_gtl 协议栈传输层 - sdk_mesh_hlp 协议栈非易失数据存储管理器 - iot_utilites 常用工具函数 # 7. 常见问题
brtiot
June 12, 2026, 4:20 p.m.
Forward
Favorites
Last
Next
Scan the QR Code
Copy link
Scan the QR code to share.
Copy link
share
link
type
password
Update password
Validity period
Markdown file
Word document
PDF document
PDF document (print)