BLE开发_03_BLE常用参数及其修改_WCH

本文以CH585EVT中从机/主机例程为例

UID和MAC地址

UID

UID:每个芯片出厂时都具有唯一的ID号,即芯片身份识别号。该ID数据及其校验和共8字节,存储于芯片内部只读区域中
下载时ISP工具会显示UID:UID = 6字节芯片MAC地址+ 2字节校验和

MAC地址

#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
    for(i = 0; i < 6; i++)
    {
        cfg.MacAddr[i] = MacAddr[5 - i];//使用自定义MAC地址
    }
#else
    {
        uint8_t MacAddr[6];
        GetMACAddress(MacAddr);
        for(i = 0; i < 6; i++)
        {
            cfg.MacAddr[i] = MacAddr[i]; // 使用芯片mac地址
        }
    }
#endif
  • BLE_MAC的宏定义在HAL/include/CONFIG.h中,由于HAL库是整个BLE共用的,如果要单个工程修改宏定义,需要按如下方式修改
    image

动态修改MAC地址

  • 流程是关闭广播--修改MAC地址--打开广播
//自定义tmos任务,完成关闭广播和修改MAC地址
    if(events & SBP_TEST_EVT)
    {
        uint8_t  initial_advertising_enable = FALSE;
        uint8_t myAddr[6] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x00};
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
        GAP_ConfigDeviceAddr(ADDRTYPE_STATIC, myAddr);
        return (events ^ SBP_TEST_EVT);
    }
	
//在peripheralStateNotificationCB回调函数中打开广播,不能在修改数据后立刻开启广播
       case GAPROLE_WAITING:
            if(pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT)
            {
                PRINT("Waiting for advertising..\n");
                uint8_t initial_advertising_enable = TRUE;
                 GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
            }

读取MAC地址

/**
 * @brief   get 6 bytes MAC address
 *
 * @param   Buffer      - Pointer to the buffer where data should be stored, Must in RAM and be aligned to 4 bytes.
 *
 * @return  0-SUCCESS  (!0)-FAILURE
 */
#define GetMACAddress(Buffer)                       FLASH_EEPROM_CMD( CMD_GET_ROM_INFO, ROM_CFG_MAC_ADDR, Buffer, 0 )

其他地址

//修改方式和动态修改MAC地址流程一致
// GAP_ADDR_TYPE_DEFINES GAP Address Types
#define ADDRTYPE_PUBLIC                         0x00  //公共地址
#define ADDRTYPE_STATIC                         0x01  //静态地址
#define ADDRTYPE_PRIVATE_NONRESOLVE             0x02  //不可解析私有地址
#define ADDRTYPE_PRIVATE_RESOLVE                0x03  //可解析私有地址
  • 不可解析私有地址不能用于设备回连

广播参数

  • 广播参数的修改和上面的MAC地址修改方式一样,需要先关闭广播,修改参数,恢复广播,注意恢复广播的位置

广播数据和扫描应答数据

GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);//扫描应答数据
GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);//广播数据

// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertising)
static uint8_t advertData[] = {
    // Flags; this sets the device to use limited discoverable
    // mode (advertises for 30 seconds at a time) instead of general
    // discoverable mode (advertises indefinitely)
    0x02, // length of this data 长度
    GAP_ADTYPE_FLAGS,//类型
    DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,//值

    // service UUID, to notify central devices what services are included
    // in this peripheral
    0x03,                  // length of this data,长度
    GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all,类型
    LO_UINT16(SIMPLEPROFILE_SERV_UUID),//值
    HI_UINT16(SIMPLEPROFILE_SERV_UUID)
};

//扫描应答数据
// GAP - SCAN RSP data (max size = 31 bytes)
static uint8_t scanRspData[] = {
    // complete name
    0x12, // length of this data
    GAP_ADTYPE_LOCAL_NAME_COMPLETE,
    'S',
    'i',
    'm',
    'p',
    'l',
    'e',
    ' ',
    'P',
    'e',
    'r',
    'i',
    'p',
    'h',
    'e',
    'r',
    'a',
    'l',
    // connection interval range
    0x05, // length of this data
    GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
    LO_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL), // 100ms
    HI_UINT16(DEFAULT_DESIRED_MIN_CONN_INTERVAL),
    LO_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL), // 1s
    HI_UINT16(DEFAULT_DESIRED_MAX_CONN_INTERVAL),

    // Tx power level
    0x02, // length of this data
    GAP_ADTYPE_POWER_LEVEL,
    0 // 0dBm
};
  • 除了扫描应答数据中有广播名称外还有attDeviceName也定义了广播名称,建议这两处的名称保持一致,IOS中不一致会出现问题,GAP_DEVICE_NAME_LEN宏定义在XXXXlib.h文件中,如果需要修改需要修改文件读写权限

修改广播数据和扫描应答数据

/**
 * @brief   Setup or change advertising and scan response data.
 *
 * @note    if the return status from this function is SUCCESS,the task isn't complete
 *          until the GAP_ADV_DATA_UPDATE_DONE_EVENT is sent to the calling application task.
 *
 * @param   taskID - task ID of the app requesting the change
 * @param   adType - TRUE - advertisement data, FALSE  - scan response data
 * @param   dataLen - Octet length of advertData
 * @param   pAdvertData - advertising or scan response data
 *
 * @return  SUCCESS: data accepted
 *          bleIncorrectMode: invalid profile role
 */
extern bStatus_t GAP_UpdateAdvertisingData( uint8_t taskID, uint8_t adType, uint16_t dataLen, uint8_t *pAdvertData );

example:
    if(events & SBP_TEST_EVT)
    {
        GAP_UpdateAdvertisingData(Peripheral_TaskID,FALSE,sizeof(scanRspData1), scanRspData1);
        return (events ^ SBP_TEST_EVT);
    }

广播间隔

uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL;// 单位为 0.625ms,默认80*0.625ms
// Set advertising interval
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt);
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt);
  • 广播间隔是指两个连续广播事件之间的时间间隔。一个广播事件包含在 3 个广播信道(37、38、39)上依次发送广播包,广播间隔就是从一个广播事件开始到下一个广播事件开始的时间,减小广播间隔可以加快连接速度,但是会增加功耗
  • BLE 规范允许设置一个范围(最小值和最大值),控制器会在该范围内伪随机选择一个值作为本次广播事件的间隔。这样多个设备即使间隔范围相同,实际间隔也会错开,减少冲突。

连接参数

连接间隔

//从机
uint16_t desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL;
uint16_t desired_max_interval = DEFAULT_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);
//主机
GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, DEFAULT_MIN_CONNECTION_INTERVAL);
GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, DEFAULT_MAX_CONNECTION_INTERVAL);
  • 蓝牙主机从机连接后并不是持续发送数据的,而是在固定周期的类似于窗口内发送数据,称为连接事件,两个连接事件的时间间隔为连接间隔,连接间隔由主机决定,从机可以请求更新参数,连接间隔越小响应越快,但是功耗也越高

从设备延迟(slave latency)

  • 从设备延迟是指从机可以连续跳过多少个连接事件而不必响应主机的数据包,但不导致连接断开。如latency设置为5,在后面5次连接事件中从机都可以不响应并且不会导致断开,但第六次连接事件必须相应,在中间跳过的数据会在从机唤醒后由协议栈链路层自动重传
  • 从设备延迟用于降低设备功耗
// Slave latency to use parameter update
#define DEFAULT_DESIRED_SLAVE_LATENCY        0

连接超时

  • 连接超时用于判断设备连接是否有效,如果超出该时间,设备会认为该连接无效;一旦判定超时,协议栈会向应用层报告连接断开事件,设备可以执行清理、重新广播、释放资源等操作
// Supervision timeout value (units of 10ms, 100=1s)
#define DEFAULT_DESIRED_CONN_TIMEOUT         100

MTU

  • MTU-最大传输单元,通常指的是ATT层的MTU,MTU最大值为512

  • MTU的协商

    • MTU的协商是在建立连接之后主机/从机发起协商
    • 最终的 ATT_MTU = min(请求方 MTU,响应方 MTU),双方在后续通信中使用这个较小值
    • 假设ATT_MTU最终协商值为512,由于ATT层的包头占用3字节,实际用户数据为509字节
    • 受限于蓝牙规范中链路层数据长度扩展(DLE)的最大有效载荷为251字节,当ATT_MTU大于247字节时在L2CAP层自动分包,比如当ATT_MTU协商值为512时,底层分包为244+244+21字节发送
  • 修改MTU: MTU = BLE_BUFF_MAX_LEN - 4

#ifndef BLE_BUFF_MAX_LEN
#define BLE_BUFF_MAX_LEN                    516
#endif
  • 从机主动发起协商更新MTU
//1. Peripheral_Init()中添加client权限
GATT_InitClient();
//2.更新MTU
if(peripheralConnList.connHandle != GAP_CONNHANDLE_INIT)//连接后才更新MTU
	{
		attExchangeMTUReq_t req = {
			.clientRxMTU = BLE_BUFF_MAX_LEN - 4,
 		};
		GATT_ExchangeMTU(peripheralConnList.connHandle, &req, Peripheral_TaskID);
	}
else{
		PRINT("no connected...\r\n");
	}
  • MTU读取
/**
 * @brief   This function is used to get the MTU size of a connection.
 *
 * @param   connHandle - connection handle.
 *
 * @return  connection MTU size.<BR>
 */
extern uint16_t ATT_GetMTU( uint16_t connHandle );

PHY

  • PHY是协议栈最底层的无线传输规范,定义了数据如何在空间中通过无线电波进行编码、调制和发送。PHY 直接决定了通信的速率、距离和抗干扰能力
  • 1M/2M PHY指的是数据在空中传输速率,并不是数据的实际发送速率,实际发送速率还受到MTU/连接间隔等参数的影响
/**
 * @brief   Update the connection phy.
 *
 * @param   connHandle - connection handle
 * @param   all_phys - a bit field that  allows the Host to specify, for each direction
 *                     set BIT0:The Host has no preference among the transmitter PHYs supported by the Controller
 *                     set BIT1:The Host has no preference among the receiver PHYs supported by the Controller
 * @param   tx_phys - a bit field that indicates the transmitter PHYs.(GAP_PHY_BIT_TYPE)
 * @param   rx_phys - a bit field that indicates the receiver PHYs.(GAP_PHY_BIT_TYPE)
 * @param   phy_options - resv
 *
 * @return  SUCCESS: PHY update started started .<BR>
 *          bleIncorrectMode: No connection to update.<BR>
 */
extern bStatus_t GAPRole_UpdatePHY( uint16_t connHandle, uint8_t all_phys, uint8_t tx_phys,\
    uint8_t rx_phys, uint16_t phy_options );

从机主动更新连接参数

/**
 * @brief   Update the parameters of an existing connection
 *
 * @param   connHandle - the connection Handle
 * @param   connIntervalMin - minimum connection interval in 1.25ms units
 * @param   connIntervalMax - maximum connection interval in 1.25ms units
 * @param   latency - the new slave latency
 * @param   connTimeout - the new timeout value
 * @param   taskId - taskID will recv L2CAP_SIGNAL_EVENT message
 *
 * @return  SUCCESS, bleNotConnected or bleInvalidRange
 */
extern bStatus_t GAPRole_PeripheralConnParamUpdateReq( uint16_t connHandle, uint16_t connIntervalMin,
    uint16_t connIntervalMax, uint16_t latency, uint16_t connTimeout, uint8_t taskId );

注意:库中还有个GAPRole_UpdateLink可以更新连接参数,但是是主机使用,该函数可以直接更新连接参数不经过协商,而GAPRole_PeripheralConnParamUpdateReq是更新连接参数请求,主机有权拒绝

posted @ 2026-08-31 16:58  J_02346  阅读(6)  评论(0)    收藏  举报