跳转至

01 BLE 中心设备模式(central)

作者:王世豪

一、BLE 概述

BLE(Bluetooth Low Energy),也称为 Bluetooth Smart,是蓝牙 4.0 及更高版本引入的低功耗无线通信技术,专为低带宽、间歇性数据传输的物联网(IoT)和穿戴设备设计。

Air8000 支持最新的 BLE 5.4 版本,BLE 5.4 在上一代基础上继续优化了功耗和性能,为用户提供了更高效、更稳定的蓝牙连接体验。具体的 BLE 版本区别若有兴趣请自行上网查询,本处不再赘述。

BLE 支持的四种模式

Air8000 的 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)

Air8000 的所有操作,都通过 UUID 来索引和管理

二、演示功能概述

本示例使用两个 Air8000 核心板来演示 BLE 中心设备模式:一个核心板做中心设备(烧录 central demo),另一个核心板做外围设备(烧录 peripheral demo)。

演示功能概述如下:

1、ble 中心设备扫描并连接外围设备;

2、ble 中心设备连接成功后,开始定时读取外围设备特征值 UUID 数据, 同时也定时发送数据给外围设备;

3、ble 中心设备收到外围设备特征值 UUID 的 notify 数据后,通过 uart 发送到 pc 端串口工具;

4、pc 端串口工具收到数据后,打印到串口工具窗口。

三、准备硬件环境

3.1 Air8000 核心板

使用 Air8000 核心板,如下图所示:

淘宝购买链接:Air8000 核心板淘宝购买链接

此核心板的详细使用说明参考:硬件手册和证书 - product@air8000 - 合宙模组资料中心中的 Core_Air8000 核心板使用说明 V1.3.pdf

3.2 PC 电脑

WIN10 以及以上版本的 WINDOWS 系统。

3.3 数据通信线

USB 数据线(其一端为 Type-C 接口,用于连接 Air8000 开发板)。

四、准备软件环境

4.1 软件环境

1、 烧录工具:Luatools 下载调试工具

2、内核固件:Air8000 V2012 版本固件(理论上,2025 年 7 月 26 日之后发布的固件都可以)

3、脚本文件:

中心设备:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/ble/central

外围设备:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/ble/peripheral

4、PC 端串口工具:例如 SSCOM、LLCOM 等都可以

5、LuatOS 运行所需要的 lib 文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件。

准备好软件环境之后,接下来查看如何烧录项目文件到 Air8000 核心板中,将本篇文章中演示使用的项目文件烧录到 Air8000 开发板中。

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
   |── check_wifi.lua
   |── readme.md

5.1 文件说明

  1. main.lua:主程序入口文件。

  2. ble_client_main.lua:BLE 中心设备主程序,进行 BLE 初始化,处理各类 BLE 事件(连接、断开连接、扫描报告、GATT 操作完成等)。

  3. ble_client_receiver.lua:BLE 中心设备接收数据处理。

  4. ble_client_sender.lua:BLE 中心设备发送数据处理。

  5. ble_timer_app.lua:BLE 中心设备定时器处理逻辑,启动两个循环定时器,一个用于定时读取外围设备特征值 UUID 数据,一个用于定时向外围设备特征值 UUID 发送数据。

  6. ble_uart_app.lua:BLE 中心设备接 uart 处理逻辑,将收到的 notify 数据,通过 uart 发送到 pc 端串口工具。

  7. check_wifi.lua:Air8000 的蓝牙功能依赖 WiFi 协处理器,需确保 WiFi 固件为最新版本。本脚本文件检查当前 Air8000 模组的 WiFi 固件是否为最新版本,若不是则自动启动升级(需插入可联网的 SIM 卡)

六、核心模块详解

6.1 主程序 (main.lua)

主程序文件 main.lua 是整个项目的入口点。它负责初始化系统环境。

6.1.1 初始化流程

1、项目和版本定义

定义 PROJECTVERSION 变量。

2、日志记录

使用 log.info("main", PROJECT, VERSION) 在日志中打印项目名和版本号。

3、看门狗初始化(如果支持):

配置并启动硬件看门狗,防止程序死循环卡死。

4、加载功能模块

加载 BLE Central(中心设备)主控制模块(ble_client_main)。

加载 wifi 升级模块(check_wifi)。

加载串口应用功能模块(ble_uart_app)。

加载定时器应用功能模块(ble_timer_app)。

5、启动任务调度器

调用 sys.run() 启动 LuatOS 的任务调度器,开始执行各个任务。

6.2 ble_client_main

本文件为 ble client 主应用功能模块,整个应用通过 sysplus.taskInitEx 启动主任务,实现了完整的 BLE 中心设备功能,包括设备发现、连接管理、数据收发和异常恢复机制。核心业务逻辑为:

6.2.1 初始化与配置

  1. 加载依赖模块( ble_client_receiver 用于数据接收处理, ble_client_sender 用于数据发送处理)。

  2. 定义配置参数(目标设备名称、服务 UUID、特征值 UUID、超时时间等)。

  3. 调用 ble_init(),初始化蓝牙功能。

6.2.2 设备扫描与连接

  1. 创建并启动 BLE 扫描(默认参数:公共地址模式、扫描间隔 100ms、扫描窗口 100ms)。

  2. 通过 is_target_device 函数过滤扫描到的设备(匹配设备名称)。

  3. 发现目标设备后停止扫描并发起连接。

  4. 连接超时处理和重连机制。

6.2.3 事件处理

通过 ble_event_cb 回调函数处理各类 BLE 事件:

  1. 连接成功(EVENT_CONN)

  2. 断开连接(EVENT_DISCONN)

  3. 扫描报告(EVENT_SCAN_REPORT)

  4. GATT 操作完成(EVENT_GATT_DONE)

  5. 读取特征值完成(EVENT_READ_VALUE)

6.2.4 业务功能

  1. GATT 服务发现完成后,自动启用目标特征值的通知监听。

  2. 接收并处理来自其他模块的读取请求( READ_REQ )。

  3. 通过消息队列与其他模块通信。

6.2.5 异常处理

  1. 扫描超时或连接失败时触发异常处理。

  2. 断开连接后自动清理消息队列并尝试重连。

  3. 异常情况下 5 秒后重新开始扫描连接。

6.3 ble_client_receiver

6.3.1 主要功能

  1. 数据分类处理 :接收两类数据(外围设备通知数据和主动读取到的数据)。

  2. 数据分发 :根据数据类型(通过特征值 UUID 区分)发布到不同的消息队列,供其他模块处理。

6.3.2 核心实现

  1. 提供 proc(service_uuid, char_uuid, data) 接口函数,接收服务 UUID、特征值 UUID 和数据。

  2. 通过判断特征值 UUID 是否匹配配置中的 target_notify_chartarget_read_char 来区分数据类型。

  3. 对于外围设备的通知数据,通过 sys.publish("RECV_BLE_NOTIFY_DATA", ...) 发布。

  4. 对于主动读取到的数据,通过 sys.publish("RECV_BLE_READ_DATA", ...) 发布。

6.3.3 数据流转

  1. ble_client_main 模块接收到 EVENT_READ_VALUE 事件时,会调用此模块的 proc 函数。

  2. 本模块将数据分类后发布到对应的消息主题。

  3. 其他订阅了这些消息主题的模块可以接收并处理数据。

6.4 ble_client_sender

其他模块只需发布 "SEND_DATA_REQ" 消息即可请求中心设备向外围设备发送数据。

6.4.1 主要功能

  1. 消息订阅:订阅 "SEND_DATA_REQ" 消息,接收其他模块的发送请求。

  2. 队列管理:维护发送队列 send_queue,存储待发送的数据项(包含服务 UUID、特征值 UUID、数据、回调信息)。

  3. 任务调度:通过任务处理函数 ble_client_sender_task_func 处理各类 BLE 事件。

  4. 数据发送:按顺序发送队列中的数据,并通过回调通知发送结果。

6.4.2 核心实现

  1. 其他模块通过 sys.publish("SEND_DATA_REQ", ...) 发布 发送请求。

  2. send_data_req_proc_func 函数将请求数据加入发送队列,并通知任务。

  3. 任务处理函数根据 BLE 事件状态(连接成功、断开连接等)处理队列数据。

  4. send_item_func 函数负责实际发送数据。

  5. send_item_cbfunc 函数处理发送结果,调用用户回调。

6.4.3 事件处理

  1. CONNECT_OK :BLE 连接成功,开始发送队列数据。

  2. SEND_REQ :有新数据需要发送,继续处理队列。

  3. DISCONNECTED :连接断开,清空队列并通知所有发送请求失败。

6.5 ble_uart_app

6.5.1 主要功能

  1. UART 初始化:打开 UART1 接口,配置波特率 115200、数据位 8、停止位 1、无奇偶校验。

  2. 数据接收:订阅 "RECV_BLE_NOTIFY_DATA" 消息,接收来自 BLE 外围设备的通知数据。

  3. 数据转发:将接收到的 BLE 数据(包含服务 UUID、特征值 UUID 和实际数据)格式化后通过 UART1 发送到 PC 端。

6.6 ble_timer_app

6.6.1 主要功能

  1. 创建两个独立的 5 秒循环定时器

  2. 一个用于定时 发送 数据到外围设备特定特征值 UUID。

  3. 一个用于定时 读取 外围设备特定特征值 UUID 的数据。

6.6.2 核心实现

  1. 定义了目标服务 UUID( FA00 )和特征值 UUID(写: EA02 ,读: EA03 )。

  2. 实现数据发送结果回调函数 send_data_cbfunc ,用于处理发送成功/失败的通知。

  3. 实现两个定时器回调函数:

  4. send_data_req_timer_cbfunc :发布 SEND_DATA_REQ 消息到 ble_client_sender 模块。

  5. read_data_req_timer_cbfunc :发送 READ_REQ 请求到 ble_client_main 模块。

  6. 启动两个 5 秒循环定时器,分别绑定上述两个回调函数。

6.6.3 数据流转

  1. 发送流程:定时器触发 → 发布 SEND_DATA_REQ 消息 → ble_client_sender 处理 → 回调通知结果。

  2. 读取流程:定时器触发 → 发送 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、结果展示

八、总结

本篇文档介绍了 Air8000 的 BLE central 模式,通过两个 Air8000 核心板:一个作中心设备,一个作外围设备,演示了 BLE 中心设备三大核心操作:

1)订阅通知(Notify):自动获取外围设备推送的数据,

2)写入特征值(Write):用于发送控制指令,要求外围设备特征支持 WRITE 属性;

3)读取特征值(Read):主动获取外围设备状态,需外围设备开放 READ 权限。

三种操作均需中心设备和外围设备的服务/特征 UUID 严格匹配。