BLE开发入门:5分钟搞懂GAP和GATT的核心区别(附nRF51822实战代码)

张开发
2026/4/12 17:06:50 15 分钟阅读

分享文章

BLE开发入门:5分钟搞懂GAP和GATT的核心区别(附nRF51822实战代码)
BLE开发实战指南从GAP/GATT原理到nRF51822代码实现当你第一次拆开nRF51822开发板的包装时那些密密麻麻的引脚和陌生的术语可能让你望而生畏。作为低功耗蓝牙(BLE)开发的核心GAP和GATT这对双子星协议构成了所有通信的基础框架。但别担心我们不需要成为协议专家才能开始开发——就像开车不需要精通内燃机原理一样。本文将用最直白的语言和可立即运行的代码带你穿透概念迷雾直接进入实战环节。1. GAP蓝牙世界的社交礼仪想象你走进一个社交场合GAP就是决定你如何自我介绍、如何回应他人搭讪的那套规则。在nRF51822的softdevice协议栈中GAP层的配置直接决定了设备能否被其他蓝牙主机发现。1.1 设备角色中心与外设的舞蹈在nRF51822的SDK中角色选择就像设置一个开关那么简单// 设置为外设角色 ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN(sec_mode); sd_ble_gap_device_name_set(sec_mode, MyBLEDevice, strlen(MyBLEDevice)); // 设置为广播模式 ble_gap_adv_params_t adv_params { .type BLE_GAP_ADV_TYPE_ADV_IND, .interval MSEC_TO_UNITS(100, UNIT_0_625_MS), .timeout 0 };关键参数说明ADV_IND表示可连接的非定向广播interval值决定了广播频率100ms是平衡功耗和响应速度的常用值1.2 广播数据包解析广播包就像电子名片下面是一个典型的广播数据结构数据类型长度内容示例说明Flags30x020106基础功能标识完整设备名可变TempSensor01可选的设备名称服务UUID160x180A设备主服务的UUID发射功率20x08信号强度参考值在代码中这样设置广播数据uint8_t adv_data[] { 0x02, 0x01, 0x06, 0x03, 0x03, 0x12, 0x18, 0x0A, 0x09, T,e,m,p,S,e,n,s,o,r };实际项目中建议将设备名放在扫描响应数据中以节省广播包空间2. GATT数据交换的语言规则当两个设备通过GAP建立连接后GATT就开始接管通信管理。如果把GAP比作电话拨号那么GATT就是通话内容的语法规则。2.1 服务与特征的实质在nRF51822中创建一个温度监测服务// 定义服务UUID #define TEMP_SERVICE_UUID 0x1234 // 定义特征值 BLE_UUID_TYPE_BLE uuid_temp { .uuid TEMP_SERVICE_UUID, .type BLE_UUID_TYPE_BLE }; // 添加特征 ble_gatts_char_md_t char_md; ble_gatts_attr_t attr_char_value; ble_gatts_attr_md_t attr_md; // ... (属性元数据配置省略) sd_ble_gatts_characteristic_add(service_handle, char_md, attr_char_value, char_handles);典型GATT服务结构服务声明(必须)UUID: 0x2800值: 服务UUID特征声明(必须)UUID: 0x2803值: 特征属性句柄特征值(必须)实际数据存储位置描述符(可选)如CCCD(0x2902)用于通知功能2.2 通知(Notify)与指示(Indicate)这两种数据推送方式的代码实现差异// 启用通知 uint8_t cccd_value BLE_GATT_HVX_NOTIFICATION; sd_ble_gatts_hvx(conn_handle, ¶ms); // 启用指示(需要确认) uint8_t cccd_value BLE_GATT_HVX_INDICATION; sd_ble_gatts_hvx(conn_handle, ¶ms);指示(Indicate)比通知(Notify)更可靠但功耗更高适合关键数据传输3. nRF51822实战构建环境监测节点让我们把这些理论转化为一个真实项目——通过BLE传输温度和湿度数据。3.1 硬件配置清单nRF51822开发板SHTC3温湿度传感器(I²C接口)纽扣电池供电电路调试用J-Link仿真器3.2 服务端完整代码框架// 服务定义 static ble_envs_t m_envs; void env_service_init(void) { ble_uuid_t service_uuid; ble_uuid128_t base_uuid {0x23,0xD1,0xBC,0xEA,0x5F,0x78,0x23,0x15, 0xDE,0xEF,0x12,0x12,0x00,0x00,0x00,0x00}; service_uuid.uuid ENV_SERVICE_UUID; sd_ble_uuid_vs_add(base_uuid, service_uuid.type); // 添加服务和特征(代码略) } // 传感器数据更新 void env_data_update() { int16_t temp read_temperature(); uint16_t humi read_humidity(); ble_gatts_hvx_params_t hvx_params; hvx_params.handle m_envs.temp_handles.value_handle; hvx_params.p_data temp; hvx_params.p_len sizeof(temp); sd_ble_gatts_hvx(m_conn_handle, hvx_params); }3.3 客户端数据接收处理在手机端(Android)的典型处理代码Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { UUID uuid characteristic.getUuid(); if(uuid.equals(TEMP_CHAR_UUID)) { int temperature characteristic.getIntValue( BluetoothGattCharacteristic.FORMAT_SINT16, 0); updateTemperatureUI(temperature); } }4. 性能优化与调试技巧当你的BLE设备开始实际运行时这些经验可能会挽救你的项目进度。4.1 连接参数协商策略推荐参数组合场景最小间隔(ms)最大间隔(ms)延迟(次)超时(s)实时控制153004常规传感器10020026超低功耗8001000610在nRF51822中设置参数ble_gap_conn_params_t gap_conn_params { .min_conn_interval MSEC_TO_UNITS(100, UNIT_1_25_MS), .max_conn_interval MSEC_TO_UNITS(200, UNIT_1_25_MS), .slave_latency 2, .conn_sup_timeout MSEC_TO_UNITS(6000, UNIT_10_MS) };4.2 常见问题排查表现象可能原因解决方法设备无法发现广播未启动/参数错误检查sd_ble_gap_adv_start()返回值连接频繁断开连接间隔太短重新协商连接参数数据吞吐量低MTU大小默认23字节协商更大的MTU(如247字节)通知不工作CCCD未正确写入使用nRF Connect验证描述符值在开发过程中我习惯在初始化代码中加入这些验证点检查softdevice是否已启用验证RAM区域是否冲突确认所有UUID已正确添加测试不同手机型号的兼容性

更多文章