01 BLE 中心设备模式(central)
一、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 中心设备模式:一个核心板做中心设备(烧录 central demo),另一个核心板做外围设备(烧录 peripheral demo)。
演示功能概述如下:
1、ble 中心设备扫描并连接外围设备;
2、ble 中心设备连接成功后,开始定时读取外围设备特征值 UUID 数据, 同时也定时发送数据给外围设备;
3、ble 中心设备收到外围设备特征值 UUID 的 notify 数据后,通过 uart 发送到 pc 端串口工具;
4、pc 端串口工具收到数据后,打印到串口工具窗口。
三、准备硬件环境
3.1 Air8101 核心板
使用 Air8101 核心板,如下图所示:
淘宝购买链接:Air8101 核心板淘宝购买链接 ;
此核心板的详细使用说明参考:硬件手册和证书 中的 Air8101 核心板使用说明。
3.2 PC 电脑
WIN10 以及以上版本的 WINDOWS 系统。
3.3 数据通信线
USB 数据线(其一端为 Type-C 接口,用于连接 Air8101 开发板)。
四、准备软件环境
4.1 软件环境
1、烧录工具:Luatools 下载调试工具
2、内核固件:Air8101 V1005 版本固件(理论上,2025 年 7 月 26 日之后发布的固件都可以)
3、脚本文件:
中心设备:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8101/demo/ble/central
外围设备:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8101/demo/ble/peripheral
4、PC 端串口工具:例如 SSCOM、LLCOM 等都可以
5、LuatOS 运行所需要的 lib 文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件。
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 核心板中,将本篇文章中演示使用的项目文件烧录到 Air8101 核心板中。
4.2 API 介绍
ble 库:https://docs.openluat.com/osapi/core/ble/
五、程序结构
ble/
├── central/
│ ├── main.lua
│ ├── ble_client_main.lua
│ ├── ble_client_receiver.lua
│ |── ble_client_sender.lua
│ ├── ble_timer_app.lua
│ |── readme.md
5.1 文件说明
-
main.lua
:主程序入口文件。 -
ble_client_main.lua
:BLE 中心设备主程序,进行 BLE 初始化,处理各类 BLE 事件(连接、断开连接、扫描报告、GATT 操作完成等)。 -
ble_client_receiver.lua
:BLE 中心设备接收数据处理。 -
ble_client_sender.lua
:BLE 中心设备发送数据处理。 -
ble_timer_app.lua
:BLE 中心设备定时器处理逻辑,启动两个循环定时器,一个用于定时读取外围设备特征值 UUID 数据,一个用于定时向外围设备特征值 UUID 发送数据。 -
ble_uart_app.lua
:BLE 中心设备接 uart 处理逻辑,将收到的 notify 数据,通过 uart 发送到 pc 端串口工具。
六、核心模块详解
6.1 主程序 (main.lua
)
主程序文件 main.lua
是整个项目的入口点。它负责初始化系统环境。
6.1.1 初始化流程
1、项目和版本定义:
定义 PROJECT
和 VERSION
变量。
2、日志记录:
使用 log.info("main", PROJECT, VERSION)
在日志中打印项目名和版本号。
3、看门狗初始化(如果支持):
配置并启动硬件看门狗,防止程序死循环卡死。
4、加载功能模块:
加载 BLE Central(中心设备)主控制模块(ble_client_main
)。
加载串口应用功能模块(ble_uart_app
)。
加载定时器应用功能模块(ble_timer_app
)。
5、启动任务调度器:
调用 sys.run()
启动 LuatOS 的任务调度器,开始执行各个任务。
6.2 ble_client_main
本文件为 ble client 主应用功能模块,整个应用通过 sysplus.taskInitEx 启动主任务,实现了完整的 BLE 中心设备功能,包括设备发现、连接管理、数据收发和异常恢复机制。核心业务逻辑为:
6.2.1 初始化与配置
-
加载依赖模块( ble_client_receiver 用于数据接收处理, ble_client_sender 用于数据发送处理)。
-
定义配置参数(目标设备名称、服务 UUID、特征值 UUID、超时时间等)。
-
调用 ble_init(),初始化蓝牙功能。
6.2.2 设备扫描与连接
-
创建并启动 BLE 扫描(默认参数:公共地址模式、扫描间隔 100ms、扫描窗口 100ms)。
-
通过 is_target_device 函数过滤扫描到的设备(匹配设备名称)。
-
发现目标设备后停止扫描并发起连接。
-
连接超时处理和重连机制。
6.2.3 事件处理
通过 ble_event_cb 回调函数处理各类 BLE 事件:
-
连接成功(EVENT_CONN)
-
断开连接(EVENT_DISCONN)
-
扫描报告(EVENT_SCAN_REPORT)
-
GATT 操作完成(EVENT_GATT_DONE)
-
读取特征值完成(EVENT_READ_VALUE)
6.2.4 业务功能
-
GATT 服务发现完成后,自动启用目标特征值的通知监听。
-
接收并处理来自其他模块的读取请求(
READ_REQ
)。 -
通过消息队列与其他模块通信。
6.2.5 异常处理
-
扫描超时或连接失败时触发异常处理。
-
断开连接后自动清理消息队列并尝试重连。
-
异常情况下 5 秒后重新开始扫描连接。
6.2 ble_client_receiver
6.2.1 主要功能
-
数据分类处理 :接收两类数据(外围设备通知数据和主动读取到的数据)。
-
数据分发 :根据数据类型(通过特征值 UUID 区分)发布到不同的消息队列,供其他模块处理。
6.2.2 核心实现
-
提供
proc(service_uuid, char_uuid, data)
接口函数,接收服务 UUID、特征值 UUID 和数据。 -
通过判断特征值 UUID 是否匹配配置中的
target_notify_char
或target_read_char
来区分数据类型。 -
对于外围设备的通知数据,通过
sys.publish("RECV_BLE_NOTIFY_DATA", ...)
发布。 -
对于主动读取到的数据,通过
sys.publish("RECV_BLE_READ_DATA", ...)
发布。
6.2.3 数据流转
-
当
ble_client_main
模块接收到EVENT_READ_VALUE
事件时,会调用此模块的 proc 函数。 -
本模块将数据分类后发布到对应的消息主题。
-
其他订阅了这些消息主题的模块可以接收并处理数据。
6.3 ble_client_sender
其他模块只需发布 "SEND_DATA_REQ"
消息即可请求中心设备向外围设备发送数据。
6.3.1 主要功能
-
消息订阅:订阅
"SEND_DATA_REQ"
消息,接收其他模块的发送请求。 -
队列管理:维护发送队列 send_queue,存储待发送的数据项(包含服务 UUID、特征值 UUID、数据、回调信息)。
-
任务调度:通过任务处理函数 ble_client_sender_task_func 处理各类 BLE 事件。
-
数据发送:按顺序发送队列中的数据,并通过回调通知发送结果。
6.3.2 核心实现
-
其他模块通过
sys.publish("SEND_DATA_REQ", ...)
发布 发送请求。 -
send_data_req_proc_func
函数将请求数据加入发送队列,并通知任务。 -
任务处理函数根据 BLE 事件状态(连接成功、断开连接等)处理队列数据。
-
send_item_func
函数负责实际发送数据。 -
send_item_cbfunc
函数处理发送结果,调用用户回调。
6.3.3 事件处理
-
CONNECT_OK
:BLE 连接成功,开始发送队列数据。 -
SEND_REQ
:有新数据需要发送,继续处理队列。 -
DISCONNECTED
:连接断开,清空队列并通知所有发送请求失败。
6.4 ble_uart_app
6.4.1 主要功能
-
UART 初始化:打开 UART1 接口,配置波特率 115200、数据位 8、停止位 1、无奇偶校验。
-
数据接收:订阅 "RECV_BLE_NOTIFY_DATA" 消息,接收来自 BLE 外围设备的通知数据。
-
数据转发:将接收到的 BLE 数据(包含服务 UUID、特征值 UUID 和实际数据)格式化后通过 UART1 发送到 PC 端。
6.5 ble_timer_app
6.5.1 主要功能
-
创建两个独立的 5 秒循环定时器
-
一个用于定时 发送 数据到外围设备特定特征值 UUID。
-
一个用于定时 读取 外围设备特定特征值 UUID 的数据。
6.5.2 核心实现
-
定义了目标服务 UUID( FA00 )和特征值 UUID(写: EA02 ,读: EA03 )。
-
实现数据发送结果回调函数 send_data_cbfunc ,用于处理发送成功/失败的通知。
-
实现两个定时器回调函数:
-
send_data_req_timer_cbfunc
:发布SEND_DATA_REQ
消息到 ble_client_sender 模块。 -
read_data_req_timer_cbfunc
:发送READ_REQ
请求到 ble_client_main 模块。 -
启动两个 5 秒循环定时器,分别绑定上述两个回调函数。
6.5.3 数据流转
-
发送流程:定时器触发 → 发布
SEND_DATA_REQ
消息 →ble_client_sender
处理 → 回调通知结果。 -
读取流程:定时器触发 → 发送
READ_REQ
请求 →ble_client_main
处理 → 结果通过事件返回。
七、结果展示
7.1 中心设备订阅外围设备特征通知(Notify)
1、中心设备端实现
在 ble_client_main.lua 文件中,在 ble.EVENT_GATT_DONE
事件触发后,开启 notify 监听,监听外围设备指定服务和特征值的通知,中心设备收到 notify 数据后,将数据通过 uart1 发送到 PC 端。开启监听的主要 demo 如下:
local notify_params = {
uuid_service = string.fromHex(config.target_service_uuid),
uuid_characteristic = string.fromHex(config.target_notify_char)
}
ble_device:notify_enable(notify_params, true)
2、外围设备端要求
服务 UUID 和特征 UUID 需要和上面中心设备端实现的一致,同时特征 UUID 的属性需包含 NOTIFY,才能正常通信。
服务 UUID:FA00,特征 UUID:EA01。
local wt = {
uuid_service = string.fromHex("FA00"),
uuid_characteristic = string.fromHex("EA01"),
}
local result = ble_device:write_notify(wt, "123456" .. os.date())
log.info("ble", "发送数据", result)
3、结果展示
7.2 中心设备写入特征值(Write)
1、中心设备端实现
ble_timer_app.lua 中,启动 5 秒的循环定时器,发布 SEND_DATA_REQ
消息到 ble_client_sender 模块,ble_client_sender 模块订阅到消息后,开始调用 write_value 向外围设备特征值写入数据,关键发送部分 demo 如下所示:
-- 发送数据
local write_params = {
uuid_service = string.fromHex(item.service_uuid),
uuid_characteristic = string.fromHex(item.char_uuid)
}
local data = item.data
local result = ble_device:write_value(write_params, data)
2、外围设备端要求
服务 UUID 和特征 UUID 需要和上面中心设备端实现的一致,同时特征 UUID 的属性需包含 WRITE。
服务 UUID:FA00,特征 UUID:EA02。
触发 ble.EVENT_WRITE 事件,接收到写请求并通过 luatools 打印出来。
3、结果展示
7.3 中心设备读取特征值(Read)
1、中心设备端实现
ble_timer_app.lua 中,启动 5 秒的循环定时器,发送 READ_REQ
请求,ble_client_main 模块收到请求后通过 read_value 开始读取外围设备特征值数据,读取成功后将数据转给 ble_client_receiver 模块处理,关键 demo 如下所示:
-- 从消息中获取传入的UUID参数,若没有则使用默认配置
local service_uuid = msg[3] or config.target_service_uuid
local char_uuid = msg[4] or config.target_read_char
local read_params = {
uuid_service = string.fromHex(service_uuid),
uuid_characteristic = string.fromHex(char_uuid)
}
ble_device:read_value(read_params)
2、外围设备端要求
服务 UUID 和特征 UUID 需要和上面中心设备端实现的一致,同时特征 UUID 的属性需包含 READ。
服务 UUID:FA00,特征 UUID:EA03。
local wt = {
uuid_service = string.fromHex("FA00"),
uuid_characteristic = string.fromHex("EA03"),
}
ble_device:write_value(wt, "8888 123454")
3、结果展示
八、总结
本篇文档介绍了 Air8101 的 BLE central 模式,通过两个 Air8101 核心板:一个作中心设备,一个作外围设备,演示了 BLE 中心设备三大核心操作:
1)订阅通知(Notify):自动获取外围设备推送的数据,
2)写入特征值(Write):用于发送控制指令,要求外围设备特征支持 WRITE 属性;
3)读取特征值(Read):主动获取外围设备状态,需外围设备开放 READ 权限。
三种操作均需中心设备和外围设备的服务/特征 UUID 严格匹配。