一、概念:
广播间隔:BLE设备每次广播时,会在3个广播信道上发送相同的报文,这些报文被称为一个广播事件。两个相邻广播事件之间的时间称为广播间隔。广播间隔是针对从机设备来说的,广播间隔决定了从机设备的广播频率。其实际广播间隔时间为32~16448,单位是0.625ms,所以实际的广播间隔时间是32*0.625~16448*0.625ms。
连接间隔:BLE主机和BLE从机成功建立连接后,主机从机设备之间的交互频率(握手)。其实际连接间隔时间为6~3200,单位是1.25ms,所以实际的连接间隔时间是6*1.25~3200*1.25ms。
二、特点:
- 广播间隔:减小广播间隔可以使广播频率增高,建立连接的过程加快,同样伴随着功耗的上升;增大广播间隔会是广播频率下降,建立连接的速度减慢,同时功耗下降。广播信道越多,各个信道同时受到干扰的几率越小,抗干扰性越强。但是广播信道越多,发射数据占用的时间就越长,功耗也就越高。所以,在综合考虑抗干扰性和功耗的情况下,SIG将广播设定为3个。
- 连接间隔:长的时间间隔的优势是显著地节省功耗,因为设备可以在连接事件之间有较长时间的休眠,坏处是当设备有应用数据需要发送时,必须要等到下一个连接事件;短的时间间隔优势是两设备连接频发,可以更快地收发数据,不利之处是设备因连接事件的到来而被频繁的唤醒,会有较多功耗。因此,在实际应用的时候,有时候需要发送数据快一点,这个时候我们可以把连接间隔改小一点,这样发送数据快,但是功耗大,当把数据发完的时候,可把连接间隔改小一点,这样可以降低功耗,达到一个均衡。
- 关于连接间隔还有一点需要注意:我们在处理BLE相关任务时,偶尔会遇到蓝牙断连的情况,有一个原因便是蓝牙其本身的任务阻塞导致的断连。蓝牙在连接成功之后,其连接间隔是固定的,当有用户程序的任务过来会导致其来不及处理自身的任务或是两种任务发生冲突。这时候,可以适当的拉大连接间隔,给以用户程序任务更多的处理时间,这样便不会出现断连的现象。针对上述情况,如果不想修改连接间隔,也可以将用户任务进行拆分。总而言之,保证蓝牙在固定时间内处理其自身任务不受影响即可。
- CH582芯片支持多主连接,即一个主机连接多个从机,此时该主机与不同从机的连接间隔均相同(底层处理),因为设置为不同的连接间隔会出现在未来的某个时间点同时发包,这样必然会导致在该时间点某一个从机丢包,甚至出现蓝牙断连的情况。因此多主连接时,即使应用层设置为不同的连接间隔,最终实际协商出来的连接间隔也是相同的。
三、信道
信道也称作通道(Channel)、频段,是以无线信号(电磁波)作为传输载体的数据信号传送通道。无线网络(路由器、AP热点、电脑无线网卡)可在多个信道上运行。在无线信号覆盖范围内的各种无线网络设备应该尽量使用不同的信道,以避免信号之间的干扰。
2.4G被划分为40个RF信道(f=2402+k*2 MHz, k=0, ... ,39), 信道间隔2MHz,其中:
- 广播信道:3个,固定。
- 数据信道: 37个,自适应跳频。
- 无线速率: 1Mbps、 2Mbps
图:链路层信道映射
广播信道:37 、38、39,对应的中心频率是2402MHz,2426MHz,2480MHz。广播信道之间至少相差24MHz。每次广播,都会在3个信道上将广播数据发送一次,这能有效地避免干扰,即使一个信道存在干扰,另外的信道也可以很好地工作,而三个信道同时被干扰的情况极少。
四、连接间隔协商
连接间隔是可协商的,使用低功耗蓝牙时会经常遇到不同手机连接协商出来的连接间隔值不同,因为连接间隔的协商是由主机端主动发起的。此时会出现一种情况,协商出来的连接间隔与我们的预期相差甚远,这时进行数据传输,速度或者功耗并不是很理想,需要重新协商连接间隔。手机端我们无法处理重新协商,因此需要从机端发起协商进行处理。在从机端协商出连接间隔后会有日志信息(在参数更新的回调函数中),出现不满足条件的情况下则重新开启TMOS任务,进行重新协商:
if(events & SBP_PARAM_UPDATE_EVT)
{
// Send connect param update request
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);
}
协商实例参考:
if(events & START_PARAM_UPDATE_EVT)
{
// Send connect param update request
uint8_t ret = GAPRole_PeripheralConnParamUpdateReq( hidEmuConnHandle, //协商函数
DESIRED_MIN_CONN_INTERVAL,
DESIRED_MAX_CONN_INTERVAL,
DEFAULT_DESIRED_SLAVE_LATENCY,
DEFAULT_DESIRED_CONN_TIMEOUT,
hidEmuTaskId);
printf("ret = %d\n", ret); //判断协商返回值,0为成功
static uint8 retry = 0; //第一次协商用的参数
static uint8 retryagain, reUpdate = 0; //第二次协商用的参数
if(conn_params.interval_current < 100){ //开启第一次协商
retry++; //conn_params.interval_current是回调函数中实际的间隔,传递到此处
printf("retry = %d\n", retry);
DESIRED_MIN_CONN_INTERVAL = 100;
DESIRED_MAX_CONN_INTERVAL = 120;
if(retry < 5){ //第一次协商次数最多为5(可自行配置),中途协商成功则跳出。
tmos_start_task(hidEmuTaskId, START_PARAM_UPDATE_EVT, 1000);
}
}else {
retry = 0;
reUpdate = 1;
}
if(reUpdate == 1){
if(conn_params.interval_current < 201){ //开启第二次协商
retryagain++;
printf("retryagain = %d\n", retryagain);
DESIRED_MIN_CONN_INTERVAL = 400;
DESIRED_MAX_CONN_INTERVAL = 420;
if(retryagain < 5){ //第一次协商次数最多为5(可自行配置),中途协商成功则跳出。
tmos_start_task(hidEmuTaskId, START_PARAM_UPDATE_EVT, 1000);
}else {
retryagain = 0;
tmos_stop_task(hidEmuTaskId, START_PARAM_UPDATE_EVT);
}
}
}
return (events ^ START_PARAM_UPDATE_EVT);
}
协商结果如下:
五、CH582间隔程序处理:
- 广播间隔:
// What is the advertising interval when device is discoverable (units of 625us, 80=50ms)
#define DEFAULT_ADVERTISING_INTERVAL 80
// Set advertising interval //设置广播间隔
{
uint16_t advInt = DEFAULT_ADVERTISING_INTERVAL; //设置广播间隔大小
GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt); //最小广播间隔
GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt); //最大广播间隔
}
- 连接间隔:
// Minimum connection interval (units of 1.25ms, 6=7.5ms) //最小连接间隔
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 6
// Maximum connection interval (units of 1.25ms, 100=125ms) //最大连接间隔
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 100
// Setup the GAP Peripheral Role Profile
{
uint8_t initial_advertising_enable = TRUE; //开启广播使能
uint16_t desired_min_interval = DEFAULT_DESIRED_MIN_CONN_INTERVAL; //最小连接间隔
uint16_t desired_max_interval = DEFAULT_DESIRED_MAX_CONN_INTERVAL; //最大连接间隔
// Set the GAP Role Parameters //设置GAP层参数
GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);
GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData);
GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData);
GAPRole_SetParameter(GAPROLE_MIN_CONN_INTERVAL, sizeof(uint16_t), &desired_min_interval);
GAPRole_SetParameter(GAPROLE_MAX_CONN_INTERVAL, sizeof(uint16_t), &desired_max_interval);
}