LuatOS ble(一)
作者:王世豪 | 最后修改:2025-11-13
Hello ,大家好,我是王世豪。
欢迎大家来到合宙LuatOS直播课堂,一起学习LuatOS课程。
第一部分:LuatOS课程背景
因为今天是我们LuatOS系列课程的第005讲,同时也是LuatOS BLE专题课程的第一讲,所以在这里我就不重复讲解整个LuatOS课程的背景了;
如果您还不清楚LuatOS课程背景,可以访问:LuatOS课程背景 这个链接,进行了解;
第二部分:LuatOS BLE 课程讲哪些内容
今天是LuatOS BLE的第一讲:BLE之外围设备模式 ;
LuatOS BLE 第一讲课程主要包含以下几个部分:
- BLE总体介绍;
- BLE协议栈介绍;
- LuatOS BLE的四种工作模式;
- LuatOS BLE核心库功能介绍(重点讲解和外围设备模式有关的api);
- LuatOS 上的BLE外围设备模式应用开发流程;
第三部分:BLE总体介绍
3.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的低功耗特性来保证较长的续航。
3.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),能够准确测量蓝牙设备间的物理距离。
3.3 蓝牙官网资料下载地址
- 蓝牙技术联盟官网:https://www.bluetooth.com/zh-cn/
- 低功耗蓝牙™安全学习指南: https://www.bluetooth.com/zh-cn/bluetooth-resources/le-security-study-guide/
- Specifications and documents:https://www.bluetooth.com/specifications/specs/
- Assigned Numbers:https://www.bluetooth.com/specifications/assigned-numbers/#assignedNumbers
- 蓝牙核心规范<6.2>: https://www.bluetooth.com/specifications/specs/core-specification-6-2/
第四部分:BLE协议栈介绍
在开始讲LuatOS的BLE之前,先大概了解下BLE的协议栈。
4.1 BLE低功耗协议栈介绍

BLE协议栈主要用来对你的应用数据进行层层封包,以生成一个满足BLE协议的空中数据包。也就是说,把应用数据包裹在一系列的帧头(header)和帧尾(tail)中。
蓝牙协议规定了两个层次的协议,分别是:
(1)蓝牙核心协议(Bluetooth Core)
这是蓝牙技术的基础,规定了从无线电波收发到数据链路管理的所有底层技术细节。它确保了不同厂商设备之间的基本互联互通。核心协议层通常又分为控制器(Controller) 和主机(Host) 两个子部分。
(2)蓝牙应用层协议(Bluetooth Application)
建立在核心协议之上,定义了如何利用核心协议来实现具体的功能和服务。例如,心率监测、血压计、键盘鼠标等具体应用场景的规范。
4.2 BLE低功耗蓝牙核心协议层详解(Bluetooth Core)
4.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之间,是最容易受到干扰的广播信道。
广播时,设备会在三个信道上都发送数据,只要有一个被手机接收到,连接就能建立。这大大提高了在干扰环境下的发现概率。
4.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)周期性地发生。
4.2.3 主机控制接口层(HCI)
HCI 是 Host-Controller Interface 的缩写,即 “主机-控制器接口”。
它本质上是一套软件层面的规范和协议,定义了蓝牙协议栈中两个主要部分——主机(Host) 和控制器(Controller)——之间应该如何通信。
Host 和 Controller 是什么?
要理解HCI,首先必须明白蓝牙协议栈是如何分层的:
Controller:负责处理所有底层、实时性要求高的无线射频任务。 - 包含协议层:物理层、链路层。 - 职责:管理无线电信号、调制解调、跳频、数据包时序、广播、扫描等。它直接与硬件打交道。
Host:负责处理所有高层、应用逻辑相关的任务。 - 包含协议层:L2CAP、ATT、GATT、SM以及最终的应用程序。 - 职责:管理连接、定义服务与特征、处理加密安全、为应用程序提供API
4.2.4 逻辑链路控制及自适应协议层(L2CAP)
L2CAP对LL进行了一次简单封装。LL层只关心传输的数据本身,L2CAP就要区分加密通道还是普通通道,同时还要对连接间隔进行管理。
L2CAP是蓝牙协议栈的“交通调度中心”和“数据包装工”。 它位于基础射频协议之上,但低于应用层协议(如ATT/GATT),充当一个承上启下的多路复用和数据适配层。
4.2.5 属性协议层(ATT)
ATT全称是Attribute protocol(数据交互协议),这一层的关键词是Attribute(属性)。一个属性其实就是一条数据,属性是BLE数据提供单元,也是蓝牙空中传播数据的最上层。
ATT层定义了各种属性,属性的操作方法。通过ATT层可以读写对端设备的属性,但是属性之间有什么联系、各个属性怎么组合起来提供服务,由上层GATT负责。
属性,是ATT层的 关键字。
4.2.6 通用访问配置文件层(GAP)
Generic Access Profile(通用访问配置规范),主要用来进行广播、扫描和发起连接等。
GAP层将设备分为四种角色,分别是外围设备,中心设备,广播设备和观察设备。
这些设备围绕着广播和连接的差异性而区分,外围设备和广播设备对外发出广播数据,中心设备和观察设备扫描外部广播数据,广播设备和观察设备通常不建立连接,而外围设备和中心设备可以建立连接。
围绕着广播和连接,GAP层定义了许多不同的"模式(mode)",比如广播模式和连接模式,在不同模式下的操作称为“规程(procedure)”。
例如:当一个设备正在进行广播时,称其为"广播模式"。广播往往会持续较长时间,也许是该设备唯一用途。而当一个设备正在寻找广播者时,称其为"观察规程"。观察往往持续一段较短时间,用以构建用户界面或者寻找需要的指定信息。
4.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 工作模式,并通过实例展示如何应用。
5.1 模式解释
- 外围设备模式(peripheral):设备会被扫描到, 并且可以被连接;
- 中心设备模式(central):设备会扫描其他设备, 并且可以连接其他设备;
- 广播者模式(ibeacon):设备会周期性的广播beacon信息, 可以被扫描到, 但一般不会被连接;
- 观察者模式(scan):设备会扫描其他设备, 但不会连接其他设备。
5.2 四种模式的基本流程
5.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、在回调函数中处理连接事件, 如接收数据, 发送数据等
5.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操作完成等)
5.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()
5.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()
5.3 应用场景
5.3.1 外围设备+中心设备(连接模式)
设计框图:

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

第六部分:LuatOS上的BLE核心库
docs链接地址:https://docs.openluat.com/osapi/core/ble/
6.1 常量详解
61.1 地址模式常量
ble.PUBLIC
常量含义:公共地址模式;
数据类型:number;
注意事项:公共地址模式下,使用设备出厂时分配的MAC地址;
示例代码:-- 设置广播地址模式为公共地址
ble_device:adv_create({
addr_mode = ble.PUBLIC
})
6.1.2 特征属性常量
ble.READ
常量含义:特征可读属性;
数据类型:number;
注意事项:表示该特征支持读取操作;
示例代码:-- 创建一个可读特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.READ -- 特征可读属性
}
}
ble_device:gatt_create(att_db)
ble.WRITE
常量含义:特征可写属性;
数据类型:number;
注意事项:表示该特征支持写入操作;
示例代码:-- 创建一个可写特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.WRITE -- 特征可写属性
}
}
ble_device:gatt_create(att_db)
ble.NOTIFY
常量含义:特征通知属性;
数据类型:number;
注意事项:表示该特征支持通知功能,无需接收方确认;
示例代码:-- 创建一个支持通知的特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.NOTIFY -- 特征通知属性
}
}
ble_device:gatt_create(att_db)
ble.IND
常量含义:特征指示属性;
数据类型:number;
注意事项:表示该特征支持指示功能,需要接收方确认;
示例代码:-- 创建一个支持指示的特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
{
string.fromHex("EA01"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.IND -- 特征指示属性
}
}
ble_device:gatt_create(att_db)
ble.WRITE_CMD
常量含义:特征写入无响应属性;
数据类型:number;
注意事项:表示该特征支持无需响应的写入操作;
示例代码:-- 创建一个支持无响应写入的特征
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID
{
string.fromHex("EA02"), -- Characteristic UUID, 特征UUID,可以是16位、32位或128位
ble.WRITE_CMD -- 特征写入无响应属性
}
}
ble_device:gatt_create(att_db)
6.1.3 事件类型常量
ble.EVENT_CONN
常量含义:连接成功事件;
数据类型:number;
注意事项:当BLE设备成功建立连接时触发;
示例代码:-- 在回调函数中处理连接成功事件
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_CONN then
log.info("ble", "connect 成功", ble_param.addr:toHex())
end
end
ble.EVENT_DISCONN
常量含义:断开连接事件;
数据类型:number;
注意事项:当BLE设备连接断开时触发;
示例代码:-- 在回调函数中处理断开连接事件
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_DISCONN then
log.info("ble", "disconnect", ble_param.reason)
end
end
ble.EVENT_WRITE
常量含义:收到写请求事件;
数据类型:number;
注意事项:当中心设备向外围设备的特征写入数据时(包括开启通知或指示功能),在外围设备端触发此事件;
示例代码:-- 在外围设备的回调函数中处理写请求
-- 示例场景:手机APP设置手环闹钟
-- 中心设备(手机)向外围设备(手环)的闹钟特征写入数据:"08:30"
-- 外围设备触发此事件,解析数据并设置闹钟
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_WRITE then
log.info("ble", "接收到写请求", ble_param.data:toHex())
end
end
ble.EVENT_READ_VALUE
常量含义:读取操作完成事件;
数据类型:number;
注意事项:当中心设备主动读取外围设备的特征值完成时,在中心设备端触发此事件;
示例代码:-- 在中心设备的回调函数中处理读取完成事件
-- 示例场景:读取手环电量
-- 中心设备(手机)读取外围设备(手环)的电量特征(0x2A19)
-- 读取完成后,手机触发此事件,获取电量百分比并显示
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_READ_VALUE then
log.info("ble", "读取操作完成", ble_param.data:toHex())
end
end
ble.EVENT_SCAN_REPORT
常量含义:扫描报告事件;
数据类型:number;
注意事项:当中心设备扫描到其他BLE设备的广播时触发;
示例代码:-- 在中心设备的回调函数中处理扫描报告事件
-- 示例场景:设备发现与连接
-- 中心设备(手机)扫描周围的外围设备
-- 每发现一个设备就触发此事件,可以显示设备列表供用户选择连接
function ble_callback(ble_device, ble_event, ble_param)
if ble_evt == ble.EVENT_SCAN_REPORT then
log.info("ble", "scan report", ble_param.rssi, ble_param.adv_addr:toHex())
end
end
ble.EVENT_GATT_ITEM
常量含义:收到GATT项事件;
数据类型:number;
注意事项:当中心设备发现外围设备的GATT服务或特征时触发;
示例代码:-- 在中心设备的回调函数中处理GATT项事件,一般调试使用
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_GATT_ITEM then
log.info("ble", "gatt item", ble_param[1]:toHex(), #ble_param)
end
end
ble.EVENT_GATT_DONE
常量含义:GATT操作完成事件;
数据类型:number;
注意事项:当中心设备完成外围设备的GATT服务发现后触发;
示例代码:-- 在中心设备的回调函数中处理GATT完成事件
-- 示例场景:设备就绪通知
-- 中心设备(手机)完成对外围设备(手环)的GATT发现
-- 触发此事件表示可以开始正常的数据交互(读取、写入、订阅)
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_GATT_DONE then
log.info("ble", "gatt done", ble_param.service_num)
end
end
ble.EVENT_SCAN_STOP
常量含义:扫描停止事件;
数据类型:number;
注意事项:当中心设备停止扫描BLE外围设备时触发;
示例代码:-- 在中心设备的回调函数中处理扫描停止事件
function ble_callback(ble_device, ble_event, ble_param)
if ble_event == ble.EVENT_SCAN_STOP then
log.info("ble", "scan stop")
end
end
6.1.4 广播相关常量
ble.COMPLETE_LOCAL_NAME
常量含义:完整本地名称;
数据类型:number;
注意事项:用于在广播数据中设置设备的完整名称;
示例代码:-- 在广播数据中设置设备名称
ble_device:adv_create({
adv_data = {
{ble.COMPLETE_LOCAL_NAME, "LuatOS"}
}
})
ble.CHNLS_ALL
常量含义:使用所有广播通道;
数据类型:number;
注意事项:表示使用蓝牙LE的所有三个广播通道(37, 38, 39);
示例代码:-- 设置使用所有广播通道
ble_device:adv_create({
channel_map = ble.CHNLS_ALL
})
ble.CHNL_37
常量含义:使用广播通道37;
数据类型:number;
注意事项:表示仅使用蓝牙LE的广播通道37;
示例代码:-- 设置仅使用广播通道37
ble_device:adv_create({
channel_map = ble.CHNL_37
})
ble.CHNL_38
常量含义:使用广播通道38;
数据类型:number;
注意事项:表示仅使用蓝牙LE的广播通道38;
示例代码:-- 设置仅使用广播通道38
ble_device:adv_create({
channel_map = ble.CHNL_38
})
ble.CHNL_39
常量含义:使用广播通道39;
数据类型:number;
常量取值:0x04;
注意事项:表示仅使用蓝牙LE的广播通道39;
示例代码:-- 设置仅使用广播通道39
ble_device:adv_create({
channel_map = ble.CHNL_39
})
ble.FLAGS
常量含义:广播标志位;
数据类型:number;
常量取值:0x01:
注意事项:用于在广播数据中设置设备的广播标志位;
示例代码:-- 在广播数据中设置广播标志位
ble_device:adv_create({
adv_data = {
{ble.FLAGS, string.char(0x06)}
}
})
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
常量含义:服务数据;
数据类型:number;
常量取值:0x16;
注意事项:用于在广播数据中设置设备的服务数据;
示例代码:-- 在广播数据中设置服务数据
ble_device:adv_create({
adv_data = {
{ble.SERVICE_DATA, string.fromHex("FE01")}
}
})
ble.MANUFACTURER_SPECIFIC_DATA
常量含义:制造商特定数据;
数据类型:number;
常量取值:0xFF;
注意事项:用于在广播数据中设置设备的制造商特定数据;
示例代码:-- 在广播数据中设置制造商特定数据
ble_device:adv_create({
adv_data = {
{ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
}
})
6.2 函数详解
bluetooth.init()
功能
初始化蓝牙框架
注意事项
必须在使用蓝牙功能之前调用;
仅需要调用一次,若创建失败, 会返回nil, 请检查内存是否足够。
参数
无
返回值
local bluetooth_device = bluetooth.init()
bluetooth_device
含义说明:蓝牙对象;
数据类型:userdata/nil;
取值范围:创建成功返回userdata对象,失败返回nil;
注意事项:有返回nil的情况,需做好对应逻辑处理;
返回示例:成功返回:BLUETOOTH*: 0C7FD730
失败返回:nil
local bluetooth_device = bluetooth.init()
log.info("bluetooth_device", bluetooth_device)
示例
-- 初始化蓝牙
bluetooth_device = bluetooth.init()
if not bluetooth_device then
log.error("bluetooth", "init failed")
return
end
bluetooth_device:ble(ble_callback)
功能
创建一个BLE对象, 用于操作BLE设备
注意事项
必须在bluetooth.init()初始化成功后调用;
对象生命周期管理 :BLE对象需要在整个操作周期内保持有效,从初始化到最终释放;
全局/模块级变量推荐 :为了确保对象在需要时始终可用,通常建议将BLE对象定义在合适的作用域中:
- 模块级变量:适用于单个模块内部使用
- 全局变量:适用于跨模块访问
- 作为参数传递
参数
ble_callback
含义说明:BLE事件回调函数, 用于处理BLE设备的事件, 如连接、断开、接收数据等;
详细说明请参考本api中的示例部分。
数据类型:function;
取值范围:无;
是否必选:是;
注意事项:不同事件类型的param参数结构不同,需根据evt值进行相应处理;
参数示例:-- 创建回调函数处理BLE事件
function ble_callback(ble_device, ble_event, ble_param)
-- ble_device: BLE设备对象
-- ble_event: 事件类型(如ble.EVENT_CONN、ble.EVENT_DISCONN等)
-- ble_param: 事件相关参数,结构根据事件类型不同而变化
-- 具体事件类型及参数说明详见后续示例代码
end
返回值 local ble_device = bluetooth_device:ble(ble_callback)
ble_device
含义说明:BLE对象;
数据类型:userdata/nil;
取值范围:创建成功返回userdata对象,失败返回nil;
注意事项:后续所有BLE操作都依赖此对象,注意对象的生命周期管理;
有返回nil的情况,需做好对应逻辑处理。
返回示例:成功返回:BLE*: 0C7FCFA8
失败返回:nil
local ble_device = bluetooth_device:ble(ble_callback)
log.info("ble_device", ble_device )
示例
-- ble_callback 是自定义函数, 用于处理BLE事件
-- BLE事件回调函数, 回调时的参数如下:
function ble_callback(ble_device, ble_event, ble_param)
-- ble_device 是BLE设备对象, 可以通过dev:adv_create()等方法进行操作
-- ble_event 是BLE事件类型, 可以是以下几种:
-- ble.EVENT_CONN: 连接成功
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.addr: 对端设备的地址(string), 6字节的二进制数据, 代表BLE设备的MAC地址
-- ble.EVENT_DISCONN: 断开连接
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.reason: 断开连接的原因(number)
-- ble.EVENT_WRITE: 收到写请求
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.uuid_service: 服务的UUID(string)
-- ble_param.uuid_characteristic: 特征的UUID(string)
-- ble_param.uuid_descriptor: 描述符的UUID(string), 可选, 不一定存在
-- ble_param.data: 写入的数据
-- ble.EVENT_READ_VALUE: 读取操作完成
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.uuid_service: 服务的UUID(string)
-- ble_param.uuid_characteristic: 特征的UUID(string)
-- ble_param.uuid_descriptor: 描述符的UUID(string), 可选, 不一定存在
-- ble_param.data: 读取到的数据
-- ble.EVENT_SCAN_REPORT: 扫描到设备
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.rssi: 信号强度(number)
-- ble_param.adv_addr: 广播地址(string), 6字节的二进制数据
-- ble_param.data: 广播数据(string), 二进制数据
-- ble.EVENT_GATT_ITEM: 收到GATT项
-- ble_param是事件参数(table),为一个嵌套表结构,具体如下:
-- ble_param[1]: 服务的UUID(string), 二进制数据
-- ble_param[2...]: 特征值信息(table),每个都是一个子表
-- ble_param[索引][1]: 特征值的UUID(string), 二进制数据
-- ble_param[索引][2]: 特征值的属性(number), 表示读写权限等
-- ble.EVENT_GATT_DONE: GATT操作完成
-- ble_param是事件参数(table), 包含以下字段:
-- ble_param.service_num: 服务数量(number)
-- ble.EVENT_SCAN_STOP: 扫描停止
-- ble_param为nil
if ble_event == ble.EVENT_CONN then
log.info("ble", "connect 成功", ble_param, ble_paramand ble_param.addr and ble_param.addr:toHex() or "unknow")
ble_stat = true
elseif ble_event == ble.EVENT_DISCONN then
log.info("ble", "disconnect")
ble_stat = false
-- 1秒后重新开始广播
sys.timerStart(function() dev:adv_start() end, 1000)
elseif ble_event == ble.EVENT_SCAN_REPORT then
log.info("ble", "scan report", ble_param.rssi, param.adv_addr:toHex(), param.data:toHex())
elseif ble_event == ble.EVENT_WRITE then
log.info("ble", "接收到写请求", ble_param.uuid_service:toHex(), ble_param.uuid_characteristic:toHex(), ble_param.data:toHex())
elseif ble_event == ble.EVENT_READ_VALUE then
log.info("ble", "读取操作完成", ble_param.uuid_service:toHex(), ble_param.uuid_characteristic:toHex(), ble_param.data:toHex())
elseif ble_event == ble.EVENT_SCAN_STOP then
log.info("ble", "scan stop")
elseif ble_event == ble.EVENT_GATT_ITEM then
log.info("ble", "gatt item", ble_param[1]:toHex(), #ble_param)
elseif ble_event == ble.EVENT_GATT_DONE then
log.info("ble", "gatt done", ble_param.service_num)
end
end
-- 初始化蓝牙并创建BLE对象
bluetooth_device = bluetooth.init()
ble_device = bluetooth_device:ble(ble_callback)
ble_device:scan_create(addr_mode,scan_interval,scan_window)
功能
创建一个BLE扫描
注意事项
无
参数
addr_mode
含义说明:要扫描的广播地址模式
数据类型:number;
取值范围:可选值: 当前仅支持ble.PUBLIC
是否必选:否;
注意事项:默认值为ble.PUBLIC
参数示例:ble.PUBLIC
scan_interval
含义说明:扫描间隔
表示两次扫描事件之间的间隔时间;
数据类型:number;
取值范围:单位为0.625ms, 最小值为20, 最大值为10240
是否必选:否;
注意事项:默认值为100
参数示例:100
scan_window
含义说明:扫描窗口
是指 BLE 设备在扫描过程中,打开接收器去监听广播设备的时间段;
这个时间段是设备实际进行扫描操作的时间,也称为扫描事件的持续时间;
数据类型:number;
取值范围:单位为0.625ms, 最小值为20, 最大值为10240
是否必选:否;
注意事项:默认值为100,它的值必须小于或等于扫描间隔;
参数示例:100
返回值
local result = ble_device:scan_create(addr_mode,scan_interval,scan_window)
result
含义说明:是否创建成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示创建成功,false表示创建失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:scan_create(ble.PUBLIC, 100, 100)
log.info("result", result)
示例
-- 创建BLE扫描
ble_device:scan_create(ble.PUBLIC, 100, 100)
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
含义说明:是否开始扫描成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开始扫描成功,false表示开始扫描失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:scan_start()
log.info("result", result)
示例
-- 开始BLE扫描
ble_device:scan_start()
ble_device:scan_stop()
功能
停止BLE扫描
注意事项
扫描会一直进行, 直到调用ble.scan_stop()停止扫描。
参数
无
返回值
local result = ble_device:scan_stop()
result
含义说明:是否停止扫描成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示停止扫描成功,false表示停止扫描失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:scan_stop()
log.info("result", result)
示例
-- 停止BLE扫描
ble_device:scan_stop()
ble_device:connect(mac, addr_type)
功能
发起BLE连接请求
注意事项
无
参数
mac
含义说明:目标蓝牙设备的MAC地址;
数据类型:string;
取值范围:有效的12个十六进制字符组成的蓝牙MAC地址字符串(如"AABBCCDDEEFF")
是否必选:是;
注意事项:MAC地址需要先使用string.fromHex()函数将十六进制字符串转换为二进制格式;
参数示例:-- MAC地址转换示例
local mac_hex = "AABBCCDDEEFF" -- 12位十六进制字符串
-- 转换为二进制格式:
local mac_bin = string.fromHex(mac_hex)
addr_type
含义说明:目标蓝牙设备的地址类型;
数据类型:number;
取值范围:可选值: 当前仅支持ble.PUBLIC;
是否必选:是;
注意事项:无;
参数示例:ble.PUBLIC
返回值
local result = ble_device:connect(mac, addr_type)
result
含义说明:是否成功发起连接请求;
真正的连接结果通过异步事件ble.EVENT_CONN通知到bluetooth_device:ble(ble_callback)中设置的回调函数ble_callback:
数据类型:boolean;
取值范围:true/false;
注意事项:true表示连接请求已成功发起,不代表连接已建立;
false表示发起连接请求失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:connect(mac, addr_type)
log.info("result", result)
示例
-- BLE连接
ble_device:connect(string.fromHex("C8478C4E027D"),0)
ble_device:disconnect()
功能
发起BLE断开连接请求
注意事项
无
参数
无
返回值
local result = ble_device:disconnect()
result
含义说明:是否成功发起断开连接请求;
真正的连接结果通过异步事件ble.EVENT_DISCONN通知到bluetooth_device:ble(ble_callback)中设置的回调函数ble_callback;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示断开连接请求已成功发起,不代表连接已被断开;
false表示发起断开连接请求失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:disconnect()
log.info("result", result)
示例
-- BLE断开连接
ble_device:disconnect()
ble_device:gatt_create(opts)
功能
创建一个BLE GATT服务
注意事项
确保UUID格式正确,且特征属性使用正确的权限常量;
特征属性必须是 ble.NOTIFY | ble.READ | ble.WRITE | ble.IND 的一种或多种组合;
参数
opts
含义说明:GATT服务的描述信息,包含服务UUID和其下所有特征的定义;
表的第一个元素:服务的UUID(通过string.fromHex转换的16位、32位或128位UUID)
表的后续元素:特征定义表(每个特征为一个子表),子表结构为:
第一个元素:特征的UUID(通过string.fromHex转换)
第二个元素:特征的属性(权限常量的组合,如ble.NOTIFY | ble.READ | ble.WRITE | ble.IND)
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:确保UUID格式正确,且特征属性使用正确的权限常量;
返回值
local result = ble_device:gatt_create(opts)
result
含义说明:是否创建GATT服务成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示创建GATT服务成功,false表示创建GATT服务失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:gatt_create(opts)
log.info("result", result)
示例
local att_db = { -- Service
string.fromHex("FA00"), -- Service UUID, 服务的UUID, 可以是16位、32位或128位
-- Characteristic
{ -- Characteristic 1
string.fromHex("EA01"), -- Characteristic UUID Value, 特征的UUID值, 可以是16位、32位或128位
ble.NOTIFY | ble.READ | ble.WRITE -- Properties, 对应蓝牙特征的属性, 参考权限常量
}, { -- Characteristic 2
string.fromHex("EA02"), ble.WRITE
}, { -- Characteristic 3
string.fromHex("EA03"), ble.READ
}, { -- Characteristic 4
string.fromHex("EA04"), ble.IND | ble.READ
}
}
ble_device:gatt_create(att_db)
ble_device:adv_create(opts)
功能
创建一个BLE广播
注意事项
无
参数
opts
含义说明:BLE广播配置参数表,包含广播的各种属性配置
addr_mode: 广播地址模式(可选值:ble.PUBLIC)
-- addr_mode可选值说明:
-- ble.PUBLIC - 公共地址(设备出厂时分配的固定MAC地址)
channel_map: 广播通道配置(可选值:ble.CHNL_37, ble.CHNL_38, ble.CHNL_39, ble.CHNLS_ALL)
-- channel_map可选值说明:
-- ble.CHNL_37 - 广播通道37
-- ble.CHNL_38 - 广播通道38
-- ble.CHNL_39 - 广播通道39
-- ble.CHNLS_ALL - 广播通道37、38、39
intv_min: 广播间隔最小值(单位:0.625ms,取值范围:20-10240)
intv_max: 广播间隔最大值(单位:0.625ms,取值范围:20-10240)
adv_data: 广播数据内容(支持表格形式和字符串形式,字符串形式不超过255字节)
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble:adv_create(opts)
result
含义说明:是否创建广播成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示创建广播成功,false表示创建广播失败;
返回示例:成功返回:true
失败返回:false
local result = ble:adv_create(opts)
log.info("result", result)
示例
-- 创建广播信息
ble_device:adv_create({
addr_mode = ble.PUBLIC, -- 广播地址模式, 可选值: ble.PUBLIC
channel_map = ble.CHNLS_ALL, -- 广播的通道, 可选值: ble.CHNL_37, ble.CHNL_38, ble.CHNL_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)},
{ble.COMPLETE_LOCAL_NAME, "LuatOS123"}, -- 广播的设备名
{ble.SERVICE_DATA, string.fromHex("FE01")}, -- 广播的服务数据
{ble.MANUFACTURER_SPECIFIC_DATA, string.fromHex("05F0")}
}
})
ble_device:adv_start()
功能
开始广播
注意事项
对于外围设备模式, 如果被断开了连接, 则需要重新开始广播, 才能被重新搜索到
参数
无
返回值
local result = ble_device:adv_start()
result
含义说明:是否开始广播成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开始广播成功,false表示开始广播失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:adv_start()
log.info("result", result)
示例
-- 开始广播
ble_device:adv_start()
ble_device:adv_stop()
功能
主动停止广播
注意事项
无
参数
无
返回值
local result = ble_device:adv_stop()
result
含义说明:是否停止广播成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示停止广播成功,false表示停止广播失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:adv_stop()
log.info("result", result)
示例
-- 停止广播
ble_device:adv_stop()
ble_device:write_notify(opts,value)
功能
写入带通知的特征值
注意事项
外围设备使用,主动向中心设备发送通知数据
参数
opts
含义说明:写入特征值的配置参数表,包含服务UUID和特征值的UUID
uuid_service: 服务的UUID,用于标识要写入的特征值所属的服务
uuid_characteristic: 特征的UUID值,用于标识要写入的特征值
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
value
含义说明:写入的特征值内容
数据类型:string;
取值范围:无特别限制
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble_device:write_notify(opts,value)
result
含义说明:是否写入成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示写入成功,false表示写入失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:write_notify(opts,value)
log.info("result", result)
示例
-- 写入带通知的特征值
ble_device:write_notify({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, "Hello BLE") -- 要写入的值
ble_device:write_indicate(opts,value)
功能
写入带指示的特征值
注意事项
外围设备使用,主动向中心设备发送指示数据
参数
opts
含义说明:写入特征值的配置参数表,包含服务UUID和特征值的UUID
uuid_service: 服务的UUID,用于标识要写入的特征值所属的服务
uuid_characteristic: 特征的UUID值,用于标识要写入的特征值
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
value
含义说明:写入的特征值内容
数据类型:string;
取值范围:无特别限制
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble:write_indicate(opts,value)
result
含义说明:是否写入成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示写入成功,false表示写入失败;
返回示例:成功返回:true
失败返回:false
local result = ble:write_indicate(opts,value)
log.info("result", result)
示例
-- 写入带指示的特征值
ble_device:write_indicate({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, "Hello BLE") -- 要写入的值
ble_device:write_value(opts,value)
功能
写入特征值
注意事项
无
参数
opts
含义说明:写入特征值的配置参数表,包含服务UUID和特征值的UUID
uuid_service: 服务的UUID,用于标识要写入的特征值所属的服务
uuid_characteristic: 特征的UUID值,用于标识要写入的特征值
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写
value
含义说明:写入的特征值内容
数据类型:string;
取值范围:无特别限制
是否必选:是;
注意事项:注意参数根据实际情况填写
返回值
local result = ble_device:write_value(opts,value)
result
含义说明:是否写入成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示写入成功,false表示写入失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:write_value(opts,value)
log.info("result", result)
示例
-- 写入特征值,填充预设值,被动读取
ble_device:write_value({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, "Hello BLE") -- 要写入的值
ble_device:read_value(opts)
功能
读取特征值
注意事项
无
参数
opts
含义说明:读取特征值的配置参数表,包含服务UUID和特征值的UUID;
uuid_service: 服务的UUID,用于标识要读取的特征值所属的服务;
uuid_characteristic: 特征的UUID值,用于标识要读取的特征值;
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写;
返回值
local result = ble_device:read_value(opts)
result
含义说明:是否读取成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示读取成功,false表示读取失败;
通过回调中的 EVENT_READ_VALUE 事件返回读取的value值;
返回示例:成功返回:true
失败返回:false
local result = ble_device:read_value(opts)
log.info("result", result)
示例
-- 读取特征值,通过回调中的 EVENT_READ_VALUE 事件返回读取的value值
ble_device:read_value({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
})
ble_device:notify_enable(opts,enable)
功能
开关通知监听
注意事项
中心设备使用,配置是否接收外围设备发送的通知消息
参数
opts
含义说明:通知监听的配置参数表,包含服务UUID和特征值的UUID;
uuid_service: 服务的UUID,用于标识要通知监听的特征值所属的服务;
uuid_characteristic: 特征的UUID值,用于标识要通知监听的特征值;
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写;
enable
含义说明:通知监听的状态;;
数据类型:boolean;
取值范围:true/false;
是否必选:是;
注意事项:true表示开启通知监听,false表示关闭通知监听;
返回值
local result = ble_devie:notify_enable(opts,enable)
result
含义说明:是否开启通知监听成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开启通知监听成功,false表示开启通知监听失败;
返回示例:成功返回:true
失败返回:false
local result = ble_devie:notify_enable(opts,enable)
log.info("result", result)
示例
ble_device:notify_enable({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, true) -- 开/关
ble_device:indicate_enable(opts,enable)
功能
开关指示监听
注意事项
中心设备使用,配置是否接收外围设备发送的指示消息
参数
opts
含义说明:指示监听的配置参数表,包含服务UUID和特征值的UUID;
uuid_service: 服务的UUID,用于标识要指示监听的特征值所属的服务;
uuid_characteristic: 特征的UUID值,用于标识要指示监听的特征值;
数据类型:table;
取值范围:符合上述结构的table对象;
是否必选:是;
注意事项:注意参数根据实际情况填写;
enable
含义说明:指示监听的状态;;
数据类型:boolean;
取值范围:true/false;
是否必选:是;
注意事项:true表示开启指示监听,false表示关闭指示监听
返回值
local result = ble_device:indicate_enable(opts,enable)
result
含义说明:是否开启指示监听成功;
数据类型:boolean;
取值范围:true/false;
注意事项:true表示开启指示监听成功,false表示开启指示监听失败;
返回示例:成功返回:true
失败返回:false
local result = ble_device:indicate_enable(opts,enable)
log.info("result", result)
示例
ble_device:indicate_enable({
uuid_service = "FA00", -- 服务的UUID, 可以是16位、32位或128位
uuid_characteristic = "EA01", -- 特征的UUID值, 可以是16位、32位或128位
}, true) -- 开/关
ble_device:adv_decode(data)
功能
解码广播数据
注意事项
广播数据通常来自于ble.EVENT_SCAN_REPORT 事件的 ble_param.data
参数
data
含义说明:原始广播数据;
数据类型:string;
取值范围:广播数据的字符串表示;
是否必选:是;
注意事项:注意参数根据实际情况填写;
返回值
local adv_data = ble_device:adv_decode(data)
adv_data
含义说明:广播数据的解码结果,为table类型,表结构如下:
索引型表(索引从1开始);
每个索引对应一个子表,代表一个广告数据单元(AD Structure);
每个子表包含以下三个字段:
len :整数类型,表示数据长度
tp :整数类型,表示广播数据类型(AD Type)
data :字符串类型(二进制数据),表示广播数据内容
数据类型:table/nil;
取值范围:解码成功返回table对象,失败返回nil。
注意事项:返回的数据需要自行解析提取
返回示例:成功返回:table: 0C7F6570
失败返回:nil
local result = ble_device:adv_decode(data)
log.info("result", result)
示例
-- 解码广播数据
local adv_data = ble_device:adv_decode(ble_param.data)
-- 解析广播数据
if adv_data then
for k, v in pairs(adv_data) do
log.info("ble", "adv data", v.len, v.tp, v.data:toHex())
end
end
ble.mac()
功能
获取蓝牙MAC
注意事项
无
参数
无
返回值
local mac = ble.mac
mac
含义说明:蓝牙MAC地址;
数据类型:string/nil;
取值范围:成功返回string,失败返回nil;
注意事项:成功返回6字节的二进制字符串,需要通过toHex()方法转换为可读的12个连续十六进制字符(如"AABBCCDDEEFF");
返回示例:成功返回:如果mac地址为"AABBCCDDEEFF",则返回6个字节长度的string数据;
第1个字节的ascii值为0xAA,后续5个字节的ascii值依次为0xBB, 0xCC, 0xDD, 0xEE, 0xFF
失败返回:nil
local mac = ble.mac()
log.info("原始二进制字符串", mac)
local mac_hex = mac:toHex()
log.info("转换成十六进制字符", mac_hex) ---- 输出如:"AABBCCDDEEFF"
示例
-- 本函数于2025.8.29新增
local mac = ble.mac()
log.info("ble mac", mac and mac:toHex())
第七部分:LuatOS上的BLE 应用开发流程
本部分将深入一项具体实践:在 「外围设备模式」下进行 BLE 应用开发。
BLE——外围设备模式代码:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/ble/peripheral
BLE——外围设备模式文档:https://docs.openluat.com/air8000/luatos/app/BLE/peripheral/
7.1 总体设计框图

7.2 分析项目代码
这个ble peripheral demo中的readme文件,以及代码中的注释都比较详细,接下来我用vscode直接打开这份demo项目代码,和大家一起分析下项目代码;
程序结构:
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
文件说明:
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 卡)
7.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口;
准备软件环境:
2、Air8000 V2016版本固件(理论上,2025年7月26日之后发布的固件都可以)
3、PC端的串口工具,例如SSCOM、LLCOM等都可以
4、nrf connect 蓝牙调试软件
IOS版本:APP Store搜索 nrf connect下载即可;
安卓版本:压缩包比较大,这里就不再放了,大家在下面文档的4.1章节部分下载即可。 https://docs.openluat.com/air8000/luatos/app/BLE/peripheral/#_4
接下来为大家演示Air8000作为外围设备+手机蓝牙调试软件,如何连接,并进行双向数据通信。
第八部分:BLE外围设备模式常见问题分析
8.1 烧录示例demo后,无法搜到蓝牙
Air8000
- 首先检查demo,固件是否是最新的,若不是则需更新的最新的版本测试,若已经是最新的,看第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卡。

(2)本地线刷升级wifi
参考下面这篇文档,进行线刷升级wifi固件
https://docs.openluat.com/air8000/luatos/app/updatwifi/update/
若升级好后,测试依旧有问题,请向合宙官方技术人员反馈。
Air8101
- 首先检查demo,固件是否 都是最新的,若不是则需更新demo以及固件版本测试;若检查已经是最新的还是测试有问题,请向合宙官方技术人员反馈。
8.2 使用Air8000/Air8101 作为外围设备,向已经建立连接的手机蓝牙调试软件发送数据,发现手机调试软件接收到的数据不全。
原因:
MTU设置的问题,Air8000/Air8101支持的MTU默认是256字节,如果手机上的蓝牙调试软件的MTU较小,会以小的为准。
解决方案:
- 可以通过Air8000读到对端蓝牙设备的MTU大小,根据读到的MTU的大小做分包处理即可。(读取对端设备MTU的功能还在开发中)
- 调大对端蓝牙设备的MTU。