构建低功耗BLE设备:LuatOS开发全解析
在电池供电设备中,延长续航时间是设计核心目标之一,而BLE与LuatOS的结合为此提供了理想方案。LuatOS不仅支持深度睡眠模式下的蓝牙唤醒机制,还能通过脚本逻辑精细控制广播间隔与连接周期,实现功耗与响应速度的平衡。本文将深入讲解LuatOS中BLE的电源管理策略、内存优化技巧与中断处理机制,并提供典型省电配置方案,助力开发者打造真正“低功耗、高可靠”的BLE终端产品。
一、BLE总体介绍
1.1 什么是BLE(Bluetooth Low Energe)?
蓝牙低功耗,通常缩写为 BLE,是蓝牙技术联盟设计的一种个人区域网络技术,旨在提供显著降低的功耗、成本和复杂性,同时保持可比的通信范围。
与传统经典蓝牙相比,BLE并非专注于传输高数据量的内容(如音频流、大文件),而是为间歇性、小数据量的传输应用而优化。这使得它非常适合那些需要长时间运行在纽扣电池或小型电池上的设备。
应用场景举例:
经典蓝牙:
1、蓝牙耳机/音箱
场景:你用无线耳机听音乐、看视频、打电话。
为什么是经典蓝牙:因为音频流需要持续、高速、低延迟的传输,才能保证声音连贯不卡顿。
2、车载蓝牙系统
场景:你一上车,手机就自动连接到汽车,可以播放手机里的音乐,或者进行免提通话。
为什么是经典蓝牙:和耳机一样,传输的是实时的音频流,对稳定性和速度要求高。
3、蓝牙文件传输
场景:两个人之间不用网络,直接通过手机“蓝牙”功能分享照片、视频或文档。
为什么是经典蓝牙:传输的文件可能比较大,需要较高的传输速率。
4、无线键盘、鼠标和手柄
场景:连接电脑的无线键盘鼠标,或者连接手机/游戏机的蓝牙游戏手柄。
为什么是经典蓝牙:虽然数据量不大,但它们需要保持持续连接和极低的延迟,以确保你每次按键、移动鼠标或操作手柄的指令都能被即时响应。
低功耗蓝牙BLE:
1、共享单车开锁
场景:你用手机App扫码后,单车锁“滴”一声就打开了。
为什么是BLE:开锁过程只需要手机向车锁发送一个极小的加密指令包,传输瞬间完成,车锁的电池需要支撑数月。
2、智能手环/手表
场景:你的小米手环或Apple Watch记录了你一天的步数、心率和睡眠数据。
为什么是BLE:设备本身通过小型电池供电,需要续航数周。它持续采集你的健康数据(小数据包),只在当你打开手机App同步时,才通过BLE将积攒的数据批量发送到手机上。
3、蓝牙防丢器
场景:你把一个Tile或AirTag挂在钥匙上,当钥匙找不到时,用手机让防丢器发出声音。
为什么是BLE:防丢器绝大部分时间处于待机状态。当你“寻找”它时,手机通过BLE发送一个指令唤醒它,它再回应一个信号。这种间歇性工作模式让它的纽扣电池能用一年多。
4、物联网传感器
场景:家里的温湿度计、门窗传感器、智能灯泡。
为什么是BLE:温度传感器每隔几分钟才上报一次数据(几个字节);门窗传感器只有在开/关状态变化时才发送信号。它们都由电池供电,需要BLE的低功耗特性来保证较长的续航。
1.2 BLE的发展历史
BLE的发展与蓝牙技术的整体演进紧密相连。其历史可以看作是为了满足物联网需求而专门开辟和不断优化的一条技术路径。
1、1998-2010:前BLE时代(经典蓝牙主导)
说明:经典蓝牙(Bluetooth Classic)专注于连续数据流应用,如音频和文件传输。功耗较高,不适合物联网传感器。
2、2010:革命性的起点 - 蓝牙4.0
说明:蓝牙4.0核心规范发布,首次引入了“蓝牙低功耗”技术。这是一个里程碑,它创建了两种并行的技术:经典蓝牙和蓝牙低功耗。蓝牙4.0芯片分为三种类型:
单模:仅支持BLE。
双模:同时支持经典蓝牙和BLE。
经典:仅支持经典蓝牙。
影响:催生了第一批真正的低功耗物联网设备,如心率带、智能标签等。
3、2013:同互联网融合 - 蓝牙4.1
说明:蓝牙与互联网无缝衔接,推动智能家居发展。
支持IPv6直接联网
设备可同时作为主/从机
单包容量23字节(广播包仍31字节)
4、2014:速度与连接的提升 - 蓝牙4.2
说明:此版本带来了关键改进:
数据传输速度提升:将发送数据包长度扩展,单包容量255字节,提升数据传输速度。
隐私与安全增强:提供了更强大的加密和隐私保护。
5、2016:物联网的基石 - 蓝牙5.0

说明:这是针对物联网的一次巨大飞跃,主要特性包括:
BLE速度翻倍至2 Mbps,是BLE 4.2的两倍
理论距离240米(室外)
Mesh网络支持
6、2019-2020:专注定向与高精度 - 蓝牙5.1 & 5.2
说明:
蓝牙5.1:引入了寻向功能,通过测量信号相位,可以实现厘米级精度的室内定位,解决了“在哪里”的问题。
蓝牙5.2:引入了LE Audio的核心——低功耗同步信道,为下一代蓝牙音频奠定了基础,同时提升了多设备连接效率和功耗控制。
7、2021-2023:音频革命与未来 - 蓝牙5.3 & 5.4
说明:
持续优化:蓝牙5.3/5.4进一步优化了连接稳定性、延迟和安全性。
LE Audio:基于蓝牙5.2及更高版本,它使用全新的LC3编码器,在更低功耗下提供更高质量的音频,并支持广播音频(如助听器、多人共享音频)等创新应用。
Mesh网络:虽然规范更早推出,但正随着BLE的普及而广泛应用,允许成千上万个设备组成一个庞大的网络,用于智能楼宇、工业控制等场景。
8、2024: 蓝牙6.0
说明:
引入Bluetooth Channel Sounding,通过RTT(round-trip time) 和 PBR(phase-based ranging)技术(类似苹果的UWB),能够准确测量蓝牙设备间的物理距离。
二、BLE协议栈介绍
在开始讲LuatOS的BLE之前,先大概了解下BLE的协议栈。
2.1 BLE低功耗协议栈介绍

BLE协议栈主要用来对你的应用数据进行层层封包,以生成一个满足BLE协议的空中数据包。也就是说,把应用数据包裹在一系列的帧头(header)和帧尾(tail)中。
蓝牙协议规定了两个层次的协议,分别是:
(1)蓝牙核心协议(Bluetooth Core)
这是蓝牙技术的基础,规定了从无线电波收发到数据链路管理的所有底层技术细节。它确保了不同厂商设备之间的基本互联互通。核心协议层通常又分为控制器(Controller) 和主机(Host) 两个子部分。
(2)蓝牙应用层协议(Bluetooth Application)
建立在核心协议之上,定义了如何利用核心协议来实现具体的功能和服务。例如,心率监测、血压计、键盘鼠标等具体应用场景的规范。
2.2 BLE低功耗蓝牙核心协议层详解(Bluetooth Core)
2.2.1 物理层(PHY)
PHY层用来指定BLE所用的无线频段,调制解调方式和方法等。
蓝牙工作在2.4GHz的频段,具体的频段范围是2400MHz到2483.5MHz,频段宽度为83.5MHz。BLE将这83.5MHz的宽度分成了0到39共40个通道,每一个通道宽度为2MHz。
下面我们看下蓝牙的波形图:

其中广播通道为37/38/39,对应的中心频率分别为2402MHz,2426MHz,2480MHz。BLE在广播的时候会轮流使用这3个广播通道进行广播。
数据通道为0-36,专门用于在设备连接建立之后,传输用户数据和命令。
从图中可以看到BLE的3个广播通道并不是连续的,这三个信道和蓝牙广播关系密切,用于设备被发现。
为什么不是连续的?
这就需要看下wifi的信道划分了,wifi同样也是工作在2.4GHz频段下,如果BLE处理不当,自然会被wifi影响。
下面我们来详细分析Wi-Fi如何影响BLE,以及BLE的应对策略。

Wi-Fi 对 BLE 的影响机制
根本原因在于频段重叠:
-
BLE: 工作在 2.400 - 2.4835 GHz,使用 40 个 2MHz 宽的信道。
-
Wi-Fi(2.4GHz): 同样工作在 2.412 - 2.472 GHz(通常),使用 20MHz 或 40MHz 宽的信道。
可以想象一下,Wi-Fi的一个信道就像一条宽阔的八车道高速公路,而BLE的一个信道就像是其中的一条自行车道。当Wi-Fi这条高速公路车流繁忙时,自然会影响到在旁边自行车道上行驶的BLE。
具体来说:
1、物理信道重叠:
-
Wi-Fi的1, 6, 11这三个最常用的非重叠信道,会覆盖一大片BLE的信道。
-
例如,Wi-Fi信道1(中心频率2.412 GHz)会干扰BLE的数据信道0到10。
-
Wi-Fi信道6(中心频率2.437 GHz)会干扰BLE中间部分的数据信道。
-
Wi-Fi信道11(中心频率2.462 GHz)会干扰BLE的数据信道22到36。
2、影响类型:
-
数据包丢失: BLE数据包在传输过程中被Wi-Fi信号淹没,导致接收端无法正确解码。
-
连接中断: 如果数据包持续丢失,可能导致连接超时而断开。
-
广播受阻: 设备更难被发现或连接,因为广播信道(特别是38)可能被干扰。
-
功耗增加: 为了补偿丢失的数据包,设备需要更频繁地重传数据,从而增加了功耗。
BLE 的应对策略(为什么影响通常不大)
1、自适应跳频【蓝牙跳频(Frequency Hopping)技术)】
蓝牙技术使用跳频扩频(FHSS)来避免干扰和多径衰减。跳频是指蓝牙设备在通信过程中,按照一定的序列在不同的信道之间快速切换。这样,即使某个信道受到干扰,也可以在其他信道上继续通信,从而保证整体的通信质量。
这是BLE对抗Wi-Fi干扰的方式。在连接状态下,BLE主从设备会在37个数据信道上快速切换。
它们会持续监测每个信道的通信质量。如果一个信道(比如被Wi-Fi信道6占据的区域)频繁出错,系统会将其标记为“坏信道”,并在未来的跳频序列中自动避开。
这样,即使有40%的信道被Wi-Fi干扰,通信依然可以通过剩下60%的干净信道可靠进行。
2、广播信道的巧妙设计
BLE的3个广播信道(37, 38, 39)被特意安排在2.4GHz频段的两端和正中间。
这个设计就是为了最大化地避开Wi-Fi最常用的1、6、11信道。 - 信道37(2402MHz): 在Wi-Fi信道1的左侧,基本安全。 - 信道39(2480MHz): 在Wi-Fi信道11的右侧,基本安全。 - 信道38(2426MHz): 位于Wi-Fi信道1和6之间,是最容易受到干扰的广播信道。
广播时,设备会在三个信道上都发送数据,只要有一个被手机接收到,连接就能建立。这大大提高了在干扰环境下的发现概率。
2.2.2 链路层(LL)
LL 位于物理层(PHY)之上,主机控制器接口(HCI)之下,是 BLE 协议栈中负责报文组装/拆解、时序控制、信道管理、状态机切换、安全加密等的核心模块。
链路层定义了两个设备如何利用无线电传输信息。它包含了报文、广播、数据信道的详细定义,也规定了发现其他设备的流程、广播的数据、连接的建立、连接的管理以及连接中的数据传输。
LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP或者ATT。
LL层收到的数据,主要交给 ATT 进行解析,以服务于 GATT 定义的应用逻辑。而 GAP 主要处理LL层上报的连接和广播状态事件,而非解析具体的数据内容。
主要功能:
-
广播与扫描:支撑无连接的广播通信。
-
建立与维护连接:完成从扫描→发起→连接确认的流程,并维护连接事件。
-
数据交换:基于信道跳频机制可靠传输 ACL 数据包。
-
安全管理:执行加密、鉴权与隐私地址解析。
-
控制流程:实现连接参数更新、信道映射更新、数据长度扩展等 LL Control PDUs。
LL层主要有5种状态:
-
- 待机状态(Standby State)
-
- 广播状态(Advertising State)
-
- 扫描状态(Scanning State)
-
- 发起状态(Initiating State)
-
- 连接状态(Connection State)

下面我们详细解释每个状态:
1、待机状态(Standby State)
这是链路层的默认状态,设备既不发送也不接收数据。
功耗最低,设备可以在此状态下初始化或等待其他操作。
2、广播状态(Advertising State)
设备通过发送广播报文来宣告自己的存在。
广播报文可以包含设备地址、名称、服务等信息。
设备可以配置为不同的广播类型(如可连接广播、非可连接广播、可扫描广播等)。
3、扫描状态(Scanning State)
设备监听广播报文,分为主动扫描和被动扫描。
被动扫描:仅接收广播报文,不发送扫描请求。
主动扫描:在收到可扫描的广播报文后,发送扫描请求以获取更多信息(扫描响应)。
4、发起状态(Initiating State)
设备监听特定设备的广播报文,并在收到后发起连接请求。
只有设备配置为发起模式时才会进入此状态。
5、连接状态(Connection State)
当发起设备发送连接请求并被广播设备接受后,双方进入连接状态。
在连接状态下,设备分为主设备和从设备。
中心设备(Central):发起连接的设备。
外围设备(Peripheral):接受连接的设备。
在连接状态下,链路层会维护一个连接事件(Connection Events),在每个连接事件中,主设备和从设备可以进行数据包的交换。连接事件按照连接间隔(Connection Interval)周期性地发生。
2.2.3 主机控制接口层(HCI)
HCI 是 Host-Controller Interface 的缩写,即 “主机-控制器接口”。
它本质上是一套软件层面的规范和协议,定义了蓝牙协议栈中两个主要部分——主机(Host) 和控制器(Controller)——之间应该如何通信。
Host 和 Controller 是什么?
要理解HCI,首先必须明白蓝牙协议栈是如何分层的:
Controller:负责处理所有底层、实时性要求高的无线射频任务。 - 包含协议层:物理层、链路层。 - 职责:管理无线电信号、调制解调、跳频、数据包时序、广播、扫描等。它直接与硬件打交道。
Host:负责处理所有高层、应用逻辑相关的任务。 - 包含协议层:L2CAP、ATT、GATT、SM以及最终的应用程序。 - 职责:管理连接、定义服务与特征、处理加密安全、为应用程序提供API
2.2.4 逻辑链路控制及自适应协议层(L2CAP)
L2CAP对LL进行了一次简单封装。LL层只关心传输的数据本身,L2CAP就要区分加密通道还是普通通道,同时还要对连接间隔进行管理。
L2CAP是蓝牙协议栈的“交通调度中心”和“数据包装工”。 它位于基础射频协议之上,但低于应用层协议(如ATT/GATT),充当一个承上启下的多路复用和数据适配层。
2.2.5 属性协议层(ATT)
ATT全称是Attribute protocol(数据交互协议),这一层的关键词是Attribute(属性)。一个属性其实就是一条数据,属性是BLE数据提供单元,也是蓝牙空中传播数据的最上层。
ATT层定义了各种属性,属性的操作方法。通过ATT层可以读写对端设备的属性,但是属性之间有什么联系、各个属性怎么组合起来提供服务,由上层GATT负责。
属性,是ATT层的 关键字。
2.2.6 通用访问配置文件层(GAP)
Generic Access Profile(通用访问配置规范),主要用来进行广播、扫描和发起连接等。
GAP层将设备分为四种角色,分别是外围设备,中心设备,广播设备和观察设备。
这些设备围绕着广播和连接的差异性而区分,外围设备和广播设备对外发出广播数据,中心设备和观察设备扫描外部广播数据,广播设备和观察设备通常不建立连接,而外围设备和中心设备可以建立连接。
围绕着广播和连接,GAP层定义了许多不同的"模式(mode)",比如广播模式和连接模式,在不同模式下的操作称为“规程(procedure)”。
例如:当一个设备正在进行广播时,称其为"广播模式"。广播往往会持续较长时间,也许是该设备唯一用途。而当一个设备正在寻找广播者时,称其为"观察规程"。观察往往持续一段较短时间,用以构建用户界面或者寻找需要的指定信息。
2.2.7 通用属性配置文件层(GATT)
GATT(Generic Attribute Profile, 通用属性规范),自己本身不提供数据,而是将ATT层提供的属性组合起来构成的服务。GATT是建立连接后通信规范, 而蓝牙是通过GAP建立通信的。
在BLE里,通过ATT层可以读写对端设备的属性,但是属性之间有什么联系、各个属性怎么组合起来提供服务,由上层GATT负责。
服务,是GATT层的关键字。
-
注意:
-
GATT 连接,必须先经过GAP协议。
-
一旦两个设备建立起了连接,GATT 就开始起作用了。
-
中心设备和外设需要双向通信的话,唯一的方式就是建立GATT 连接。
-
GATT 定义两个BLE设备通过服务(Service)和特征(Characteristic)进行通信。
1、GATT(通用属性配置文件)
定义 BLE 设备如何组织和传输数据,以 “服务(Service)” 和 “特征(Characteristic)” 为单位。
示例:心率监测设备的 GATT 服务包含 “心率特征”,手机通过读取该特征获取心率数据。
2、服务和特征
服务是特征的容器,通过逻辑分组简化复杂功能的管理;
特征是数据交互的最小单元,通过属性定义实现灵活的读写与推送机制;
两者结合构成 GATT 协议的核心框架,支撑蓝牙设备间的标准化数据交互(如智能穿戴、医疗设备、物联网传感器)。
3、特征的关键属性(Properties)
特征通过 “属性” 定义数据的操作方式,常见属性包括:
1)可读(Read):允许客户端读取特征值(如读取电池电量)。
2)可写(Write):允许客户端写入特征值(如设置设备参数)。
3)通知(Notification):服务端主动发送特征值更新(如心率变化时推送给手机)。
4、UUID
UUID 是蓝牙 GATT 协议的 “数字身份证”,通过标准化的唯一标识机制,实现了跨厂商设备的功能互认(标准 UUID)与厂商个性化功能的扩展(自定义 UUID)
三、LuatOS BLE 的四种工作模式解析
在前面的章节中,我们介绍了 BLE 的背景以及基础理论知识。若要深入了解其协议细节,读者可参考其他专业的资料。
从本部分开始,我们将聚焦于 LuatOS 的实际开发,重点讲解其支持的 四种核心 BLE 工作模式,并通过实例展示如何应用。
3.1 模式解释
外围设备模式(peripheral):设备会被扫描到, 并且可以被连接;
中心设备模式(central):设备会扫描其他设备, 并且可以连接其他设备;
广播者模式(ibeacon):设备会周期性的广播beacon信息, 可以被扫描到, 但一般不会被连接;
观察者模式(scan):设备会扫描其他设备, 但不会连接其他设备。
3.2 四种模式的基本流程
3.2.1 外围设备模式(peripheral)的基本流程(概要描述)
1、初始化蓝牙框架
bluetooth_device = bluetooth.init()
2、创建BLE对象
local ble_device = bluetooth_device:ble(ble_callback)
3、创建GATT描述
local att_db = {xxx}
4、创建广播信息
ble_device:adv_create(adv_data)
5、开始广播
ble_device:adv_start()
6、等待连接
7、在回调函数中处理连接事件, 如接收数据, 发送数据等
3.2.2 中心设备模式(central)的基本流程(概要描述)
1、初始化蓝牙框架
bluetooth_device = bluetooth.init()
2、创建BLE对象
local ble_device = bluetooth_device:ble(ble_callback)
3、扫描目标BLE设备
ble_device:scan_start()
4、建立与目标设备的连接
ble_device:connect(mac, add_type)
5、处理各类BLE事件(连接、断开连接、扫描报告、GATT操作完成等)
3.2.3 广播者模式(ibeacon)的基本流程(概要描述)
1、初始化蓝牙底层框架
bluetooth_device = bluetooth.init()
2、创建BLE对象
local ble_device = bluetooth_device:ble(ble_callback)
3、配置ibeacon广播数据包
包含厂商特定数据格式,ibeacon类型标识符
设置UUID、Major、Minor等关键参数
4、启动BLE广播功能
ble_device:adv_start()
3.2.4 观察者模式(scan)的基本流程(概要描述)
1、初始化蓝牙框架
bluetooth_device = bluetooth.init()
2、创建BLE对象
local ble_device = bluetooth_device:ble(ble_callback)
3、开始扫描
ble_device:scan_start()
4、在回调函数中处理扫描事件, 如接收设备信息等
5、按需停止扫描
ble_device:scan_stop()
3.3 应用场景
3.3.1 外围设备+中心设备(连接模式)
设计框图:

3.3.2 广播者+观察者(无连接模式)
设计框图:

四、LuatOS上的BLE核心库
4.1 常量详解
4.1.1 地址模式常量
ble.PUBLIC

4.1.2 特征属性常量
ble.READ

ble.WRITE

ble.NOTIFY

ble.IND

ble.WRITE_CMD

4.1.3 事件类型常量
ble.EVENT_CONN

ble.EVENT_DISCONN

ble.EVENT_WRITE

ble.EVENT_READ_VALUE

ble.EVENT_SCAN_REPORT

ble.EVENT_GATT_ITEM

ble.EVENT_GATT_DONE

ble.EVENT_SCAN_STOP

4.1.4 广播相关常量
ble.COMPLETE_LOCAL_NAME

ble.CHNLS_ALL

ble.CHNL_37

ble.CHNL_38

ble.CHNL_39

ble.FLAGS

ble.FLAGS 说明
在BLE中,标志(flags)通常出现在广播数据中,这些标志用于指示设备的能力和可发现性等。
根据蓝牙核心规范(Bluetooth Core Specification),广播数据中的Flags字段是一个8位的位图(bitmask),每个位代表特定的含义,以下是各个位的定义(从LSB到MSB):
Bit 0: LE Limited Discoverable Mode(有限可发现模式)
Bit 1: LE General Discoverable Mode(通用可发现模式,设备持续可被发现)
Bit 2: BR/EDR Not Supported(不支持经典蓝牙)
Bit 3: Simultaneous LE and BR/EDR to Same Device Capable(同一设备同时支持BLE和经典蓝牙)
Bit 4: Simultaneous LE and BR/EDR to Different Devices Capable(支持同时连接不同设备的BLE和经典蓝牙)
Bit 5-7: 保留(Reserved)
注意:Bit 0和Bit 1不能同时被设置。如果同时设置,则视为无效。
Bit1和Bit2被设置时,Flags字段的值为0x06(二进制0000 0110),
Bit2被设置时,Flags字段的值为0x04(二进制0000 0100)。
ble.SERVICE_DATA

ble.MANUFACTURER_SPECIFIC_DATA

4.2 函数详解
bluetooth.init()
功能
初始化蓝牙框架
注意事项
必须在使用蓝牙功能之前调用;
仅需要调用一次,若创建失败, 会返回nil, 请检查内存是否足够。
参数
无
返回值
local bluetooth_device = bluetooth.init()
bluetooth_device

示例

bluetooth_device:ble(ble_callback)
功能
创建一个BLE对象, 用于操作BLE设备
注意事项
必须在bluetooth.init()初始化成功后调用;
对象生命周期管理 :BLE对象需要在整个操作周期内保持有效,从初始化到最终释放;
全局/模块级变量推荐 :为了确保对象在需要时始终可用,通常建议将BLE对象定义在合适的作用域中:
-
模块级变量:适用于单个模块内部使用
-
全局变量:适用于跨模块访问
-
作为参数传递
参数
ble_callback

返回值
local ble_device = bluetooth_device:ble(ble_callback)
ble_device

示例

ble_device:scan_create(addr_mode,scan_interval,scan_window)
功能
创建一个BLE扫描
注意事项
无
参数
addr_mode

scan_interval

scan_window

返回值
local result = ble_device:scan_create(addr_mode,scan_interval,scan_window)
result

示例

ble_device:scan_start()
功能
开始BLE扫描
注意事项
扫描会一直进行, 直到调用ble.scan_stop()停止扫描;
扫描到结果会触发ble.EVENT_SCAN_REPORT事件,执行通过bluetooth_device:ble(ble_callback)创建BLE对象时注册的回调函数;
扫描到同一个设备不会去重, 扫描到数据就会执行回调。
参数
无
返回值
local result = ble_device:scan_start()
result

示例

ble_device:scan_stop()
功能
停止BLE扫描
注意事项
扫描会一直进行, 直到调用ble.scan_stop()停止扫描。
参数
无
返回值
local result = ble_device:scan_stop()
result

示例

ble_device:connect(mac, addr_type)
功能
发起BLE连接请求
注意事项
无
参数
mac

addr_type

返回值
local result = ble_device:connect(mac, addr_type)
result

示例

ble_device:disconnect()
功能
发起BLE断开连接请求
注意事项
无
参数
无
返回值
local result = ble_device:disconnect()
result

示例

ble_device:gatt_create(opts)
功能
创建一个BLE GATT服务
注意事项
确保UUID格式正确,且特征属性使用正确的权限常量;
特征属性必须是 ble.NOTIFY | ble.READ | ble.WRITE | ble.IND 的一种或多种组合;
参数
opts

返回值
local result = ble_device:gatt_create(opts)
result

示例

ble_device:adv_create(opts)
功能
创建一个BLE广播
注意事项
无
参数
opts

返回值
local result = ble:adv_create(opts)
result

示例

ble_device:adv_start()
功能
开始广播
注意事项
对于外围设备模式, 如果被断开了连接, 则需要重新开始广播, 才能被重新搜索到
参数
无
返回值
local result = ble_device:adv_start()
result

示例

ble_device:adv_stop()
功能
主动停止广播
注意事项
无
参数
无
返回值
local result = ble_device:adv_stop()
result

示例

ble_device:write_notify(opts,value)
功能
写入带通知的特征值
注意事项
外围设备使用,主动向中心设备发送通知数据
参数
opts

value

返回值
local result = ble_device:write_notify(opts,value)
result

示例

ble_device:write_indicate(opts,value)
功能
写入带指示的特征值
注意事项
外围设备使用,主动向中心设备发送指示数据
参数
opts

value

返回值
local result = ble:write_indicate(opts,value)
result

示例

ble_device:write_value(opts,value)
功能
写入特征值
注意事项
无
参数
opts

value

返回值
local result = ble_device:write_value(opts,value)
result

示例

ble_device:read_value(opts)
功能
读取特征值
注意事项
无
参数
opts

返回值
local result = ble_device:read_value(opts)
result

示例

ble_device:notify_enable(opts,enable)
功能
开关通知监听
注意事项
中心设备使用,配置是否接收外围设备发送的通知消息
参数
opts

enable

返回值
local result = ble_devie:notify_enable(opts,enable)
result

示例

ble_device:indicate_enable(opts,enable)
功能
开关指示监听
注意事项
中心设备使用,配置是否接收外围设备发送的指示消息
参数
opts

enable

返回值
local result = ble_device:indicate_enable(opts,enable)
result

示例

ble_device:adv_decode(data)
功能
解码广播数据
注意事项
广播数据通常来自于ble.EVENT_SCAN_REPORT 事件的 ble_param.data
参数
data

返回值
local adv_data = ble_device:adv_decode(data)
adv_data

示例

ble.mac()
功能
获取蓝牙MAC
注意事项
无
参数
无
返回值
local mac = ble.mac
mac

示例

五、LuatOS上的BLE 应用开发流程
本部分将深入一项具体实践:在 「外围设备模式」下进行 BLE 应用开发。
5.1 总体设计框图

5.2 分析项目代码
这个ble peripheral demo中的readme文件,以及代码中的注释都比较详细,接下来我用vscode直接打开这份demo项目代码,和大家一起分析下项目代码;
程序结构:

文件说明:
-
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 端串口工具。
-
check_wifi.lua:Air8000 的蓝牙功能依赖 WiFi 协处理器,需确保 WiFi 固件为最新版本。本脚本文件检查当前 Air8000 模组的 WiFi 固件是否为最新版本,若不是则自动启动升级(需插入可联网的 SIM 卡)
5.3 Air8000开发板上运行演示这个项目
准备硬件环境:
1、Air8000开发板一块+2.4gwifi天线一根:
- 天线装到开发板上
2、TYPE-C USB数据线一根 + USB转串口数据线一根,Air8000开发板和数据线的硬件接线方式为:
-
Air8000开发板通过TYPE-C USB口供电;(外部供电/USB供电 拨动开关 拨到 USB供电一端)
-
TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
六、BLE外围设备模式常见问题分析
6.1 烧录示例demo后,无法搜到蓝牙
Air8000
1、首先检查demo,固件是否是最新的,若不是则需更新的最新的版本测试,若已经是最新的,看第2步
2、luatools日志全局搜 AIRLINK_READY,查看WIFI固件版本打印(因为Air8000的蓝牙功能依赖WiFi协处理器)

version后面的数字代表的是wifi固件的版本,目前最新发布的是14。
如果不是最新的14,此时需要升级wifi固件,目前有两种wifi的升级方式,可自由选择:
(1)4g远程升级wifi
在示例demo中的main.lua中,会有下面这句话,打开require "check_wifi"即可通过4g升级wifi,不过注意要插上能够正常上网的sim卡。

七、LuatOS 上的中心设备模式应用开发流程
7.1 前置知识了解
7.1.1 UUID
7.1.1.1 UUID 是什么?
UUID 是蓝牙 GATT 协议的 “数字身份证”,通过标准化的唯一标识机制,实现了跨厂商设备的功能互认(标准 UUID)与厂商个性化功能的扩展(自定义 UUID)
蓝牙协议通过 UUID 实现设备间的标准化通信,使用蓝牙对外提供服务的设备,需要有对应的服务功能,服务是蓝牙设备中功能划分的单元,每个服务都对应着一种特定的功能或数据传输需求。
例如,当一个蓝牙设备(如智能手环)向外界广播服务时,会携带对应的 UUID,其他设备(如手机)通过识别这些 UUID,就能知道该设备提供哪些功能(如心率监测、数据传输等),并建立针对性的连接。
一个蓝牙设备可以包含多个服务(Service),每个服务通过一个 UUID(服务 UUID) 进行标识。
每个服务下包含多个特征(Characteristic),每个特征都拥有一个独立的 UUID(特征 UUID)作为其唯一标识。
特征是最小的数据单元,我们通过读写特征来与设备交互。
1、服务(Service)
是什么:服务是蓝牙设备功能的逻辑分组,类似于一个"功能模块"。
例如:心率监测服务、电池电量服务等。
作用:定义设备能做什么(如测量心率、监控电量)。通过 UUID 唯一标识。
示例:

2、特征(Characteristic)
是什么:特征是服务的子元素,是服务中的具体数据点,用于实际的数据读写操作。
例如:心率值、电池电量百分比。
作用:存储具体数据(如 71 bpm)。通过 UUID 和 属性(Properties) 定义操作权限(读/写/通知等)。
示例:

3、描述符(Descriptor)
是什么:描述符是特征的子元素,是特征的附加信息,用于细化特征的行为或配置。
例如:启用数据通知、设置数据格式。
作用:配置特征的行为(如开启实时通知)。补充描述特征(如单位、数据范围)。
最常见描述符:。
Client Characteristic Configuration Descriptor (CCCD)
用于启用/禁用特征的 NOTIFY 或 INDICATE 功能。
三者的层级关系:

实际示例(手环):

7.1.1.2 UUID 的格式:
蓝牙 UUID 的标准格式为 128 位,通常表示为 32 个十六进制字符,以 8-4-4-4-12 的格式分组,共 36 个字符(包括 4 个连字符):
-
格式:8-4-4-4-12
-
示例:0000180D-0000-1000-8000-00805F9B34FB
标准 UUID:
由蓝牙技术联盟(Bluetooth SIG)定义,用于常见服务。
标准的 UUID 为:0000xxxx-0000-1000-8000-00805F9B34FB。
为了节省带宽,标准 UUID 通常使用 16 位或 32 位短格式,实际通信时自动扩展为 128 位。每一个蓝牙技术联盟定义的属性有一个唯一的 16 位 UUID,以代替上面的基本 UUID 的‘x’部分。
若 16 bit UUID 为 xxxx,那么 128 bit UUID 为 0000xxxx-0000-1000-8000-00805F9B34FB。
若 32 bit UUID 为 xxxxxxxx,那么 128 bit UUID 为 xxxxxxxx-0000-1000-8000-00805F9B34FB。
自定义 UUID:
用于私有服务或厂商特定功能,需开发者自行生成,通常使用 UUID 随机生成器生成 128 位 UUID,确保全球唯一性
7.1.1.3 UUID 的分类
蓝牙规定好的 uuid 如下:
-
0x180x 开头 → 只能当 Service UUID
-
0x2Axx 开头 → 只能当 Characteristic UUID
-
0x29xx 开头 → 只能当 Descriptor UUID
0x180x 开头 UUID(Service UUID)
0x180x 区间只能当 Service UUID。

0x2Axx 开头 UUID(Characteristic UUID)
0x2Axx (0x2A00 – 0x2AFF) 区间只能当 Characteristic UUID。

0x29xx 开头 UUID(Descriptor UUID)
0x29xx 开头只能当 Descriptor UUID,即描述符 UUID。
这里仅介绍一个使用最频繁的 UUID:0x2902
0x2902 - Client Characteristic Configuration(CCC,客户端特征配置描述符)
这是一个可写的描述符,允许客户端设备(如手机、电脑)配置如何从服务器设备(BLE 外设)接收数据更新。主要用于启用或禁用通知(Notifications) 和指示(Indications) 功能。
BLE 实时数据推送(如传感器数据、状态更新)都需要通过正确配置 0x2902 描述符来实现。
UUID 格式:
-
完整 UUID:00002902-0000-1000-8000-00805f9b34fb
-
缩写:0x2902
-
类型:Descriptor(描述符)
有效值:
0xFFxx 开头 UUID(Vendor Specific)
0xFF00 ~ 0xFFFF 区间为 SIG 的公共预留池(Vendor-Specific 区间) 任何厂商都可以临时借用。
这个区间 SIG 作为公共预留区间,一般用作示例测试参考,属于临时方案,想要作为产品,要么去 SIG 申请正式分配,要么直接用 128-bit 自建 UUID。
注意事项:
1、整个 16-bit 空间都由 Bluetooth SIG 的官方文档 《Assigned Numbers》统一管理
2、商用不要使用已存在的 UUID,可以用 128-bit 自定义 UUID,或者在 SIG 申请正式分配。
3、同一设备,不同特征 UUID 任何时候都不能一样。
4、自定义的 128-bit UUID,服务 UUID 可以和 特征 UUID 一样,SIG 规定的 16-bit 的服务和特征值的 UUID 不能一样。

7.1.2 Properties
特征的关键属性(Properties)
特征通过 “属性” 定义数据的操作方式,常见属性包括:

7.2 demo 项目总体设计框图
demo 项目的总体设计框图如下:

7.3 源码分析
7.3.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 卡)
7.3.2 ble_client_main.lua
本文件为 ble client 主应用功能模块,整个应用通过 sysplus.taskInitEx 启动主任务,实现了完整的 BLE 中心设备功能,包括设备发现、连接管理、数据收发和异常恢复机制。核心业务逻辑为:
7.3.2.1 初始化与配置
加载依赖模块( ble_client_receiver 用于数据接收处理, ble_client_sender 用于数据发送处理)。
定义配置参数(目标设备名称、服务 UUID、特征值 UUID、超时时间等)。
调用 ble_init(),初始化蓝牙功能。
7.3.2.2 设备扫描与连接
创建并启动 BLE 扫描(默认参数:公共地址模式、扫描间隔 100ms、扫描窗口 100ms)。
通过 is_target_device 函数过滤扫描到的设备(匹配设备名称)。
发现目标设备后停止扫描并发起连接。
连接超时处理和重连机制。
7.3.2.3 事件处理
通过 ble_event_cb 回调函数处理各类 BLE 事件:
连接成功(EVENT_CONN)
断开连接(EVENT_DISCONN)
扫描报告(EVENT_SCAN_REPORT)
GATT 操作完成(EVENT_GATT_DONE)
读取特征值完成(EVENT_READ_VALUE)
7.3.2.4 业务功能
GATT 服务发现完成后,自动启用目标特征值的通知监听。
接收并处理来自其他模块的读取请求( READ_REQ )。
通过消息队列与其他模块通信。
7.3.2.5 异常处理
扫描超时或连接失败时触发异常处理。
断开连接后自动清理消息队列并尝试重连。
异常情况下 5 秒后重新开始扫描连接。
7.3.3 ble_client_receiver.lua
7.3.3.1 主要功能
数据分类处理 :接收两类数据(外围设备通知数据和主动读取到的数据)。
数据分发 :根据数据类型(通过特征值 UUID 区分)发布到不同的消息队列,供其他模块处理。
7.3.3.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", ...) 发布。
7.3.3.3 数据流转
当 ble_client_main 模块接收到 EVENT_READ_VALUE 事件时,会调用此模块的 proc 函数。
本模块将数据分类后发布到对应的消息主题。
其他订阅了这些消息主题的模块可以接收并处理数据。
7.3.4 ble_client_sender.lua
其他模块只需发布 "SEND_DATA_REQ" 消息即可请求中心设备向外围设备发送数据。
7.3.4.1 主要功能
消息订阅:订阅 "SEND_DATA_REQ" 消息,接收其他模块的发送请求。
队列管理:维护发送队列 send_queue,存储待发送的数据项(包含服务 UUID、特征值 UUID、数据、回调信息)。
任务调度:通过任务处理函数 ble_client_sender_task_func 处理各类 BLE 事件。
数据发送:按顺序发送队列中的数据,并通过回调通知发送结果。
7.3.4.2 核心实现
其他模块通过 sys.publish("SEND_DATA_REQ", ...) 发布 发送请求。
send_data_req_proc_func 函数将请求数据加入发送队列,并通知任务。
任务处理函数根据 BLE 事件状态(连接成功、断开连接等)处理队列数据。
send_item_func 函数负责实际发送数据。
send_item_cbfunc 函数处理发送结果,调用用户回调。
7.3.4.3 事件处理
CONNECT_OK :BLE 连接成功,开始发送队列数据。
SEND_REQ :有新数据需要发送,继续处理队列。
DISCONNECTED :连接断开,清空队列并通知所有发送请求失败。
7.3.5 ble_uart_app.lua
UART 初始化:打开 UART1 接口,配置波特率 115200、数据位 8、停止位 1、无奇偶校验。
数据接收:订阅 "RECV_BLE_NOTIFY_DATA" 消息,接收来自 BLE 外围设备的通知数据。
数据转发:将接收到的 BLE 数据(包含服务 UUID、特征值 UUID 和实际数据)格式化后通过 UART1 发送到 PC 端。
7.3.6 ble_timer_app
7.3.6.1 主要功能
创建两个独立的 5 秒循环定时器
一个用于定时 发送 数据到外围设备特定特征值 UUID。
一个用于定时 读取 外围设备特定特征值 UUID 的数据。
7.3.6.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 秒循环定时器,分别绑定上述两个回调函数。
7.3.6.3 数据流转
发送流程:定时器触发 → 发布 SEND_DATA_REQ 消息 → ble_client_sender 处理 → 回调通知结果。
读取流程:定时器触发 → 发送 READ_REQ 请求 → ble_client_main 处理 → 结果通过事件返回。
7.4 日志分析
接下来用两个 Air8000 核心板,一个烧录外围设备的 demo,另一个烧录中心设备的 demo,来演示中心设备如何读,写操作。
1、中心设备订阅外围设备特征通知(Notify)

2、中心设备写入特征值(Write)

3、中心设备主动读取特征值数据(Read)

八、LuatOS 上的广播模式应用开发流程
8.1 前置知识了解
8.1.1 ibeacon 介绍
1、ibeacon 技术是 Apple 公司在 2013 年 9 月发布的一种基于 BLE 蓝牙的通信协议,主要用于短距离传送少量数据。
它通过周期性广播包含唯一标识符(UUID、Major、Minor)的数据包,使智能设备在接收信号后,结合信号强度(RSSI)估算距离,实现室内定位、场景触发等功能。
2、ibeacon 规定了一个 30 个字节的广播包。其中需要重点解析的是后 21 个字节(即从 UUID 开始),此前字节重在标识是否为 ibeacon 协议。
ibeacon 广播数据包的完整格式如下:

一个 30 字节的完整的 iBeacon 可做如下拆解:
AD Structure1(Advertising Data Structure)
长度字段(1 字节):此处一般为 0x02(即十进制 2),表示该 AD Structure 后续数据的总字节数
类型字段(1 字节):0x01(Flags,广播标志位)
数据(1 字节):0x06(Flags 的值,表示可被发现且支持 BLE 通用模式,Flags 见 7.2 章节)
AD Structure2
长度字段(1 字节):此处一般为 0x1A(即十进制 26)表示后续数据的总字节数
类型字段(1 字节):固定为 0xFF,表示厂商特定数据。
数据(此处为公司标识符)(2 字节):苹果的公司 ID 为 0x004C(小端存储为 0x4C 0x00)。
iBeacon 有效载荷(仍属于 AD Structure2)
iBeacon 类型标识符(1 字节):固定为 0x02,表示子类型为 iBeacon
iBeacon 数据长度(1 字节):固定为 0x15,表示 ibeacon 后续数据长度为 21 字节 后续数据长度为需要重点解析的 21 字节
Proximity UUID(16 字节):设备的唯一标识符(如 UUID)。
Major(2 字节):用于区分区域(如建筑楼层)。
Minor(2 字节):用于更细粒度的定位(如具体房间)。
Tx Power(1 字节):校准信号强度的参考值(RSSI at 1m)。
AD Structures 是什么?
在 BLE 协议中,设备通过广播包(Advertising Packet)向外发送数据。
一个广播包可能包含多个 AD Structure(Advertising Data Structure),每个 AD Structure 用于描述不同的信息(例如设备名称、服务 UUID、厂商数据等)。
每个 AD Structure 的格式固定为:
[长度(1字节)] + [类型(1字节)] + [数据(N字节)]
长度字段(1 字节):表示 类型 + 数据 的总字节数(即 类型1字节 + 数据N字节)。
类型字段(1 字节):定义数据的用途(例如 0xFF 表示厂商数据,0x09 表示设备名称)。
数据字段(N 字节):具体内容,长度由长度字段-1 决定(因为类型占 1 字节)。
AD Structure 的解析规则:
顺序无关:AD Structure 的顺序不固定。
长度限制:总长度不超过 31 字节(若为扩展广播,可更长,但 iBeacon 不支持)。
类型唯一性:同一类型可能重复出现(例如多个厂商数据块)。
在解析时,可以通过以下步骤遍历所有 AD Structure:
从广播包首字节开始。
读取长度字段(1 字节),确定当前 AD Structure 的总长度(包括类型和数据)。
读取类型字段(1 字节),判断数据类型。
根据类型,处理后续数据。
常见 AD Structure 类型对照表:
其中标志位,长度,类型我们不需要处理,我们只需要关注 ibeacon 的有效载荷部分,接下来详细介绍下这部分字段内容:
厂商标识符(2 字节):是蓝牙技术中用于唯一标识设备制造商或品牌方的 2 字节(16 位)编码,范围是 0x0000 ~ 0xFFFF(即 0~65535),它的核心作用是区分不同厂商的蓝牙设备,确保数据解析和兼容性。
ibeacon 类型标识符(1 字节):固定为 0x02, 表示子类型为 ibeacon。
ibeacon 数据长度(1 字节):固定为 0x15,表示 ibeacon 数据长度 21 字节。
Proximity UUID(16 字节):通用唯一标识符。
这是一个 128 位(16 字节)的唯一标识符,用于区分你所在的 iBeacon 网络。 例如,一个商店的所有 iBeacon 可以使用同一个 UUID,这样你的应用就可以知道用户进入了该商店区域。 通常,一个组织或一个应用使用同一个 UUID,然后通过 Major 和 Minor 来进一步细分区域和设备。
Major(2 字节):主标识,用于区分同一组织(UUID 相同)下的不同区域或组别。
Major 是一个 16 位的无符号整数,用于将一组相关的设备进行分组。 例如,一个连锁商店的每个分店可以使用相同的 Major 值,这样应用就知道用户进入了哪个分店。
Minor(2 字节):次标识,用于在同一个 Major 组内进行更细粒度的区分。
Minor 也是一个 16 位的无符号整数,用于标识特定的 iBeacon。 例如,在一个分店内,每个货架或区域可以有一个唯一的 Minor 值。这样,应用就可以知道用户接近哪个具体的货架。
Signal Power(1 字节):校准信号强度的参考值,单位 dBm。(该位为 8 位有符号数据,范围为-128 到 127,最高位是符号位)
这个字段是 8 位有符号整数,表示在距离 iBeacon 设备 1 米处测量到的信号强度(RSSI)。这个值用于校准,帮助估算与设备之间的实际距离。设备接收到信标的信号强度(RSSI)后,与这个校准值进行比较,通过信号衰减模型来估算距离。 例如:0xC0 对应-64dBm
十六进制 0xC0 的二进制表示为 11000000
作为有符号整数,最高位 1 表示负数
取反加 1 计算补码值:01000000 = 64
因此,0xC0 对应十进制-64
注:
1、如何获取厂商标识符?
(1)向蓝牙技术联盟(SIG)直接申请。
(2)使用已授权厂商的 ID,申请得到其授权。
2、Signal Power 是 8 位有符号整数,例如:0xC0 的二进制表示是 1100 0000,最高位 1 代表负数,对应十进制是-64。
3、厂商标识符是按照小端序存储的,例如:Apple 的公司 ID 是 0x004C(大端序),但在蓝牙数据包中按规范存储为 4C 00(小端序)。
注意:Apple 的 ID 是 0x004C,但是 demo 中需按照 0x4C,0x00 的方式写入存储。
原因:在 BLE 协议中,公司 ID 按照小端序存储。
大端序:高位字节存储在低地址,低位字节存储在高地址,0x004C 在大端序中存储为00 4C

小端序:高位字节存储在高地址,低位字节存储在低地址,0x004C 在小端序中存储为4C 00

8.1.2 ibeacon 如何利用 Signal Power 和 RSSI 进行距离估算?
ibeacon 通过 Signal Power(出厂校准信号强度) 和 RSSI(接收信号强度) 估算设备与 ibeacon 之间的距离,其核心原理基于蓝牙信号衰减模型。简单来讲就是设备出厂前先根据实际情况,测算在 1 米距离时的信号强度是多少,作为基准值,然后基于蓝牙信号衰减模型,根据实际信号值 RSSI 推算出实际距离。以下是具体方法和实现步骤:
注意:不同的蓝牙设备或相同设备不同的工况甚至不同的场地环境,都会影响 Signal Power 值,因此这个值虽然可以测量,但一定程度上是个经验值,很难测准。故 ibeacon 的距离估算功能只是估算大概范围,并不能用于精准定位。
1、关键概念
2、距离估算公式
iBeacon 使用 对数路径损耗模型(Log-distance Path Loss Model)计算距离:

-
d:估算距离(米)。
-
n:环境衰减因子(通常 2~4,空旷环境=2,普通室内=2.5-3,复杂环境多障碍物=3.5-4),环境越复杂信号衰减越快。
-
Tx Power:Beacon 的校准信号强度(通过实际环境测量拟合,需预先标定)。
-
RSSI:手机实际测得的信号强度。
3、示例计算
Tx Power = -60 dBm
RSSI = -80 dBm
n = 2.5(室内环境)

8.2 源码分析
8.2.1 文件说明
1、main.lua:主程序入口文件。
2、ble_ibeacon.lua:iBeacon 功能的具体实现,负责蓝牙初始化、广播配置和异常处理。
3、check_wifi.lua:Air8000 的蓝牙功能依赖 WiFi 协处理器,需确保 WiFi 固件为最新版本。本脚本文件检查当前 Air8000 模组的 WiFi 固件是否为最新版本,若不是则自动启动升级(需插入可联网的 SIM 卡)
8.2.2 ble_ibeacon.lua
8.2.2.1 全局变量定义
device_name :广播设备名称,
adv_state :广播状态标志,用于跟踪 iBeacon 广播的开启/关闭状态,
ibeacon_data :iBeacon 广播数据包,包含以下结构:
-
厂商标识符(2 字节):0x004C,本例演示的是 ibeacon,所以采用 Apple 的 ID:0x004C(iBeacon 是 Apple 的专有技术,采用 Apple 的 ID 才能显示成 ibeacon)
-
ibeacon 类型标识符(2 字节):固定为 0x02,0x15, 表示子类型为 ibeacon。
-
Proximity UUID(16 字节):0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
-
Major(2 字节):0x00,0x01
-
Minor(2 字节):0x00,0x02
-
Signal Power(1 字节):0xC0

8.2.2.2 事件回调函数 (ble_callback)
处理 BLE 设备的各种事件:
-
ble.EVENT_ADV_START :广播成功启动时设置 adv_state 为 true
-
ble.EVENT_ADV_STOP :广播停止时设置 adv_state 为 false

8.2.2.3 核心任务函数 (ble_ibeacon_task_func)
这是模块的主要功能实现,采用无限循环结构确保广播稳定运行:
-
初始化蓝牙核心 :创建 bluetooth_device 实例
-
初始化 BLE 功能 :创建 ble_device 实例并注册回调
-
配置广播参数 :通过 adv_create 方法设置:
-
广播地址模式 (ble.PUBLIC)
-
广播通道 (ble.CHNLS_ALL)
-
广播间隔 (intv_min/max = 120)
-
广播数据 (包含标志位、iBeacon 数据和设备名称)
-
启动广播 :调用 adv_start()方法
-
状态监控 :通过 while adv_state 循环监控广播状态
-
异常处理 :使用 goto EXCEPTION_PROC 标签统一处理各种初始化失败情况
-
资源清理与重试 :在异常情况下停止广播并重新初始化,间隔 5 秒后重试

8.3 日志分析
luatools 日志比较简单,只有开启广播的 log 打印

重点看 nrf connect 扫描出来的 ibeacon 信息:

九、LuatOS 上的扫描模式应用开发流程
9.1 前置知识了解
9.1.1 扫描窗口和扫描间隔
扫描窗口(scan_window):
是指 BLE 设备在扫描过程中,打开接收器去监听广播设备的时间段。这个时间段是设备实际进行扫描操作的时间,也称为扫描事件的持续时间。扫描窗口的单位通常是 0.625ms,并且它的值必须小于或等于扫描间隔。
扫描间隔(scan_interval):
表示两次扫描事件之间的间隔时间。扫描间隔的单位与扫描窗口相同,单位也是 0.625ms。
注:
1、如果扫描窗口与扫描间隔一样长,表明主机一直在扫描。
2、扫描窗口和扫描间隔是在 ble_device:scan_create 创建扫描需要填写的参数。
默认参数, addr_mode=0, scan_interval=100, scan_window=100

9.1.2 扫描到的广播数据如何解码?
ble.EVENT_SCAN_REPORT 事件的 ble.param 包含如下内容:
-
addr_type :整数类型,表示蓝牙设备的地址类型
-
adv_addr :设备的广播地址,可以通过 :toHex() 方法转换为十六进制字符串形式的 MAC 地址
-
rssi :整数类型,表示接收信号强度,单位为 dBm
-
data :二进制数据类型,表示接收到的原始广播数据,可以通过 :toHex() 方法转换为十六进制字符串
其中的广播数据 data 可以通过 ble_device:adv_decode(data) 来解码。
ble_device:adv_decode(data)
功能
解码广播数据
注意事项
广播数据通常来自于 ble.EVENT_SCAN_REPORT 事件的 ble_param.data
参数
data

返回值
local adv_data = ble_device:adv_decode(data)
adv_data

示例

9.2 源码分析
9.2.1 文件说明
1、main.lua:主程序入口文件。
2、ble_scan.lua:ble_scan.lua 是 Air8000 的蓝牙扫描功能实现模块,主要负责初始化蓝牙框架、配置并执行设备的扫描操作,并通过回调函数处理扫描到的设备信息。
3、check_wifi.lua:Air8000 的蓝牙功能依赖 WiFi 协处理器,需确保 WiFi 固件为最新版本。本脚本文件检查当前 Air8000 模组的 WiFi 固件是否为最新版本,若不是则自动启动升级(需插入可联网的 SIM 卡)
9.2.2 ble_scan.lua
9.2.2.1 全局变量定义
scan_state :扫描状态标志,用于跟踪 BLE 扫描的开启/关闭状态,初始值为 false 表示未扫描

9.2.2.2 处理扫描报告事件 (handle_scan_report)
功能:当扫描到 BLE 设备时,处理扫描报告事件。
处理内容:记录并输出发现设备的信息,包括 RSSI 值、设备地址和广播数据等,可以根据需求筛选数据。
示例演示了如何筛选 ibeacon 广播数据。

9.2.2.3 事件回调函数 (ble_callback)
处理 BLE 设备的各种扫描事件:
-
ble.EVENT_SCAN_INIT :扫描初始化成功时,记录日志并设置 scan_state 为 true
-
ble.EVENT_SCAN_REPORT :接收到扫描报告时,调用 handle_scan_report 函数处理扫描数据
-
ble.EVENT_SCAN_STOP :扫描停止时,记录日志并设置 scan_state 为 false

9.2.2.4 核心任务函数 (ble_scan_task_func)
这是模块的主要功能实现,采用无限循环结构确保扫描稳定运行:
-
初始化蓝牙核心 :创建 bluetooth_device 实例
-
初始化 BLE 功能 :创建 ble_device 实例并注册回调
-
配置扫描参数 :通过 scan_create()方法设置扫描参数(地址模式、扫描间隔、扫描窗口等)
-
启动扫描 :调用 scan_start()方法开始扫描周围 BLE 设备
-
状态监控 :通过 while scan_state 循环监控扫描状态
-
异常处理 :使用 goto EXCEPTION_PROC 标签统一处理各种初始化失败情况
-
资源清理与重试 :在异常情况下停止扫描并重新初始化,间隔 5 秒后重试

9.3 日志分析
luatools 日志,可以查看扫描到的 ibeacon 的广播包数据信息

最后再结合 ibeacon 应用,进行简单的距离估算:
代码:

十、常见问题
10.1 ibeacon 应用,为什么无法显示名称?
答:

一个完整的 BLE 广播数据包最长可以有 37 个字节,其中前 6 个字节固定用于设备 MAC 地址,剩下的 31 个字节才是我们可以自由配置的广播数据区域。这 31 个字节会被划分为若干个广播数据结构体(AD Structure)。
也就是 BLE 广播包 广播数据区域不超过 31 字节,那么 iBeacon 包含的数据和包含 flag 的 AD Structure 已经占了 30 个字节,如果要设置设备命名,会超出 31 字节。
可能有人会问,不是还有 1 个字节的空间吗,设备名称用一个字节不可以吗?
答:
-
名称:"1"(1 字符)。
-
AD Structure 长度:1(数据) + 1(类型) + 1(长度) = 3 字节。
-
总长度:27(iBeacon) + 3(Flags) + 3(名称) = 33 字节 → 仍超出。
10.2 什么是 Flags?
ble.FLAGS 说明
在 BLE 中,标志(flags)通常出现在广播数据中,这些标志用于指示设备的能力和可发现性等。
根据蓝牙核心规范(Bluetooth Core Specification),广播数据中的 Flags 字段是一个 8 位的位图(bitmask),每个位代表特定的含义,以下是各个位的定义(从 LSB 到 MSB):
-
Bit 0: LE Limited Discoverable Mode(有限可发现模式)
-
Bit 1: LE General Discoverable Mode(通用可发现模式,设备持续可被发现)
-
Bit 2: BR/EDR Not Supported(不支持经典蓝牙)
-
Bit 3: Simultaneous LE and BR/EDR to Same Device Capable(同一设备同时支持 BLE 和经典蓝牙)
-
Bit 4: Simultaneous LE and BR/EDR to Different Devices Capable(支持同时连接不同设备的 BLE 和经典蓝牙)
-
Bit 5-7: 保留(Reserved)
-
注意:Bit 0 和 Bit 1 不能同时被设置。如果同时设置,则视为无效。
-
Bit1 和 Bit2 被设置时,Flags 字段的值为 0x06(二进制 0000 0110),
-
Bit2 被设置时,Flags 字段的值为 0x04(二进制 0000 0100)。
10.3 常见的 BLE 断开连接 reason

示例:
1、中心设备和外围设备在数据传输过程中,把外围设备断电
中心设备会提示 8 的错误码,即数据传输过程中超时断开连接。

2、中心设备和外围设备连接时,中心设备主动发起 disconnect
中心设备会提示 22 的错误码,即本地主机终止连接。

外围设备会提示 19 的错误码,即远程用户终止连接。

今天的内容就分享到这里了~

浙公网安备 33010602011771号