蓝牙低功耗协议
引言
蓝牙低功耗(Bluetooth Low Energy,简称BLE)是一种旨在降低功耗的无线通信技术,广泛应用于健康、运动、智能家居等领域。与经典蓝牙相比,BLE在功耗、连接速度和数据传输方面有显著的改进。本节将详细探讨BLE协议的原理和内容,包括其基本架构、数据包格式、连接流程、服务和特征等,并通过具体的代码示例来说明如何在仿真环境中实现BLE通信。
基本架构
1. 物理层(Physical Layer)
物理层负责定义无线信号的传输频率、调制方式、发射功率等。BLE工作在2.4 GHz ISM频段,使用GFSK(高斯频移键控)调制,数据传输速率为1 Mbps。BLE使用37个数据信道和3个广告信道(37、38、39 MHz),其中广告信道用于设备发现和连接建立。
2. 链路层(Link Layer)
链路层负责设备之间的连接管理和数据包的传输。BLE链路层的主要功能包括:
- 设备发现:通过广告信道广播设备信息。
- 连接建立:设备通过广告信道建立连接。
- 数据传输:连接建立后,设备通过数据信道传输数据。
- 连接维护:包括连接参数更新、断开连接等。
广告包
广告包是BLE设备在广告信道上发送的数据包,用于广播设备的标识和信息。广告包的格式如下:
- Preamble:1字节,固定为0x55。
- Access Address:4字节,固定为0x8E89BED6。
- AD Data:包含设备信息的广告数据,最大长度为31字节。
- CRC:3字节,用于校验数据的完整性。
连接请求包
连接请求包用于发起连接请求。其格式如下:
- Preamble:1字节,固定为0x55。
- Access Address:4字节,固定为0x8E89BED6。
- Connection Request Data:包含连接参数,如连接间隔、从设备地址等。
- CRC:3字节,用于校验数据的完整性。
3. 逻辑链路控制和适配协议(L2CAP)
L2CAP层负责数据包的分段和重组,以及多路复用。BLE使用的L2CAP层更加简单,主要用于传输ATT(属性协议)数据。
4. 属性协议(ATT)
属性协议(Attribute Protocol)用于定义和访问设备上的属性。每个属性都有一个唯一的16位或128位UUID(通用唯一识别码),并且可以通过读、写、通知等操作进行访问。
服务和特征
- 服务(Service):一组相关的特征,用于描述特定的功能或应用。例如,一个心率服务可能包含心率测量、体感温度等特征。
- 特征(Characteristic):服务中的具体数据项,可以读取、写入或通知。例如,心率测量特征包含当前的心率值。
5. 通用访问配置文件(GAP)
通用访问配置文件(Generic Access Profile)定义了设备如何被发现、连接和配置。GAP包括设备的名称、外观、连接模式等。
6. 通用属性配置文件(GATT)
通用属性配置文件(Generic Attribute Profile)定义了如何通过ATT协议访问服务和特征。GATT包括服务发现、特征发现、读取和写入等操作。
数据包格式
1. 广告包格式
| 字段 | 长度(字节) | 描述 | |--------------|--------------|-------------------------------| | Preamble | 1 | 固定为0x55 | | Access Address| 4 | 固定为0x8E89BED6 | | AD Data | 0-31 | 广告数据,包含设备信息 | | CRC | 3 | 循环冗余校验码 |2. 连接请求包格式
| 字段 | 长度(字节) | 描述 | |----------------------------|--------------|-------------------------------| | Preamble | 1 | 固定为0x55 | | Access Address | 4 | 固定为0x8E89BED6 | | Connection Request Data | 25 | 包含连接参数和设备地址 | | CRC | 3 | 循环冗余校验码 |连接流程
1. 广告
设备通过广告信道广播自己的信息。广告包包括设备的名称、UUID、功率等级等。
2. 扫描
扫描设备监听广告信道,收集广告包中的信息。扫描设备可以发送扫描请求,广告设备可以回应扫描响应。
3. 连接建立
扫描设备向广告设备发送连接请求,广告设备接受请求后,两者建立连接。连接建立后,设备通过数据信道进行数据传输。
4. 数据传输
连接建立后,设备通过数据信道传输数据。数据传输可以是单向或双向的,具体取决于服务和特征的定义。
5. 连接维护
连接建立后,设备需要定期发送维持连接的信号,如心跳包。连接参数可以动态调整,以适应不同的应用场景。
服务和特征
1. 服务定义
服务是一组相关的特征,用于描述特定的功能或应用。服务可以通过UUID来唯一标识。例如,心率服务的UUID为0x180D。
2. 特征定义
特征是服务中的具体数据项,可以读取、写入或通知。特征也有自己的UUID。例如,心率测量特征的UUID为0x2A37。
3. 服务和特征的访问
通过GATT协议,设备可以访问其他设备的服务和特征。访问操作包括:
- 服务发现:获取设备上所有服务的UUID。
- 特征发现:获取特定服务下所有特征的UUID。
- 读取特征值:读取特定特征的当前值。
- 写入特征值:写入特定特征的值。
- 通知和指示:设备可以启用特征的通知或指示,当特征值发生变化时,主动通知或指示另一设备。
代码示例
1. 广告包生成
以下是一个Python示例,用于生成并发送BLE广告包。
importstructimportbinasciidefgenerate_advertising_packet(device_name,uuid):""" 生成BLE广告包 :param device_name: 设备名称 :param uuid: 设备UUID :return: 广告包数据 """# 固定前缀preamble=b'\x55'access_address=b'\x8E\x89\xBE\xD6'# 广告数据adv_data=b'\x02\x01\x06'# Flagsadv_data+=struct.pack('B',len(device_name)+1)+b'\x09'+device_name.encode('utf-8')# 设备名称adv_data+=struct.pack('B',len(uuid)+1)+b'\x07'+binascii.unhexlify(uuid)# UUID# 计算CRCcrc=b'\x00\x00\x00'# 假设CRC为0x000000,实际应用中需要计算CRC# 组合成完整的广告包advertising_packet=preamble+access_address+adv_data+crcreturnadvertising_packet# 示例:生成一个包含设备名称"BLE Device"和UUID"180D"的广告包advertising_packet=generate_advertising_packet("BLE Device","180D")print(binascii.hexlify(advertising_packet))2. 连接请求包生成
以下是一个Python示例,用于生成并发送BLE连接请求包。
defgenerate_connection_request_packet(initiator_address,advertising_address,connection_interval,slave_latency,supervision_timeout):""" 生成BLE连接请求包 :param initiator_address: 发起设备地址 :param advertising_address: 广告设备地址 :param connection_interval: 连接间隔 :param slave_latency: 从设备延迟 :param supervision_timeout: 监督超时时间 :return: 连接请求包数据 """# 固定前缀preamble=b'\x55'access_address=b'\x8E\x89\xBE\xD6'# 连接请求数据conn_req_data=b'\x00\x00\x00\x00\x00\x00'# 初始化PDU类型和信道conn_req_data+=struct.pack('6s',binascii.unhexlify(initiator_address))# 发起设备地址conn_req_data+=struct.pack('6s',binascii.unhexlify(advertising_address))# 广告设备地址conn_req_data+=struct.pack('<H',connection_interval)# 连接间隔conn_req_data+=struct.pack('<H',slave_latency)# 从设备延迟conn_req_data+=struct.pack('<H',supervision_timeout)# 监督超时时间# 计算CRCcrc=b'\x00\x00\x00'# 假设CRC为0x000000,实际应用中需要计算CRC# 组合成完整的连接请求包connection_request_packet=preamble+access_address+conn_req_data+crcreturnconnection_request_packet# 示例:生成一个连接请求包initiator_address="A1:B2:C3:D4:E5:F6"advertising_address="01:02:03:04:05:06"connection_interval=7.5# 7.5 msslave_latency=0# 无延迟supervision_timeout=100# 100 ms# 将连接间隔和监督超时时间转换为BLE协议的单位conn_interval=int(connection_interval*1000/1.25)sup_timeout=int(supervision_timeout*10)connection_request_packet=generate_connection_request_packet(initiator_address,advertising_address,conn_interval,slave_latency,sup_timeout)print(binascii.hexlify(connection_request_packet))3. 服务和特征的访问
以下是一个Python示例,使用pybluez库来访问BLE设备的服务和特征。
importbluetoothdefdiscover_services(device_address):""" 发现设备上的所有服务 :param device_address: 设备地址 :return: 服务列表 """services=bluetooth.find_service(address=device_address)returnservicesdefdiscover_characteristics(device_address,service_uuid):""" 发现特定服务下的所有特征 :param device_address: 设备地址 :param service_uuid: 服务UUID :return: 特征列表 """characteristics=[]services=discover_services(device_address)forserviceinservices:ifservice['uuid']==service_uuid:forcharacteristicinservice['characteristics']:characteristics.append(characteristic)returncharacteristicsdefread_characteristic_value(device_address,characteristic_uuid):""" 读取特征值 :param device_address: 设备地址 :param characteristic_uuid: 特征UUID :return: 特征值 """sock=bluetooth.BluetoothSocket(bluetooth.L2CAP)sock.connect((device_address,0x10))# 发送读取特征值的请求request=b'\x01'+binascii.unhexlify(characteristic_uuid)sock.send(request)# 接收响应response=sock.recv(1024)sock.close()returnresponse# 示例:发现服务和特征,读取特征值device_address="A1:B2:C3:D4:E5:F6"service_uuid="180D"characteristic_uuid="2A37"services=discover_services(device_address)print("发现的服务:",services)characteristics=discover_characteristics(device_address,service_uuid)print("发现的特征:",characteristics)value=read_characteristic_value(device_address,characteristic_uuid)print("读取的特征值:",binascii.hexlify(value))仿真环境搭建
1. 使用pybluez库
pybluez是一个Python库,用于在Linux系统上进行蓝牙通信。以下是如何安装和使用pybluez库的步骤。
安装
pipinstallpybluez示例代码
以下是一个简单的示例,展示如何使用pybluez库进行设备扫描、连接、发送和接收数据。
importbluetoothdeffind_devices():""" 扫描附近的蓝牙设备 :return: 设备列表 """nearby_devices=bluetooth.discover_devices(duration=8,lookup_names=True,flush_cache=True,lookup_class=False)returnnearby_devicesdefconnect_to_device(device_address,port):""" 连接到蓝牙设备 :param device_address: 设备地址 :param port: 端口 :return: 连接套接字 """sock=bluetooth.BluetoothSocket(bluetooth.RFCOMM)sock.connect((device_address,port))returnsockdefsend_data(sock,data):""" 发送数据到蓝牙设备 :param sock: 连接套接字 :param data: 要发送的数据 """sock.send(data)defreceive_data(sock):""" 从蓝牙设备接收数据 :param sock: 连接套接字 :return: 接收到的数据 """returnsock.recv(1024)# 示例:扫描设备、连接设备、发送和接收数据devices=find_devices()print("附近的设备:",devices)device_address="A1:B2:C3:D4:E5:F6"port=1sock=connect_to_device(device_address,port)send_data(sock,b'Hello, BLE Device!')data=receive_data(sock)print("接收到的数据:",data)sock.close()2. 使用nRF5 SDK进行硬件仿真
nRF5 SDK是Nordic Semiconductor提供的开发工具,用于开发基于nRF5系列芯片的蓝牙低功耗应用。以下是如何使用nRF5 SDK进行硬件仿真的步骤。
环境搭建
- 安装工具链:安装
GNU Arm Embedded Toolchain和SEGGER J-Link等工具。 - 下载SDK:从Nordic的官方网站下载
nRF5 SDK。 - 配置项目:在
nRF5 SDK中创建一个新的项目,并配置项目参数。
示例代码
以下是一个简单的示例,展示如何使用nRF5 SDK创建一个广告和连接的BLE设备。
#include"ble.h"#include"ble_advdata.h"#include"ble_hci.h"#include"nrf_sdh.h"#include"nrf_sdh_ble.h"#include"nrf.h"#include"nrf_log.h"#include"nrf_log_ctrl.h"#include"nrf_log_default_backends.h"staticuint16_tservice_uuid=0x180D;staticuint16_tcharacteristic_uuid=0x2A37;staticble_gap_adv_params_tm_adv_params;staticble_gap_conn_params_tm_conn_params;staticvoidble_gap_params_init(void){// 广告参数初始化memset(&m_adv_params,0,sizeof(m_adv_params));m_adv_params.type=BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;m_adv_params.p_props=NULL;m_adv_params.p_whitelist=NULL;m_adv_params.primary_phy=BLE_GAP_PHY_1MBPS;m_adv_params.secondary_phy=BLE_GAP_PHY_1MBPS;m_adv_params.duration=0;// 永久广告m_adv_params.max_adv_evts=0;m_adv_params.channel_mask=0x07;m_adv_params.interval=MSEC_TO_UNITS(100,UNIT_0_625_MS);// 100 msm_adv_params.timeout=0;// 连接参数初始化memset(&m_conn_params,0,sizeof(m_conn_params));m_conn_params.min_conn_interval=MSEC_TO_UNITS(7.5,UNIT_1_25_MS);// 7.5 msm_conn_params.max_conn_interval=MSEC_TO_UNITS(7.5,UNIT_1_25_MS);// 7.5 msm_conn_params.slave_latency=0;m_conn_params.conn_sup_timeout=MSEC_TO_UNITS(100,UNIT_10_MS);// 100 ms}staticvoidble_advdata_init(void){// 广告数据初始化ble_advdata_tadvdata;uint8_tadvdata_array[31];uint8_tadvdata_len;memset(&advdata,0,sizeof(advdata));advdata.name_type=BLE_advdata_name_type_short_name;advdata.include_addr=true;advdata.flags=BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;advdata.p_service_uuids=&service_uuid;advdata.service_uuid_count=1;advdata.p_manufacturer_specific_data=NULL;advdata_len=ble_advdata_encode(&advdata,advdata_array);// 发送广告数据nrf_ble_gap_adv_data_set(BLE_GAP_ADV_DATA_TYPE_ADVERTISING,advdata_array,advdata_len);}staticvoidble_conn_params_init(void){// 连接参数初始化nrf_ble_gap_conn_params_set(&m_conn_params);}staticvoidble_stack_init(void){// 初始化蓝牙堆栈nrf_sdh_enable_request();nrf_sdh_ble_default_cfg_set(BLE_CONN_CFG_DEFAULT,NULL);nrf_sdh_ble_enable(&m_conn_params);// 注册事件处理函数nrf_sdh_ble_observers_register(&m_ble_observer);}staticvoidble_adv_start(){// 开始广告nrf_ble_gap_adv_start(&m_adv_params);}intmain(void){// 初始化日志nrf_log_init();nrf_log_default_backends_init();// 初始化蓝牙堆栈ble_stack_init();// 初始化广告参数ble_gap_params_init();// 初始化广告数据ble_advdata_init();// 初始化连接参数ble_conn_params_init();// 开始广告ble_adv_start();// 主循环while(1){nrf_sdhprocesso();}return0;}3. 使用nRF Connect for Desktop进行测试
nRF Connect for Desktop是一个图形化的工具,用于测试和调试BLE设备。以下是使用该工具进行测试的步骤:
- 安装工具:从Nordic Semiconductor的官方网站下载并安装
nRF Connect for Desktop。 - 打开工具:启动
nRF Connect for Desktop,选择nRF Connect for Bluetooth Low Energy应用。 - 扫描设备:点击“扫描”按钮,搜索附近的BLE设备。
- 连接设备:选择要连接的设备,点击“连接”按钮。
- 服务和特征:连接成功后,工具会自动发现设备上的服务和特征。可以在服务列表中选择特定的服务和特征进行读取、写入或启用通知。
4. 使用nRF Connect for Mobile进行测试
nRF Connect for Mobile是Nordic Semiconductor提供的移动应用,用于测试和调试BLE设备。以下是使用该应用进行测试的步骤:
- 安装应用:从Google Play或Apple App Store下载并安装
nRF Connect for Mobile。 - 打开应用:启动应用,选择“扫描”功能。
- 扫描设备:搜索附近的BLE设备。
- 连接设备:选择要连接的设备,点击“连接”按钮。
- 服务和特征:连接成功后,应用会自动发现设备上的服务和特征。可以在服务列表中选择特定的服务和特征进行读取、写入或启用通知。
结论
蓝牙低功耗(BLE)协议在功耗、连接速度和数据传输方面具有显著的优势,使其成为许多低功耗应用场景的首选技术。通过本文的介绍,读者可以了解BLE的基本架构、数据包格式、连接流程、服务和特征的定义,以及如何在仿真环境中实现BLE通信。希望这些内容能够帮助读者更好地理解和应用BLE技术。