跳转至

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下载。

点我,下载ANDROID版 nrf connect APP

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 文件说明

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

  2. ble_peripheral_main.lua:ble 外围设备主程序,进行 ble 初始化,设置广播内容,处理各类 ble 事件(连接、断开连接、写入请求等)。

  3. ble_peripheral_receiver.lua:BLE 外围设备接收数据处理。

  4. ble_peripheral_sender.lua:BLE 外围设备发送数据处理。

  5. ble_timer_app.lua:ble 外围设备定时器处理逻辑,启动两个循环定时器,一个是以 notify 方式主动向中心设备推送数据(需中心设备先开启 notify 订阅),另一个是使用 write 方式,更新特征值数据,中心设备需要主动读取特征值获取最新数据。

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

六、核心模块详解

6.1 主程序 (main.lua)

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

6.1.1 初始化流程

1、项目和版本定义

定义 PROJECTVERSION 变量。

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 事件:

  1. 连接成功(EVENT_CONN)

  2. 断开连接(EVENT_DISCONN)

  3. 写入请求(EVENT_WRITE)

注意:EVENT_WRITE 事件,是中心设备开启 notify 通知功能,或者向外围设备的特征里写入数据时,外围设备触发的回调事件。

6.2.3 业务功能

  1. 被动接收中心设备写入的数据:通过 ble_server_receiver.proc() 处理

  2. 建立连接后,向 ble_server_sender 模块发送"CONNECT_OK"的消息,通过 ble_server_sender 模块向中心设备发送数据。

6.2.4 异常处理

  1. 初始化失败 :进入异常处理流程。

  2. 连接断开 :清理资源并等待重连。

  3. 超时处理 :5 秒后重新启动广播。

6.3 ble_server_receiver

6.3.1 主要功能

  1. 数据处理 :处理接收到的 BLE 写入请求数据。

  2. 数据分发 :将收到的数据发给其他模块处理,比如本 demo 便演示了通过 uart 发给 pc 端处理。

ble_server_main 模块接收到 EVENT_WRITE 事件时,会调用此模块的 proc 函数。将数据发布到对应的消息主题,其他订阅了这些消息主题的模块可以接收并处理数据

6.3.2 核心实现

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

  2. 通过 sys.publish("RECV_BLE_WRITE_DATA", ...) 发给其他模块处理。

6.4 ble_server_sender

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

6.4.1 主要功能

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

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

  3. 任务调度:通过任务处理函数 ble_server_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_WRITE_DATA" 消息,接收来自 BLE 中心设备的写入数据。

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

6.6 ble_timer_app

6.6.1 主要功能

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

一个用于定时 以 notify 方式向中心设备推送数据(需中心设备先开启 notify 订阅)。

一个用于定时 更新 特征值数据,中心设备需要主动读取特征值获取最新数据。

6.6.2 核心实现

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

send_notify_data_timer_cbfunc :发布 SEND_DATA_REQ 消息到 ble_server_sender 模块。

send_write_data_timer_cbfunc :发送 SEND_DATA_REQ 消息到 ble_server_sender 模块。

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

七、结果展示

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 外围设备模式,通过示例演示了如何向中心设备发送通知数据,以及如何接收中心设备发过来的数据。