02 BLE 外围设备模式(peripheral)
作者:王世豪
一、BLE 概述
BLE(Bluetooth Low Energy),也称为 Bluetooth Smart,是蓝牙 4.0 及更高版本引入的低功耗无线通信技术,专为低带宽、间歇性数据传输的物联网(IoT)和穿戴设备设计。
Air8101 支持最新的 BLE 5.4 版本,BLE 5.4 在上一代基础上继续优化了功耗和性能,为用户提供了更高效、更稳定的蓝牙连接体验。具体的 BLE 版本区别若有兴趣请自行上网查询,本处不再赘述。
BLE 支持的四种模式
Air8101 的 BLE 支持 4 种模式,分别是中心设备模式(central),外围设备模式(peripheral),广播者模式(ibeacon),以及观察者模式(scan)。
1、中心设备模式(central):
中心设备模式是能够搜索别人并主动建立连接的一方,从扫描状态转化而来的。其可以和一个或多个从设备进行连接通信,它会定期的扫描周围的广播状态设备发送的广播信息,可以对周围设备进行搜索并选择所需要连接的从设备进行配对连接,建立通信链路成功后,主从双方就可以发送接收数据。
2、外围设备模式(peripheral):
外围设备模式是从广播者模式转化而来的,未被连接的外围设备首先进入广播状态,等待被中心设备搜索,当中心设备扫描到外围设备建立连接后,就可以和中心设备进行数据的收发,其不能主动的建立连接,只能等别人来连接自己。和广播模式有区别的地方在于,外围设备模式的设备是可以被连接的,定期的和中心设备进行连接和数据传输,在数据传输过程中作外围设备。
3、广播者模式(ibeacon)
处于广播模式的设备,会周期性的广播 beacon 信息, 可以被扫描, 但一般不会被连接,典型应用 ibeacon。
4、观察者模式(scan)
观察者模式,该模式下模块为非连接,相对广播者模式的一对多发送广播,观察者可以一对多接收数据。在该模式中,设备可以仅监听和读取空中的广播数据。和中心设备唯一的区别是不能发起连接,只能持续扫描外围设备。
蓝牙中的重要概念
1、GATT(通用属性配置文件)
定义 BLE 设备如何组织和传输数据,以 “服务(Service)” 和 “特征(Characteristic)” 为单位。
示例:心率监测设备的 GATT 服务包含 “心率特征”,手机通过读取该特征获取心率数据。
2、服务和特征
服务是特征的容器,通过逻辑分组简化复杂功能的管理;
特征是数据交互的最小单元,通过属性定义实现灵活的读写与推送机制;
两者结合构成 GATT 协议的核心框架,支撑蓝牙设备间的标准化数据交互(如智能穿戴、医疗设备、物联网传感器)。
3、特征的关键属性(Properties)
特征通过 “属性” 定义数据的操作方式,常见属性包括:
1)可读(Read):允许客户端读取特征值(如读取电池电量)。
2)可写(Write):允许客户端写入特征值(如设置设备参数)。
3)通知(Notification):服务端主动发送特征值更新(如心率变化时推送给手机)。
4、UUID
UUID 是蓝牙 GATT 协议的 “数字身份证”,通过标准化的唯一标识机制,实现了跨厂商设备的功能互认(标准 UUID)与厂商个性化功能的扩展(自定义 UUID)
Air8101 的所有操作,都通过 UUID 来索引和管理
二、演示功能概述
本示例使用 Air8101 核心板演示 ble 的 peripheral(外围设备) 功能。
1、Air8101 作为外围设备开启广播,被动等待中心设备发起连接;
2、连接成功后,定期向中心设备发送数据;
3、外围设备收到中心设备的写入数据后,通过 uart1 发送到 pc 端串口工具;
4、pc 端串口工具收到数据后,打印到串口工具窗口。
三、准备硬件环境
3.1 Air8101 核心板
使用 Air8101 核心板,如下图所示:
淘宝购买链接:Air8101 核心板淘宝购买链接 ;
此核心板的详细使用说明参考:硬件手册和证书 - product@air8101 - 合宙模组资料中心中的 Core_Air8101 核心板使用说明 V1.3.pdf。
3.2 PC 电脑
WIN10 以及以上版本的 WINDOWS 系统。
3.3 数据通信线
USB 数据线(其一端为 Type-C 接口,用于连接 Air8101 核心板)。
四、准备软件环境
4.1 软件环境
1、烧录工具:Luatools 下载调试工具
2、内核固件:Air8101 V1006 版本固件(理论上,2025 年 7 月 26 日之后发布的固件都可以)
3、脚本文件:
外围设备:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8101/demo/ble/peripheral
4、PC 端串口工具:例如 SSCOM、LLCOM 等都可以
5、蓝牙调试软件:
本示例使用的蓝牙调试软件是 nrf connect(Android 版本),下载下面的压缩包即可;IOS 版请在APP Store搜索 nrf connect下载。
6、LuatOS 运行所需要的 lib 文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件。
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 核心板中,将本篇文章中演示使用的项目文件烧录到 Air8101 核心板中。
4.2 API 介绍
ble 库:https://docs.openluat.com/osapi/core/ble/
五、程序结构
ble/
├── peripheral/
│ ├── main.lua
│ ├── ble_server_main.lua
│ ├── ble_server_receiver.lua
│ |── ble_server_sender.lua
│ ├── ble_timer_app.lua
| ├── ble_uart_app.lua
│ |── readme.md
5.1 文件说明
-
main.lua
:主程序入口文件。 -
ble_peripheral_main.lua
:ble 外围设备主程序,进行 ble 初始化,设置广播内容,处理各类 ble 事件(连接、断开连接、写入请求等)。 -
ble_peripheral_receiver.lua
:BLE 外围设备接收数据处理。 -
ble_peripheral_sender.lua
:BLE 外围设备发送数据处理。 -
ble_timer_app.lua
:ble 外围设备定时器处理逻辑,启动两个循环定时器,一个是以 notify 方式主动向中心设备推送数据(需中心设备先开启 notify 订阅),另一个是使用 write 方式,更新特征值数据,中心设备需要主动读取特征值获取最新数据。 -
ble_uart_app.lua
:ble 外围设备接 uart 处理逻辑,将收到的中心设备的写入数据,通过 uart 发送到 pc 端串口工具。
六、核心模块详解
6.1 主程序 (main.lua
)
主程序文件 main.lua
是整个项目的入口点。它负责初始化系统环境。
6.1.1 初始化流程
1、项目和版本定义:
定义 PROJECT
和 VERSION
变量。
2、日志记录:
使用 log.info("main", PROJECT, VERSION)
在日志中打印项目名和版本号。
3、看门狗初始化(如果支持):
配置并启动硬件看门狗,防止程序死循环卡死。
4、加载功能模块:
加载 BLE peripheral(外围设备)主控制模块(ble_server_main
)。
加载 wifi 升级模块(check_wifi
)。
加载串口应用功能模块(ble_uart_app
)。
加载定时器应用功能模块(ble_timer_app
)。
5、启动任务调度器:
调用 sys.run()
启动 LuatOS 的任务调度器,开始执行各个任务。
6.2 ble_server_main
本文件为 ble server 主应用功能模块,整个应用通过 sys.taskInitEx 启动主任务,实现了完整的 BLE 外围设备功能,核心业务逻辑为:
6.2.1 初始化与配置
1、加载依赖模块( ble_server_receiver 用于数据接收处理, ble_server_sender 用于数据发送处理)。
2、定义配置参数(自身设备名称、服务 UUID、特征值 UUID、GATT 数据库定义)。
注意:在 GATT 中,UUID 和属性的定义是由外围设备决定的,中心设备需要按照外围设备定义的 UUID 和属性来访问。
config = {
device_name = "LuatOS", -- 设备名称
service_uuid = "FA00", -- 服务UUID
char_uuid1 = "EA01", -- 特征值1 UUID (支持Notify)
char_uuid2 = "EA02", -- 特征值2 UUID (仅支持Write)
char_uuid3 = "EA03", -- 特征值3 UUID (仅支持Read)
}
-- GATT数据库定义
local att_db = {
string.fromHex(config.service_uuid), -- Service UUID
-- Characteristic
{ -- Characteristic 1 (Notify + Read + Write)
string.fromHex(config.char_uuid1),
ble.NOTIFY | ble.READ | ble.WRITE
}, { -- Characteristic 2 (Write)
string.fromHex(config.char_uuid2),
ble.WRITE | ble.WRITE_CMD -- ble.WRITE_CMD 表示支持write no Response写入
}, { -- Characteristic 3 (Read)
string.fromHex(config.char_uuid3),
ble.READ
}
}
3、调用 ble_init(),初始化蓝牙功能,设置广播包内容并开始广播。
作为外围设备,无需主动扫描,而是通过广播让中心设备发现:
-- 设置广播内容
adv_create = adv_create or ble_device:adv_create({
addr_mode = ble.PUBLIC, -- 广播地址模式, 可选值: ble.PUBLIC, ble.RANDOM, ble.RPA, ble.NRPA
channel_map = ble.CHNLS_ALL, -- 广播的通道, 可选值: ble.CHNLS_37, ble.CHNLS_38, ble.CHNLS_39, ble.CHNLS_ALL
intv_min = 120, -- 广播间隔最小值, 单位为0.625ms, 最小值为20, 最大值为10240
intv_max = 120, -- 广播间隔最大值, 单位为0.625ms, 最小值为20, 最大值为10240
adv_data = { -- 支持表格形式, 也支持字符串形式(255字节以内)
{ble.FLAGS, string.char(0x06)}, -- 广播标志位, 0x06: 支持LE Limited Discoverable Mode, 0x04: 支持LE General Discoverable Mode
{ble.COMPLETE_LOCAL_NAME, config.device_name}, -- 广播本地名称
}
})
6.2.2 事件处理
通过 ble_event_cb 回调函数处理各类 BLE 事件:
-
连接成功(EVENT_CONN)
-
断开连接(EVENT_DISCONN)
-
写入请求(EVENT_WRITE)
注意:EVENT_WRITE 事件,是中心设备开启 notify 通知功能,或者向外围设备的特征里写入数据时,外围设备触发的回调事件。
6.2.3 业务功能
-
被动接收中心设备写入的数据:通过 ble_server_receiver.proc() 处理
-
建立连接后,向 ble_server_sender 模块发送"CONNECT_OK"的消息,通过 ble_server_sender 模块向中心设备发送数据。
6.2.4 异常处理
-
初始化失败 :进入异常处理流程。
-
连接断开 :清理资源并等待重连。
-
超时处理 :5 秒后重新启动广播。
6.3 ble_server_receiver
6.3.1 主要功能
-
数据处理 :处理接收到的 BLE 写入请求数据。
-
数据分发 :将收到的数据发给其他模块处理,比如本 demo 便演示了通过 uart 发给 pc 端处理。
当
ble_server_main
模块接收到EVENT_WRITE
事件时,会调用此模块的 proc 函数。将数据发布到对应的消息主题,其他订阅了这些消息主题的模块可以接收并处理数据
6.3.2 核心实现
-
提供
proc(service_uuid, char_uuid, data)
接口函数,接收服务 UUID、特征值 UUID 和数据。 -
通过
sys.publish("RECV_BLE_WRITE_DATA", ...)
发给其他模块处理。
6.4 ble_server_sender
其他模块只需发布 "SEND_DATA_REQ"
消息即可请求外围设备向中心设备发送数据。
6.4.1 主要功能
-
消息订阅:订阅
"SEND_DATA_REQ"
消息,接收其他模块的发送请求。 -
队列管理:维护发送队列 send_queue,存储待发送的数据项(包含服务 UUID、特征值 UUID、数据、回调信息)。
-
任务调度:通过任务处理函数 ble_server_sender_task_func 处理各类 BLE 事件。
-
数据发送:按顺序发送队列中的数据,并通过回调通知发送结果。
6.4.2 核心实现
-
其他模块通过
sys.publish("SEND_DATA_REQ", ...)
发布 发送请求。 -
send_data_req_proc_func
函数将请求数据加入发送队列,并通知任务。 -
任务处理函数根据 BLE 事件状态(连接成功、断开连接等)处理队列数据。
-
send_item_func
函数负责实际发送数据。 -
send_item_cbfunc
函数处理发送结果,调用用户回调。
6.4.3 事件处理
-
CONNECT_OK
:BLE 连接成功,开始发送队列数据。 -
SEND_REQ
:有新数据需要发送,继续处理队列。 -
DISCONNECTED
:连接断开,清空队列并通知所有发送请求失败。
6.5 ble_uart_app
6.5.1 主要功能
-
UART 初始化:打开 UART1 接口,配置波特率 115200、数据位 8、停止位 1、无奇偶校验。
-
数据接收:订阅 "RECV_BLE_WRITE_DATA" 消息,接收来自 BLE 中心设备的写入数据。
-
数据转发:将接收到的 BLE 数据(包含服务 UUID、特征值 UUID 和实际数据)通过 UART1 发送到 PC 端。
6.6 ble_timer_app
6.6.1 主要功能
- 创建两个独立的循环定时器
一个用于定时 以 notify 方式向中心设备推送数据(需中心设备先开启 notify 订阅)。
一个用于定时 更新 特征值数据,中心设备需要主动读取特征值获取最新数据。
6.6.2 核心实现
- 实现两个定时器回调函数:
send_notify_data_timer_cbfunc
:发布 SEND_DATA_REQ
消息到 ble_server_sender 模块。
send_write_data_timer_cbfunc
:发送 SEND_DATA_REQ
消息到 ble_server_sender 模块。
- 启动两个循环定时器,分别绑定上述两个回调函数。
七、结果展示
7.1 外围设备接收中心设备的写入数据
注:nrf connect 作为中心设备,Air8101 作为外围设备。
1、烧录示例 demo 到 Air8101 核心板后,手机端打开 nrf connect 蓝牙调试软件,找到广播的设备名称为"LuatOS123"的设备并连接。
2、手机连接作为外围设备的 Air8101 后,界面如下所示:
Generic Access 和 Generic Attribute 是 BLE 共有的服务,Unknown Service 为广播者自定义添加的服务,点开 Unknown Service ,对应的是自定义的服务 UUID 和特征值 UUID 以及其属性值。
3、中心设备发送,外围设备被动接收
手机通过 nrf connect 中服务 UUID=0xFA00,特征值 UUID=0xEA02(可写操作),向外围设备发送数据。
nrf connect 操作界面如下:
luatools 日志如下:
7.2 外围设备向中心设备发送 notify 数据
注:nrf connect 作为中心设备,Air8101 作为外围设备。外围设备向中心设备发送 notify 数据,需要中心设备先开启 notify 订阅,下图是 nrf connec 开启订阅的方式,点击图标”↓↓↓“即可。
点击图标”↓↓↓“后,APP 后台自动监听从设备 notify 上来的数据,右滑界面,可以看到接收到的每条数据。
八、总结
本文介绍了 Air8101 的 BLE 外围设备模式,通过示例演示了如何向中心设备发送通知数据,以及如何接收中心设备发过来的数据。