【Zephyr|ESP32-S3】基础学习:BLE服务搭建与手机蓝牙控灯哈喽,我是余火,一个普通的牛马打工人,目前正在学如何使用Zephyr RTOS。之前已通过 UDP server 实现了局域网控灯,手机或电脑发个命令过去,WS2812 就变色。这次来试试给ESP32-S3加上BLE(蓝牙低功耗)——手机通过蓝牙直连板子来发命令控灯。💡本篇学习目标•bt_enable()/bt_le_adv_start():BLE 协议栈初始化与广播•BT_GATT_SERVICE_DEFINE:GATT 服务静态注册改了哪些东西文件改了什么prj.conf新增 4 行 BLE 配置boards/...overlay显式启用esp32_bt_hci节点CMakeLists.txt追加src/ble.csrc/ble.c新增,BLE 初始化 + GATT 服务 + 广播src/ble.h新增,ble_init()声明src/main.c追加ble_init_entry线程src/wifi.c/h无改动src/udp_server.c/h无改动BLE 基础概念BLE 和经典蓝牙不是一回事——BLE 专为低功耗设计,速率低但省电,适合 IoT 设备的短距离通信。对比项经典蓝牙BLE速率高(音频传输)低(125Kbps~2Mbps)功耗高极低(纽扣电池能用几个月)适用场景耳机、音箱IoT 设备、传感器、手环BLE 协议栈分多层,从硬件到应用逐层封装:Application(你的代码:ble.c / cmd_dispatch.c) │ ▼ GATT(Generic Attribute Profile)── 语义层:Service / Characteristic │ ▼ ATT(Attribute Protocol)── 读写层:像对象的属性 get/set │ ▼ L2CAP(Logical Link Control)── 通道复用 + 分片重组 │ ▼ Link Layer ── 跳频、加密、连接管理 │ ▼ Physical(RF 2.4GHz ISM band)── 调制解调GAP 和 GATT 是 BLE 协议栈中两个核心 Profile,各管各的事:层全称职责GAPGeneric Access Profile设备怎么被发现和连接(广播、扫描)GATTGeneric Attribute Profile连接后怎么交换数据(服务、特征值、读写)GATT 的层级结构:Service → Characteristic。Service 是一个功能单元,Characteristic 是里面的数据点,每个 Characteristic 有自己的 UUID 和读写属性。UUID 类型:类型长度示例用途16-bit4位hex0x180F(Battery Service)、0x180D(Heart Rate)BLE SIG 分配的标准服务,自动识别128-bit32位hexf0000000-1212-46ef-9242-8da2ba3e6a00自定义服务和特征值本篇用自定义 128-bit UUID,避免和标准服务冲突。自定义 UUID 手机 App 不认识,会显示为 Unknown Service,这是正常的。BLE 连接流程很简单:手机扫描 → 发现板子广播 → 连接 → 自动发现服务 → 读写特征值。💡GATT 和面向对象的类比:GATT 的 Service/Characteristic 模式很像面向对象的类/属性——Service 就像"类"(一个功能单元),Characteristic 就像"属性"(一个数据点),UUID 就是"属性名",Write/Notify 就是"setter/getter"。BLE 底层用的 ATT 协议就是"属性的读写",GATT 只是在上面加了语义层。启用 BLE 配置prj.conf 新增 4 行:CONFIG_BT=y # 启用 BLE 子系统(会自动选中 GATT、ATT 等依赖项) CONFIG_BT_PERIPHERAL=y # 外设角色:板子作为被连接方(手机是中央设备) CONFIG_BT_DEVICE_NAME="Zephyr-WS2812" # BLE 广播时对外显示的设备名 CONFIG_BT_MAX_CONN=1 # 最大同时连接数,只允许一个设备连接(省内存)配置项作用依据CONFIG_BT=y启用 BLE 子系统所有 BLE sample 必须CONFIG_BT_PERIPHERAL=y外设角色(被连接方)peripheral系列 sample 均使用CONFIG_BT_DEVICE_NAME广播设备名peripheralsample 使用CONFIG_BT_DEVICE_NAMECONFIG_BT_MAX_CONN=1只允许一个设备连接精简内存占用💡三个"想当然但错了"的配置:CONFIG_BT_GATT=y不需要手动写(CONFIG_BT=y自动选中,手动写反而报 unused 警告);CONFIG_BT_WIFI_COEX=y这个符号不存在(很多教程误传);同时开CONFIG_WIFI=y和CONFIG_BT=y时共存功能自动启用(CONFIG_ESP32_SW_COEXIST_ENABLE),不需要手动加任何共存配置项。overlay 新增 BT HCI 节点:/* ESP32-S3 的蓝牙控制器通过 VHCI 接口和 CPU 通信(RAM 回调,不走 UART/SPI), * 默认 status = "disabled",必须在 overlay 中显式启用才会加载驱动 */ esp32_bt_hci { status = "okay"; };ESP32-S3 的 BT HCI 节点默认disabled,必须在 overlay 中显式启用。dtsi 中的chosen { zephyr,bt-hci = esp32_bt_hci; }已配好,不需要重复声明。GATT 服务定义ble.h —— 对外只暴露一个初始化接口:#ifndefBLE_H#defineBLE_Hvoidble_init(void);#endifble.c —— 自定义 UUID:#includestring.h#includezephyr/kernel.h#includezephyr/bluetooth/bluetooth.h#includezephyr/bluetooth/gatt.h#includezephyr/bluetooth/uuid.h#includezephyr/logging/log.h#include
【Zephyr|ESP32-S3】基础学习:BLE服务搭建与手机蓝牙控灯
发布时间:2026/6/13 7:32:03
【Zephyr|ESP32-S3】基础学习:BLE服务搭建与手机蓝牙控灯哈喽,我是余火,一个普通的牛马打工人,目前正在学如何使用Zephyr RTOS。之前已通过 UDP server 实现了局域网控灯,手机或电脑发个命令过去,WS2812 就变色。这次来试试给ESP32-S3加上BLE(蓝牙低功耗)——手机通过蓝牙直连板子来发命令控灯。💡本篇学习目标•bt_enable()/bt_le_adv_start():BLE 协议栈初始化与广播•BT_GATT_SERVICE_DEFINE:GATT 服务静态注册改了哪些东西文件改了什么prj.conf新增 4 行 BLE 配置boards/...overlay显式启用esp32_bt_hci节点CMakeLists.txt追加src/ble.csrc/ble.c新增,BLE 初始化 + GATT 服务 + 广播src/ble.h新增,ble_init()声明src/main.c追加ble_init_entry线程src/wifi.c/h无改动src/udp_server.c/h无改动BLE 基础概念BLE 和经典蓝牙不是一回事——BLE 专为低功耗设计,速率低但省电,适合 IoT 设备的短距离通信。对比项经典蓝牙BLE速率高(音频传输)低(125Kbps~2Mbps)功耗高极低(纽扣电池能用几个月)适用场景耳机、音箱IoT 设备、传感器、手环BLE 协议栈分多层,从硬件到应用逐层封装:Application(你的代码:ble.c / cmd_dispatch.c) │ ▼ GATT(Generic Attribute Profile)── 语义层:Service / Characteristic │ ▼ ATT(Attribute Protocol)── 读写层:像对象的属性 get/set │ ▼ L2CAP(Logical Link Control)── 通道复用 + 分片重组 │ ▼ Link Layer ── 跳频、加密、连接管理 │ ▼ Physical(RF 2.4GHz ISM band)── 调制解调GAP 和 GATT 是 BLE 协议栈中两个核心 Profile,各管各的事:层全称职责GAPGeneric Access Profile设备怎么被发现和连接(广播、扫描)GATTGeneric Attribute Profile连接后怎么交换数据(服务、特征值、读写)GATT 的层级结构:Service → Characteristic。Service 是一个功能单元,Characteristic 是里面的数据点,每个 Characteristic 有自己的 UUID 和读写属性。UUID 类型:类型长度示例用途16-bit4位hex0x180F(Battery Service)、0x180D(Heart Rate)BLE SIG 分配的标准服务,自动识别128-bit32位hexf0000000-1212-46ef-9242-8da2ba3e6a00自定义服务和特征值本篇用自定义 128-bit UUID,避免和标准服务冲突。自定义 UUID 手机 App 不认识,会显示为 Unknown Service,这是正常的。BLE 连接流程很简单:手机扫描 → 发现板子广播 → 连接 → 自动发现服务 → 读写特征值。💡GATT 和面向对象的类比:GATT 的 Service/Characteristic 模式很像面向对象的类/属性——Service 就像"类"(一个功能单元),Characteristic 就像"属性"(一个数据点),UUID 就是"属性名",Write/Notify 就是"setter/getter"。BLE 底层用的 ATT 协议就是"属性的读写",GATT 只是在上面加了语义层。启用 BLE 配置prj.conf 新增 4 行:CONFIG_BT=y # 启用 BLE 子系统(会自动选中 GATT、ATT 等依赖项) CONFIG_BT_PERIPHERAL=y # 外设角色:板子作为被连接方(手机是中央设备) CONFIG_BT_DEVICE_NAME="Zephyr-WS2812" # BLE 广播时对外显示的设备名 CONFIG_BT_MAX_CONN=1 # 最大同时连接数,只允许一个设备连接(省内存)配置项作用依据CONFIG_BT=y启用 BLE 子系统所有 BLE sample 必须CONFIG_BT_PERIPHERAL=y外设角色(被连接方)peripheral系列 sample 均使用CONFIG_BT_DEVICE_NAME广播设备名peripheralsample 使用CONFIG_BT_DEVICE_NAMECONFIG_BT_MAX_CONN=1只允许一个设备连接精简内存占用💡三个"想当然但错了"的配置:CONFIG_BT_GATT=y不需要手动写(CONFIG_BT=y自动选中,手动写反而报 unused 警告);CONFIG_BT_WIFI_COEX=y这个符号不存在(很多教程误传);同时开CONFIG_WIFI=y和CONFIG_BT=y时共存功能自动启用(CONFIG_ESP32_SW_COEXIST_ENABLE),不需要手动加任何共存配置项。overlay 新增 BT HCI 节点:/* ESP32-S3 的蓝牙控制器通过 VHCI 接口和 CPU 通信(RAM 回调,不走 UART/SPI), * 默认 status = "disabled",必须在 overlay 中显式启用才会加载驱动 */ esp32_bt_hci { status = "okay"; };ESP32-S3 的 BT HCI 节点默认disabled,必须在 overlay 中显式启用。dtsi 中的chosen { zephyr,bt-hci = esp32_bt_hci; }已配好,不需要重复声明。GATT 服务定义ble.h —— 对外只暴露一个初始化接口:#ifndefBLE_H#defineBLE_Hvoidble_init(void);#endifble.c —— 自定义 UUID:#includestring.h#includezephyr/kernel.h#includezephyr/bluetooth/bluetooth.h#includezephyr/bluetooth/gatt.h#includezephyr/bluetooth/uuid.h#includezephyr/logging/log.h#include