首页 / 资讯中心 / 文章详情

沁恒 RISC-V 蓝牙应用中常用蓝牙参数的设定和修改

沁恒 RISC-V 蓝牙应用中常用蓝牙参数的设定和修改 ★ FEATURED ARTICLE
整理一下实际应用中蓝牙参数的设定和修改方式 ...... 矜辰所致 增加其他部分接口说明 ...... 2026/5/22 修正发射功率设置说明 ...... 2026/11/3前言之前的文章我们讲了很多理论基础例程分析在实际应用中根据不同的需求我们需要设定修改不同的蓝牙参数。所以本文我们就来整理下 实际应用中 工程里 常用的参数设置与修改方式 。相关博文与本文有关的博文比较多所以大家可通过专栏目录自行查找对应知识点的文章介绍。沁恒微蓝牙专栏目录【导航】沁恒微 RISC-V 蓝牙 入门教程目录 【快速跳转】.我是矜辰所致全网同名尽量用心写好每一系列文章不浮夸不将就认真对待学知识的我们矜辰所致金石为开目录前言一、 广播相关1.1 关闭/开启广播1.2 发射功率1.3 MAC 地址1.4 广播间隔1.4.1 一次广播时长说明1.5 广播内容1.5.1 修改广播名称1.6 广播类型二、连接相关2.1 连接参数2.2 MTU2.3 PHY2.4 断开当前连接三、扫描相关3.1 扫描时间3.2 扫描间隔3.3 扫描窗口四、其他接口4.1 协议栈剩余大小4.2 协议栈剩余缓存包结语本文以 CH585 EVT 为例说明仅供参考同系列芯片大致相同但是也不排除有某些特定型号的区别具体以大家实际测试为准。原理、流程、框架相关的东西都在以前博文中讲过了不知道代码添加在哪里的朋友自行查阅上面相关博文。一、 广播相关1.1 关闭/开启广播关闭广播uint8_tinitial_advertising_enableFALSE;GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED,sizeof(uint8_t),initial_advertising_enable);开启广播/* 如果当前已经在广播模式, 不要再次开启广播了 如果不确定当前状态可以操作前先获取当前广播状态 非 0 为广播 uint8_t adv_status; GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED, adv_status ); */uint8_tinitial_advertising_enableTRUE;GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED,sizeof(uint8_t),initial_advertising_enable);注意对于与广播参数有关的动态修改需要先关闭广播 - 修改配置 - 再开启广播。这个 关闭/开启 广播步骤对应用实际效果来说基本是无感的并不会有明显的延时在实际运行中需要修改广播参数的情况必须按照 关闭广播 - 修改配置 - 再开启广播的流程。首先大部分是需要这个步骤的即便存在有什么东西修改不需要这个步骤的按照这个来也不会出错反正我自己目前测试是不知道有哪个步骤不需要重新开启广播所以实际使用按照这个步骤准没错。此流程的示例如下不能直接在设置完以后的代码处直接开启广播必须按照上面示例在协议栈回复了状态以后才能再次开启广播1.2 发射功率初始发功功率设置默认发射功率如下操作如果不设置EVT 默认发射功率为LL_TX_POWEER_0_DBM动态修改发射功率如果要在广播期间修改发射功率使用如下函数此过程需要关闭广播 - 设置 - 再开启广播/* 1、需要先关闭广播然后设置最后在状态回调里面开启广播 2、#define TGAP_ADV_TX_POWER 25 //! Indicates the maximum power level Range: -127 ≤ N ≤ 126 Units: dBm.Default 127(Host has no preference). 3、它是“上限”而不是“精确值”。控制器会在自己支持的功率档位里选一个 ≤ N 的档位。所以写 4 不一定真输出 4.0 dBm而是“不超过 4 dBm 的最高可用档”。 */intset_dbm4GAP_SetParamValue(TGAP_ADV_TX_POWER,set_dbm);连接时候的发射功率修改后期遇到了再来更新。1.3 MAC 地址初始MAC地址芯片上电默认使用芯片本身的公共地址。如果想修改上电的 MAC 地址用于测试需要定义一个宏BLE_MAC TRUE便可以在代码中自己设定自定义地址如下图动态修改 MAC 地址如果要动态修改 MAC 地址使用如下函数此过程需要关闭广播 - 设置 - 再开启广播/* // GAP_ADDR_TYPE_DEFINES GAP Address Types #define ADDRTYPE_PUBLIC 0x00 //! Use the BD_ADDR #define ADDRTYPE_STATIC 0x01 //! Static address #define ADDRTYPE_PRIVATE_NONRESOLVE 0x02 //! Generate Non-Resolvable Private Address #define ADDRTYPE_PRIVATE_RESOLVE 0x03 //! Generate Resolvable Private Address 第一个参数选上面宏定义 需要先关闭广播然后设置最后在状态回调里面开启广播 */bStatus_tGAP_ConfigDeviceAddr(uint8_taddrType,uint8_t*pStaticAddr);//示例uint8_tmyAddr[6]{0x00,0xAA,0xBB,0xCC,0xDD,0x00};GAP_ConfigDeviceAddr(ADDRTYPE_STATIC,myAddr);详细说明可参考博主之前的博文BLE 蓝牙 MAC 地址相关说明1.4 广播间隔BLE 广播间隔的标准范围是 20 ms 10.24 s设置范围为 32~16348以 0.625 ms 单位。示例默认为 80// What is the advertising interval when device is discoverable (units of 625us, 8050ms)#defineDEFAULT_ADVERTISING_INTERVAL80修改方式如下此过程需要关闭广播 - 设置 - 再开启广播uint16_tadvInt100;//想要修改的间隔32~16348// Set advertising intervalGAP_SetParamValue(TGAP_DISC_ADV_INT_MIN,advInt);GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX,advInt);减少广播间隔时可以使得建立连接速度更快但是这样也会使得芯片功耗增大。1.4.1 一次广播时长说明一次广播事件就是在 3 个广播信37/38/39上各发一遍广播包发完就停直到下一个广播间隔再发一轮不是持续发射。如果有扫描响应就回广播响应一次广播事件流程如下信道 37发广播 → 看有没有扫描请求 → 有就回扫描响应信道 38发广播 → 看有没有扫描请求 → 有就回扫描响应信道 39发广播 → 看有没有扫描请求 → 有就回扫描响应单次广播事件时长是很短的 一般时间最长 可连接广播扫描响应 的广播时间估算下来 4ms 左右 甚至更少 。剩余的时间就可以用来休眠节约功耗 比如 20ms 广播间隔剩余的 16ms 就可以休眠 。1.5 广播内容根据示例有两个数组表示广播包和广播响应的内容scanRspData[]和advertData[]修改方式如下此过程需要关闭广播 - 设置 - 再开启广播GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA,sizeof(scanRspData),scanRspData);GAPRole_SetParameter(GAPROLE_ADVERT_DATA,sizeof(advertData),advertData);或者通过下面函数直接生效/* 参数1任务 ID 参数2广播包类型确定是修改广播数据还是扫描响应数据 TRUE - advertisement data, FALSE - scan response data 参数3数据长度 参数4指向广播内容缓冲区的指针要修改成的数据内容 */bStatus_tGAP_UpdateAdvertisingData(uint8_ttaskID,uint8_tadType,uint16_tdataLen,uint8_t*pAdvertData);广播包格式需要遵循标准格式可参考之前博文BLE 蓝牙空中报文格式与解析广播包1.5.1 修改广播名称广播名称是属于上面广播内容的一部分的我们使用上面方式二做个示例说明if(eventsMY_ChangePower_EVT){PRINT(Set Set...\r\n);GAP_UpdateAdvertisingData(Peripheral_TaskID,FALSE,sizeof(my_change_scanRspData),my_change_scanRspData);return(events^MY_ChangePower_EVT);}测试图额外说明在工程里面涉及到名字的地方有两个一个就是上面的广播包/扫描响应包中还有一个是需要存在服务特征值中链接以后通过特征值读取的。如下// GAP GATT Attributesstaticuint8_tattDeviceName[GAP_DEVICE_NAME_LEN]Simple Peripheral;// Set the GAP CharacteristicsGGS_SetParameter(GGS_DEVICE_NAME_ATT,GAP_DEVICE_NAME_LEN,attDeviceName);虽然这两个地方的名字没有明文规定必须一致但是强烈建议实际产品中保持一致苹果 IOS 中如果不一致会存在一些问题。1.6 广播类型广播类型一般不会在使用中更改在初始化的时候设置例程并没有设置默认广播类型为GAP_ADTYPE_ADV_IND可连接、非定向广播设置其他广播类型如下 // GAP_ADVERTISEMENT_TYPE_DEFINES GAP Advertising Event Types#defineGAP_ADTYPE_ADV_IND0x00//! Connectable undirected event typet#defineGAP_ADTYPE_ADV_HDC_DIRECT_IND0x01//! Connectable high duty cycle directed event type#defineGAP_ADTYPE_ADV_SCAN_IND0x02//! Scannable undirected event type#defineGAP_ADTYPE_ADV_NONCONN_IND0x03//! Non-Connectable undirected event type#defineGAP_ADTYPE_ADV_LDC_DIRECT_IND0x04//! Connectable low duty cycle directed event type/* 依次为 可连接、非定向广播 可被扫描 可被连接最常用 高占空比、可连接、定向广播 设备需要瞬间秒连时用 可扫描、非定向、不可连接 只发数据、不做连接的设备展 不可连接、不可扫描、纯广播 iBeacon / 传感器 低占空比、可连接、定向广播 低功耗定向连接 */uint8_tmy_test_adv_typeGAP_ADTYPE_ADV_SCAN_IND;GAPRole_SetParameter(GAPROLE_ADV_EVENT_TYPE,sizeof(uint8_t),my_test_adv_type);二、连接相关2.1 连接参数连接参数相关详细说明可参考博文BLE 蓝牙连接参数详解从机端下面是从机例程与连接参数有关的宏定义// Minimum connection interval (units of 1.25ms, 67.5ms)#defineDEFAULT_DESIRED_MIN_CONN_INTERVAL6// Maximum connection interval (units of 1.25ms, 100125ms)#defineDEFAULT_DESIRED_MAX_CONN_INTERVAL100// Slave latency to use parameter update#defineDEFAULT_DESIRED_SLAVE_LATENCY0// Supervision timeout value (units of 10ms, 1001s)#defineDEFAULT_DESIRED_CONN_TIMEOUT100必须满足Supervision Timeout (1 Slave Latency) × Connection Interval × 2超时时间 (ms)(1延迟次数)×连接间隔 (ms)×2uint16_tdesired_min_intervalDEFAULT_DESIRED_MIN_CONN_INTERVAL;uint16_tdesired_max_intervalDEFAULT_DESIRED_MAX_CONN_INTERVAL;GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL,sizeof(uint16_t),desired_min_interval);GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL,sizeof(uint16_t),desired_max_interval);这只是从机端希望的连接间隔主机会在这个范围内给一个合适的值由主机决定如果这个范围主机给不了主机也会给从机一个连接间隔从机不会拒绝 。连接上以后从机还能发起协商请求if(eventsSBP_PARAM_UPDATE_EVT){// Send connect param update request// When the current connection parameters already meet the requirements for update, return 0x18(InvalidRange)GAPRole_PeripheralConnParamUpdateReq(peripheralConnList.connHandle,DEFAULT_DESIRED_MIN_CONN_INTERVAL,DEFAULT_DESIRED_MAX_CONN_INTERVAL,DEFAULT_DESIRED_SLAVE_LATENCY,DEFAULT_DESIRED_CONN_TIMEOUT,Peripheral_TaskID);return(events^SBP_PARAM_UPDATE_EVT);}不管协商几次主机协商还是从机自己协商协商的结果会在从机回调函数peripheralParamUpdateCB里打印连接间隔以最后一次协商结果为最终结果如下图 主机端// Minimum connection interval (units of 1.25ms)#defineDEFAULT_UPDATE_MIN_CONN_INTERVAL20// Maximum connection interval (units of 1.25ms)#defineDEFAULT_UPDATE_MAX_CONN_INTERVAL100// Slave latency to use parameter update#defineDEFAULT_UPDATE_SLAVE_LATENCY0// Supervision timeout value (units of 10ms)#defineDEFAULT_UPDATE_CONN_TIMEOUT600if(eventsSTART_PARAM_UPDATE_EVT){// start connect parameter updateGAPRole_UpdateLink(centralConnHandle,DEFAULT_UPDATE_MIN_CONN_INTERVAL,DEFAULT_UPDATE_MAX_CONN_INTERVAL,DEFAULT_UPDATE_SLAVE_LATENCY,DEFAULT_UPDATE_CONN_TIMEOUT);return(events^START_PARAM_UPDATE_EVT);}2.2 MTU关于 MTU 交互 一些理论知识请参考博主之前博文沁恒微 CH585 芯片 Ble 传输速率测试说明 里面 MTUBLE_BUFF_MAX_LEN 和 单包数据长度小节相关说明。这里举几个例子先看看最大的情况如果 BLE_BUFF_MAX_LEN 516 字节那么MTU 最大为 512 字节用户一包数据最大为 509 字节可以定义一个 509 字节大小的数组用于发送但是因为空中物理帧限制一包空中数据最大 251 字节减去 2 字节 LL header减去 4 字节 L2CAP header再减去 3 字节 ATT header用户数据一帧最大发出 244 字节。所以这种情况它会分成 3 包 244 B 244 B 21 B 发送对于适合单帧不分包的情况BLE_BUFF_MAX_LEN 251MTU 最大为 247用户一包数据最大为 244 字节 (通过特征值或者通知数据交互)对于默认的情况BLE_BUFF_MAX_LEN 27MTU 最大为 23用户一包数据最大为 20设置 MTU 需要主从机均支持修改 MTU对于应用来说就是 主机从机的BLE_BUFF_MAX_LEN要足够如果我们想协商 512 的 MTU 那么需要BLE_BUFF_MAX_LEN至少为 516 。从机端首先是宏定义BLE_BUFF_MAX_LEN然后通过手机连接从机手机端发起 MTU 交互就能够成功主机端主机端同样的和从机一样的方式先定义BLE_BUFF_MAX_LEN。然后再程序需要设置的地方手动调用如下代码// Update MTU最大为 BLE_BUFF_MAX_LEN - 4attExchangeMTUReq_treq{.clientRxMTUBLE_BUFF_MAX_LEN-4,//这只是最大值};GATT_ExchangeMTU(centralConnHandle,req,centralTaskId);从机主动交互 MTU如果想要从机主动交互 MTU 我们可以使用如下方式先定义BLE_BUFF_MAX_LEN从机初始化的地方Peripheral_Init加上GATT_InitClient();和主机示例手动调用 MTU 协商一样的方式。1。 BLE_BUFF_MAX_LEN516516都可以2.//...// Register receive scan request callbackGAPRole_BroadcasterSetCB(Broadcaster_BroadcasterCBs);//增加代码GATT_InitClient();// Setup a delayed profile startuptmos_set_event(Peripheral_TaskID,SBP_START_DEVICE_EVT);//...3.if(eventsMY_ChangePower_EVT){if(peripheralConnList.connHandle!GAP_CONNHANDLE_INIT)//如果存在连接状态才设置{PRINT(Set Set...\r\n);attExchangeMTUReq_treq{.clientRxMTU512,//这只是最大值};GATT_ExchangeMTU(peripheralConnList.connHandle,req,Peripheral_TaskID);}else{PRINT(no connected...\r\n);}return(events^MY_ChangePower_EVT);}测试结果程序中协商后获取 MTU 接口/** * brief This function is used to get the MTU size of a connection. * * param connHandle - connection handle. * * return connection MTU size.BR */externuint16_tATT_GetMTU(uint16_tconnHandle);2.3 PHYPHY 协商主机和从机一样的函数// start phy updatePRINT(PHY Update %x...\n,GAPRole_UpdatePHY(peripheralConnList.connHandle,0,GAP_PHY_BIT_LE_2M,GAP_PHY_BIT_LE_2M,0));2.4 断开当前连接bStatus_tGAPRole_TerminateLink(uint16_tconnHandle);上面传入的是句柄这个在主机从机示例里面可以找到比如主机端使用的句柄变量是centralConnHandle从机使用的句柄变量是peripheralConnList.connHandle。三、扫描相关扫描相关是针对主机或者观察者角色而言的。3.1 扫描时间表示设备扫描持续时间扫描多久后停止// Scan duration in 0.625ms#defineDEFAULT_SCAN_DURATION2400/* 扫描持续时间 Default 10.24seconds. Setting this parameter to 0 turns off the timeout 设置为0永不超时 */GAP_SetParamValue(TGAP_DISC_SCAN,DEFAULT_SCAN_DURATION);3.2 扫描间隔表示 多久扫一次/* Default 16. (n * 0.625 mSec) 扫描间隔,需要扫描窗口 */GAP_SetParamValue(TGAP_DISC_SCAN_INT,64);3.3 扫描窗口表示 每次扫多久/* Default 16. (n * 0.625 mSec) */GAP_SetParamValue(TGAP_DISC_SCAN_WIND,32);扫描间隔不是扫描停止到下次扫描开始的时间啊不要搞错了他是两次扫描开始的间隔所以由 扫描间隔需要扫描窗口如下图上面 3 个参数是主机扫描的核心参数举几个组合示例 快速发现设备功耗大TGAP_DISC_SCAN0;// 无限扫描TGAP_DISC_SCAN_INT10ms;// 扫描间隔TGAP_DISC_SCAN_WIND10ms;// 窗口 间隔 → 一直扫描低功耗扫描省电TGAP_DISC_SCAN5000ms;// 扫5秒自动停TGAP_DISC_SCAN_INT100ms;// 每100ms扫一次TGAP_DISC_SCAN_WIND10ms;// 每次只扫10ms四、其他接口4.1 协议栈剩余大小PRINT(协议栈剩余 %d\n,tmos_memory_getlen());测试单位字节4.2 协议栈剩余缓存包在某些时候发送太快协议栈允许一定的缓存宏定义为BLE_BUFF_NUM- 控制器缓存的包数量( 默认:5 )在程序允许期间可通过下面接口获取PRINT(剩余包 %d,LL_GetNumberOfUnAckPacket(centralConnHandle));//参数为句柄从机主机注意区分修改一下结语本文整理了一些蓝牙应用中需要用到的功能接口函数以供大家查阅。在后期如果有更新或者新的一些说明博主也会更新博文内容。好了本文就到这里。谢谢大家
阅读完成 · 觉得有帮助?
咨询建站