BR1601Axx
BR1601A02 Mesh SDK说明
BR1601A02 Mesh应用笔记
BR1601A/Bxx资料汇总
-
+
首页
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
2026年6月12日 16:20
转发
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
分享
链接
类型
密码
更新密码
有效期
Markdown文件
Word文件
PDF文档
PDF文档(打印)