跳转至

02 BLE 外围设备模式(peripheral)

作者:王世豪

一、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 的 peripheral(外围设备) 功能。

1、Air8000 作为外围设备开启广播,被动等待中心设备发起连接;

2、连接成功后,定期向中心设备发送数据;

3、外围设备收到中心设备的写入数据后,通过 uart1 发送到 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 V2014 版本固件(理论上,2025 年 7 月 26 日之后发布的固件都可以)

3、脚本文件:

外围设备:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/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 脚本文件。

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

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
   |── check_wifi.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 端串口工具。

  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 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 作为中心设备,Air8000 作为外围设备。

1、烧录示例 demo 到 Air8000 核心板后,手机端打开 nrf connect 蓝牙调试软件,找到广播的设备名称为"LuatOS123"的设备并连接。

2、手机连接作为外围设备的 Air8000 后,界面如下所示:

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 作为中心设备,Air8000 作为外围设备。外围设备向中心设备发送 notify 数据,需要中心设备先开启 notify 订阅,下图是 nrf connec 开启订阅的方式,点击图标”↓↓↓“即可。

点击图标”↓↓↓“后,APP 后台自动监听从设备 notify 上来的数据,右滑界面,可以看到接收到的每条数据。

八、总结

本文介绍了 Air8000 的 BLE 外围设备模式,通过示例演示了如何向中心设备发送通知数据,以及如何接收中心设备发过来的数据。