03 BLE 观察者模式(scan)
作者:王世豪 | 最后修改:2026-04-10
一、BLE 概述
BLE(Bluetooth Low Energy),也称为 Bluetooth Smart,是蓝牙 4.0 及更高版本引入的低功耗无线通信技术,专为低带宽、间歇性数据传输的物联网(IoT)和穿戴设备设计。
Air8101 支持最新的 BLE 5.4 版本,BLE 5.4 在上一代基础上继续优化了功耗和性能,为用户提供了更高效、更稳定的蓝牙连接体验。具体的 BLE 版本区别若有兴趣请自行上网查询,本处不再赘述。
Air8101 的蓝牙发射功率为 6dBm,不可调整;最远通讯距离在10米左右。
BLE 支持的四种模式
Air8101 的 BLE 支持 4 种模式,分别是中心设备模式(central),外围设备模式(peripheral),广播者模式(ibeacon),以及观察者模式(scan)。
1、中心设备模式(central):
中心设备模式是能够搜索别人并主动建立连接的一方,从扫描状态转化而来的。它会定期的扫描周围的广播状态设备发送的广播信息,可以对周围设备进行搜索并选择所需要连接的从设备进行配对连接,建立通信链路成功后,主从双方就可以发送接收数据。
2、外围设备模式(peripheral):
外围设备模式是从广播者模式转化而来的,未被连接的外围设备首先进入广播状态,等待被中心设备搜索,当中心设备扫描到外围设备建立连接后,就可以和中心设备进行数据的收发,其不能主动的建立连接,只能等别人来连接自己。和广播模式有区别的地方在于,外围设备模式的设备是可以被连接的,定期的和中心设备进行连接和数据传输,在数据传输过程中作外围设备。
3、广播者模式(ibeacon)
处于广播模式的设备,会周期性的广播 beacon 信息, 可以被扫描, 但一般不会被连接,典型应用 ibeacon。
4、观察者模式(scan)
观察者模式,该模式下模块为非连接,相对广播者模式的一对多发送广播,观察者可以一对多接收数据。在该模式中,设备可以仅监听和读取空中的广播数据。和中心设备唯一的区别是不能发起连接,只能持续扫描外围设备。
二、演示功能概述
本示例将演示如何使用 Air8101 在观察者模式下工作。
观察者模式(scan)的基本流程(概要描述)
1. 初始化蓝牙框架
bluetooth_device.init()
2. 创建 BLE 对象
local ble_device = bluetooth_device:ble(ble_event_cb)
3. 设置扫描模式
ble_device:scan_create() -- 使用默认参数, addr_mode=0, scan_interval=100, scan_window=100
4. 开始扫描
ble_device:scan_start()
5. 在回调函数中处理扫描事件, 如接收设备信息等
6. 按需停止扫描
ble_device:scan_stop()
三、准备硬件环境
3.1 Air8101 核心板
使用 Air8101 核心板,如下图所示:

淘宝购买链接:Air8101 核心板淘宝购买链接 ;
此核心板的详细使用说明参考:硬件手册和证书 中的 Air8101 核心板使用说明。
3.2 PC 电脑
WINDOWS 系统,其他暂无特别要求;
3.3 数据通信线
USB 数据线(其一端为 Type-C 接口,用于连接 Air8101 核心板)。
四、准备软件环境
4.1 软件环境
-
烧录工具:Luatools 下载调试工具
-
本demo开发测试时使用的固件为Air8101 V1006 版本固件,本demo对固件版本没有什么特殊要求,所以你如果要测试本demo时,可以直接使用最新版本的内核固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本demo时使用的内核固件版本来对比测试;
-
脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8101/demo/ble/scan
-
LuatOS 运行所需要的 lib 文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件。
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 核心板中,将本篇文章中演示使用的项目文件烧录到 Air8101 核心板中。
4.2 API 介绍
ble 库:https://docs.openluat.com/osapi/core/ble/
五、程序结构
ble/
├── ibeacon/
│ ├── main.lua
│ ├── ble_scan.lua
│ |── readme.md
5.1 文件说明
-
main.lua:主程序入口文件。 -
ble_scan.lua:ble_scan.lua 是 Air8101 的蓝牙扫描功能实现模块,主要负责初始化蓝牙框架、配置并执行设备的扫描操作,并通过回调函数处理扫描到的设备信息。
六、代码详解
6.1 main.lua
主程序文件 main.lua 是整个项目的入口点。它负责初始化系统环境。
6.2 ble_scan.lua
6.2.1 全局变量定义
scan_state :扫描状态标志,用于跟踪 BLE 扫描的开启/关闭状态,初始值为 false 表示未扫描
-- 扫描状态
local scan_state = false
6.2.2 处理扫描报告事件 (handle_scan_report)
-
功能:当扫描到 BLE 设备时,处理扫描报告事件。
-
处理内容:记录并输出发现设备的信息,包括 RSSI 值、设备地址和广播数据等,可以根据需求筛选数据。
-
示例演示了如何筛选 ibeacon 广播数据。
-- 处理扫描报告事件
local function handle_scan_report(ble_device, ble_param)
-- 基础设备信息
log.info("ble_scan", "发现设备",
"RSSI:", ble_param.rssi,
"地址:", ble_param.adv_addr:toHex(),
"数据:", ble_param.data:toHex())
-- 解析广播数据
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_scan", "广播数据", "长度:", v.len, "类型:", v.tp, "数据:", v.data:toHex())
-- 以下是演示如何筛选ibeacon广播数据
-- 检查Manufacturer Specific Data (类型0xFF)
if v.tp == 0xFF then
local mfg_data = v.data
-- iBeacon格式检查
if mfg_data:len() >= 25 then
local company_id = mfg_data:byte(1) + mfg_data:byte(2) * 256
local beacon_type = mfg_data:byte(3) -- 0x02
local data_length = mfg_data:byte(4) -- 0x15 (21字节)
if beacon_type == 0x02 and data_length == 0x15 then
log.info("ble_scan", "发现iBeacon设备")
-- 解析iBeacon数据
local uuid = mfg_data:sub(5, 20):toHex()
local major = mfg_data:byte(21) * 256 + mfg_data:byte(22)
local minor = mfg_data:byte(23) * 256 + mfg_data:byte(24)
local tx_power_byte = mfg_data:byte(25)
local tx_power
if tx_power_byte > 127 then
tx_power = tx_power_byte - 256
else
tx_power = tx_power_byte
end
log.info("ble_scan", "iBeacon详情",
"UUID:", uuid,
"Major:", major,
"Minor:", minor,
"TxPower:", tx_power.. " dBm",
"RSSI:", ble_param.rssi .. " dBm")
end
end
end
end
end
end
6.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
-- 事件回调函数
local function ble_callback(ble_device, ble_event, ble_param)
-- 扫描初始化事件
if ble_event == ble.EVENT_SCAN_INIT then
log.info("ble_scan", "scan init")
scan_state = true
-- 扫描报告事件
elseif ble_event == ble.EVENT_SCAN_REPORT then
handle_scan_report(ble_device, ble_param)
-- 停止扫描事件
elseif ble_event == ble.EVENT_SCAN_STOP then
log.info("ble_scan", "scan stop")
scan_state = false
-- 在这里可以添加自己的扫描停止后的处理逻辑
end
end
6.2.4 核心任务函数 (ble_scan_task_func)
这是模块的主要功能实现,采用无限循环结构确保扫描稳定运行:
-
初始化蓝牙核心 :创建 bluetooth_device 实例
-
初始化 BLE 功能 :创建 ble_device 实例并注册回调
-
配置扫描参数 :通过 scan_create()方法设置扫描参数(地址模式、扫描间隔、扫描窗口等)
-
启动扫描 :调用 scan_start()方法开始扫描周围 BLE 设备
-
状态监控 :通过 while scan_state 循环监控扫描状态
-
异常处理 :使用 goto EXCEPTION_PROC 标签统一处理各种初始化失败情况
-
资源清理与重试 :在异常情况下停止扫描并重新初始化,间隔 5 秒后重试
function ble_scan_task_func()
while true do
-- 初始化蓝牙核心
bluetooth_device = bluetooth_device or bluetooth.init()
if not bluetooth_device then
log.error("BLE", "蓝牙初始化失败")
goto EXCEPTION_PROC
end
-- 初始化BLE功能
ble_device = ble_device or bluetooth_device:ble(ble_callback)
if not ble_device then
log.error("BLE", "当前固件不支持完整的BLE")
goto EXCEPTION_PROC
end
-- 创建扫描
if not ble_device:scan_create() then
log.error("BLE", "BLE创建扫描失败")
goto EXCEPTION_PROC
end
log.info("ble_scan", "开始扫描")
if not ble_device:scan_start() then
log.error("ble_scan", "扫描启动失败")
goto EXCEPTION_PROC
end
scan_state = true
-- 等待直到扫描停止
while scan_state do
sys.wait(1000)
end
::EXCEPTION_PROC::
log.info("ble_scan", "检测到扫描异常,准备重新初始化")
-- 停止扫描
if ble_device then
ble_device:scan_stop()
ble_device = nil
end
-- 5秒后跳转到循环体开始位置,重新扫描
sys.wait(5000)
end
end
-- 启动扫描任务
sys.taskInit(ble_scan_task_func)
七、运行结果展示
7.1 完整代码
完整代码请参考:https://gitee.com/openLuat/LuatOS/blob/master/module/Air8101/demo/ble/scan
7.2 结果演示

八、总结
本文介绍了 Air8101 的 BLE 的观察者模式(SCAN),通过示例演示了如何开启蓝牙设备的观察者模式(SCAN),扫描附近的蓝牙设备信息并通过 luatools 日志打印出来。
九、常见问题
9.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
ble_device:scan_create(addr_mode, scan_interval, scan_window)
-- addr_mode:地址模式,在BLE规范中,0表示公共地址模式(public address mode)
-- scan_interval:扫描间隔,单位为0.625ms,最小值为20,最大值为10240
-- scan_window:扫描窗口,单位为0.625ms,最小值为20,最大值为10240