跳转至

蓝牙

一、简介

蓝牙低功耗(Bluetooth Low Energy,简称 BLE)是一种专为低功耗设备设计的无线通信技术,广泛应用于物联网、智能家居、可穿戴设备等领域。相较于传统蓝牙,BLE 具备更低的功耗和更快的连接速度,但传输数据量较小。它使用广播模式进行设备间的通信,支持定向和非定向广告。通过 BLE,设备可以长时间保持待机状态,并在需要时迅速建立连接,因此非常适合对能耗敏感的应用场景。

二、本教程实现的功能概述

本教程将教你如何使用 LUA 脚本快速上手 BLE 开发,并掌握 BLE 广播,客户端,服务端功能。

本教程实现的功能定义是:

三、硬件环境

3.1 Air 724UG 开发板

724UG 开发板购买链接(https://item.taobao.com/item.htm?id=614125604268)

此开发板的详细使用说明参考:Air724UG 产品手册 中的《EVB_Air724UG_AXX 开发板使用说明》,写这篇文章时最新版本的使用说明为:《EVB_Air724UG_A14 开发板使用说明》;开发板使用过程中遇到任何问题,可以直接参考这份使用说明文档。

3.2 数据通信线

Micro-B USB 数据线

3.3 PC 电脑

Windows7 及以上系统。

注意:电脑有 USB 口,并且可以正常上网!!!

四、准备软件环境

4.1 LuaTools 安装

使用说明参考:Luatools 下载和详细使用

4.2 底层 core 下载

下载底层固件,并解压

链接:https://docs.openluat.com/air724ug/luatos/firmware/

如下图所示,红框的是我们要使用到的

4.3 手机端 nRF connect 下载

nRF connect 软件下载链接

nRF connect 使用教程下载链接

五、ibeacon 基本用法

1.ibeacon 报文结构

首先我们来看看 BLE 广播报文结构体如下,需要注意的是,一个 BLE 广播包必须存在 0x01 类型的广播数据,该广播主要是用于指示当前设备能进行的一些行为。因此 AD Structure 1 必须是 0x01 类型广播。

接下来的 AD Structure 2 就是 ibeacon 的数据包格式。从下图我们即可看出,我们正在要关心和修改的地方只有如下四个。对于一部分人而言,Company ID 甚至也不需要管。

  • Company ID : 设备公司名
  • UUID : 用于唯一标识应用场景
  • Major : 用户自定义的主要值,用于分组或区域标识
  • Minor : 用户自定义的次要值,用于更精细的分组或区域标识

2.API 介绍

btcore.open(mode)

打开蓝牙

参数

参数
类型
释义
取值
mode
number
开启模式
BLE 从模式:mode=0BLE 主模式:mode=1 经典蓝牙:mode=2

返回值

返回值
类型
释义
取值
result
number
返回 BLE 打开的结果
成功:0 失败:-1

例子

local function poweron()
    log.info("bt", "poweron")
    btcore.open(0) --打开蓝牙从模式
    _, result = sys.waitUntil("BT_OPEN", 5000) --等待蓝牙打开成功,时间为 5s
end

btcore.setbeacondata(uuid,major,minor)

设置 beacon 的值

参数
类型
释义
取值
uuid
string
用于唯一标识应用场景
128 位
major
number
用户自定义的主要值,用于分组或区域标识
0~65535
minor
number
用户自定义的次要值,用于更精细的分组或区域标识
0~65535

返回值

返回值
类型
释义
取值
result
number
返回设置 beacon 的结果
成功:0 失败:-1

例子

btcore.setbeacondata("AB8190D5D11E4941ACC442F30510B408",10107,50179) --beacon设置  (uuid,major,minor),默认公司为 Microsof

btcore.setadvdata(data)

设置 BLE 传统广播的广播值。

参数
类型
释义
取值
data
number
BLE 进行传统广播时候的内容
最大 31 字节

返回值

返回值
类型
释义
取值
result
number
返回 BLE 传统广播的结果
成功:0 失败:-1

例子

btcore.setadvdata(string.fromHex("0201061AFF06000215AB8190D5D11E4941ACC442F30510B408277BC403C5")) --通过设置广播包接口设置 beacon, Microsof 公司
btcore.setadvdata(string.fromHex("0201061AFF4C000215AB8190D5D11E4941ACC442F30510B408277BC403C5")) -- 通过设置广播包接口设置 beacon,公司修改为 apple

3.源码和工具

4.BLE 广播实现 ibeacon

烧录 demo 后,BLE 广播实现 ibeacon。

核心代码

local function advertising()

    log.info("bt", "advertising")
    --btcore.setadvparam(0x80,0xa0,0,0,0x07,0,0,"11:22:33:44:55:66") --广播参数设置 (最小广播间隔,最大广播间隔,广播类型,广播本地地址类型,广播channel map,广播过滤策略,定向地址类型,定向地址)
    btcore.setbeacondata("AB8190D5D11E4941ACC442F30510B408",10107,50179) --beacon设置  (uuid,major,minor),默认公司为 Microsof
    -- btcore.setadvdata(string.fromHex("0201061AFF06000215AB8190D5D11E4941ACC442F30510B408277BC403C5")) --通过设置广播包接口设置 beacon, Microsof 公司
    -- btcore.setadvdata(string.fromHex("0201061AFF4C000215AB8190D5D11E4941ACC442F30510B408277BC403C5")) -- 通过设置广播包接口设置 beacon,公司修改为 apple
    btcore.advertising(1)-- 打开广播
end

效果展示。下图中的的是 nRF 中的效果,我们可以看到 UUID 、Major、Minor 即为我们设置的值。

当蓝牙初始化成功后,会打印 [bt] init,并且每秒打印一次 “hello world”表示程序正在运行。

六、服务端基本用法

1.服务端介绍

BLE(蓝牙低能耗)服务端是指提供特定服务和特性的设备,它通过 GATT(通用属性配置文件)架构与客户端(如智能手机或其他 BLE 设备)进行通信。服务端定义了一组特征,每个特征包含一个或多个数据点,并可以设置属性(如读、写、通知等)。常见的应用场景包括健康监测设备、智能家居和工业自动化。BLE 服务端的实现通常涉及初始化 BLE 堆栈、创建服务和特征、设置回调函数以处理客户端请求,并通过广播进行连接。通过这种方式,服务端能够有效地与多个客户端进行数据交互,实现实时监控和控制。

2.API 介绍

btcore.addservice(uuid_s)

添加 BLE 服务

参数

参数
类型
释义
取值
uuid_s
16 bit UUID : number 128 bit UUID : string
服务 uuid
16 bit 数 or 16 个有效长度字符串

返回值

返回值
类型
释义
取值
result
number
返回添加 BLE 服务的结果
成功:0 失败:-1

例子

btcore.addservice(0xfee0) -- 添加 16 bit UUID 服务
btcore.addservice("9ecadc240ee5a9e093f3a3b50100406e") -- 添加 128 bit UUID 服务

btcore.addcharacteristic(uuid_c,type,permission)

添加 BLE 特征

参数

参数
类型
释义
取值
uuid_c
16 bit UUID : number 128 bit UUID : string
特征 uuid
16 bit 数 or 16 个有效长度字符串
type
number
特征 properity
16 bit
permission
number
特征 permission
32 bit

如下为属性 properity 详细介绍


描述
0x01
广播位(Broadcast),如果置位,必须要有服务器特征配置描述符(SCCD)
0x02
置位表示允许读(Read)
0x04
无需响应写入(Write Without Response )
0x08
置位表示允许写(Write)
0x10
通知位(Notify),如果置位,必须要有客户端特征配置描述符(CCCD)
0x20
指示位(Indicate),如果置位,必须要有客户端特征配置描述符(CCCD)
0x40
签名认证写入(Authenticated Signed Writes)
0x80
扩展性质位(Extended Properties)

如下为属性 permission 详细介绍


描述
0x0001
该特性是可读的。即客户端可以通过读取操作获取该特性的值,无安全需求。
0x0002
特性是可写的。客户端可以通过写入操作修改特性的值,无安全需求。
0x0004
在读取该特性之前,客户端必须经过身份认证。认证过程通常包括加密连接或其他形式的身份验证。
0x0008
读取该特性之前,服务端需要对客户端进行授权,通常通过应用层的逻辑实现。
0x0010
客户端必须在加密连接的情况下,才能读取该特性。加密连接通常是通过 BLE 配对过程实现的。
0x0020
特性要求在身份验证过程中使用中间人防护(MITM protection)。这是比普通认证更严格的要求,确保双方是真正的通信双方,而不是被第三方拦截或篡改。
0x0040
要求客户端在写入该特性之前进行身份认证。
0x0080
服务端必须对客户端的写入操作进行授权。在写入特性之前,可能需要用户明确确认或通过应用层授权。
0x0100
客户端必须在加密连接的情况下才能对特性进行写入操作,通常通过 BLE 配对实现。
0x0200
要求写入操作必须经过中间人防护认证,确保通信双方的身份真实且没有第三方干扰。
0x0400
表示该特性只能通过经典蓝牙(BR/EDR)而不是 BLE 来访问。它限制了访问模式,使其不能通过低功耗蓝牙进行操作。

返回值

返回值
类型
释义
取值
result
number
返回添加 BLE 特征的结果
成功:0 失败:-1

例子

btcore.addcharacteristic(0xfee1, 0x08, 0x0002) -- 16 bit UUID
btcore.addcharacteristic("9ecadc240ee5a9e093f3a3b50200406e",0x10,0x0001) -- 128 bit UUID

btcore.adddescriptor(uuid_d,value)

添加描述符

参数

参数
类型
释义
取值
uuid_d
number
特征描述 uuid
0x2902 ~ 0x2911 (Core 5.3)
value
number/string
特征描述属性值。更多信息请参考 core5.3 Vol3 : HOST
Part G: Generic Attribute Profle(GATT)
3.3.3 Characteristic descriptor declarations
根据特征描述 UUID 值来定

返回值

返回值
类型
释义
取值
result
number
返回添加 BLE 特征描述符的结果
成功:0 失败:-1

例子

btcore.adddescriptor(0x2902,0x0001)
btcore.adddescriptor(0x2901,"123456")

btcore.recv(len)

每次读取蓝牙数据的最大长度

参数

参数
类型
释义
取值
len
number
每次读取蓝牙数据的最大长度
1~244

返回值

参数
类型
释义
取值
recvuuid
number
数据来源 uuid
16bit or 128bit
recvdata
number
实际读到的数据内容
0~244 字节
recvlen
number
实际读到的数据长度
0~244

例子

local recvuuid, recvdata, recvlen = btcore.recv(3) -- 每次最大读取 3 字节蓝牙数据
if recvlen == 0 then -- 如果没有读取到数据,直接返回
    break
end
log.info("bt.recv_data recvlen", recvlen)
log.info("bt.recv_data recvdata", recvdata)
uuid = recvuuid -- 数据来源的 UUID
len = len + recvlen -- 实际读到的数据内容长度递增
data = data .. recvdata -- 将实际读到的数据内容进行拼接

btcore.disconnect(handle)

指定要断开的连接

参数

参数
类型
释义
取值
handle
number
连接句柄
如果为单连接直接无需传入值,如果是多连接,传入需要断开的连接句柄

返回值

返回值
类型
释义
取值
result
number
返回 BLE 断开连接的结果
成功:0 失败:-1

例子

btcore.disconnect()
btcore.disconnect(bt_connect.handle)

btcore.send(data,uuid_c,handle)

给指定的 BLE 连接 UUID 特征中写入值

参数

参数
类型
释义
取值
data
number
写入数据内容
1~244
uuid_c
16 bit UUID : number 128 bit UUID : string
要被写入的特征 UUID
16 bit 数 or 16 个有效长度字符串
handle
number
连接句柄
连接句柄

返回值

返回值
类型
释义
取值
result
number
返回 BLE 断开连接的结果
成功:0 失败:-1

例子

btcore.send(data, 0xfee2, bt_connect.handle)-- 将数据发送到 0xfee2 特征中
btcore.send(data, "9ecadc240ee5a9e093f3a3b50200406e", bt_connect.handle)--发送数据(数据 对应特征uuid 连接句柄)

3.源码和工具

4.服务端实现

烧录 demo 后,BLE 即可实现。实现服务端的步骤如下:

  1. 使用 rtos.on() 函数创建外部消息的处理函数
  2. 启动 BLE 服务端模式
  3. 设置广播数据、 GATT 服务、广播参数,启动广播
  4. 等待连接成功后轮询收到的蓝牙数据,将所有收到的数据拼接起来直至没有数据退出
  5. 将收到的数据打印出来,并且返回到 UUID 0xfee2 的特征中进行显示。如果收到的数据为 "close" 那么断开连接

核心代码

--自定义服务
local function service(uuid,struct)
    btcore.addservice(uuid) --添加服务
    for i = 1, #struct do
        btcore.addcharacteristic(struct[i][1],struct[i][2],struct[i][3]) --添加特征
        if(type(struct[i][4]) == "table") then
            for j = 1,#struct[i][4] do
                btcore.adddescriptor(struct[i][4][j][1],struct[i][4][j][2])  --添加描述
            end
        end
    end
end

local function advertising()
    local struct1 = {{0xfee1, 0x08, 0x0002},
       {0xfee2, 0x10,0x0001, {{0x2902,0x0001},{0x2901,"123456"}}}}--{特征uuid,特征属性,特征权限,{特征描述uuid,描述属性}}
    local struct2 = {{"9ecadc240ee5a9e093f3a3b50200406e",0x10,0x0001,{{0x2902,0x0001}}},
                 {"9ecadc240ee5a9e093f3a3b50300406e",0x0c, 0x0002}}

    log.info("bt", "advertising")
    btcore.setname("Luat_Air724UG")-- 设置广播名称
    btcore.setadvdata(string.fromHex("02010604ff000203")) -- 设置 BLE 广播包数
    --btcore.setscanrspdata(string.fromHex("04ff000203")) -- 设置 BLE 扫描响应包数据
    service(0xfee0, struct1) -- 添加 16bit 自定义服务 uuid,该服务服务默认存在
    service("9ecadc240ee5a9e093f3a3b50100406e",struct2) -- 添加服务128bit uuid 自定义服务
    --btcore.addwhitelist("11:22:33:44:55:66",0) -- 增加白名单
    --btcore.setadvparam(0x80,0xa0,0,0,0x07,2,0,"11:22:33:44:55:66") -- 广播参数设置 (最小广播间隔,最大广播间隔,广播类型,广播本地地址类型,广播channel map,广播过滤策略,定向地址类型,定向地址)
    btcore.advertising(1) -- 打开广播
end

local function data_trans()

    advertising() -- 启动广播功能
    _, bt_connect = sys.waitUntil("BT_CONNECT_IND") -- 等待连接成功
    if bt_connect.result ~= 0 then
        return false    
    end
    -- 连接成功
    log.info("bt.connect_handle",bt_connect.handle) -- 连接句柄
    log.info("bt.send", "Hello I'm Luat BLE")
    while true do
        _, bt_recv = sys.waitUntil("BT_DATA_IND") -- 等待接收到数据
        local data = ""
        local len = 0
        local uuid = ""
        while true do
            local recvuuid, recvdata, recvlen = btcore.recv(3) -- 每次最大读取 3 字节蓝牙数据
            if recvlen == 0 then -- 如果没有读取到数据,直接返回
                break
            end
            uuid = recvuuid -- 数据来源的 UUID
            len = len + recvlen -- 实际读到的数据内容长度递增
            data = data .. recvdata -- 将实际读到的数据内容进行拼接
        end
        if len ~= 0 then -- 如果实际读到的数据内容长度不为 0,则打印出数据内容、数据长度和来源 UUID
            log.info("bt.recv_data", data) -- 将读取到的数据打印出来
            log.info("bt.recv_data len", len) -- 将读取到的数据长度打印出来
            log.info("bt.recv_uuid", string.toHex(uuid)) -- 将读取到的数据来源 UUID 以 16 进制形式打印出来
            if data == "close" then -- 如果收到的数据为 "close",则断开连接
                btcore.disconnect() -- 主动断开连接
            end
            btcore.send(data, 0xfee2, bt_connect.handle)-- 将数据发送到 0xfee2 特征中
            --btcore.send(data, "9ecadc240ee5a9e093f3a3b50200406e", bt_connect.handle)--发送数据(数据 对应特征uuid 连接句柄)
        end
    end
end

效果展示

打开 nRF connect 点击扫描能够出现名为 Luat_Air724UG 的设备。

在 nRF connect 中点击 CONNECT 之后,我们可以在 LuaTools 中看到如下打印信息。

并且在 nRF connect 出现如下界面。

按照从左到右的顺序进行操作,目的是让客户端给 Air724UG 发送 0x112233 这个 3 byte 数据。

之后我们在 LuaTools 中可以看到如下图中的打印信息

  • “hello world”是固件中设置的每秒 1s 的打印。
  • bt.recv_data recvlen 表示每次读取了多少字节数据
  • bt.recv_data recvdata 表示每次接收到的数据,因为 0x11 和 0x22 从 ascii 码中可知是特殊字符,0x33 是字符 3,因此打印内容如下。
  • bt.recv_data 是总共接收到的数据内容。
  • bt.recv_data len 表示总共接收到的字节数据长度。
  • bt.recv_uuid 表示对端 UUID 号

同时可以在 nRF connect 中可以看到如下图的信息。0xFEE2 是 btcore.send(data, 0xfee2, bt_connect.handle) 的回包数据。而 0xFEE1 表示你成功发送出来的数据。

当我们在 nRF connect 中输入 close 字符。

此时我们可以在 LuaTools 中看到如下的打印的信息。

并且在 nRF connect 看到断开连接的信息。

七、客户端基本用法

1.客户端介绍

蓝牙低功耗(BLE)客户端是一种在 BLE 通信中用于扫描和连接 BLE 服务器(外设)的设备。客户端可以发现附近的 BLE 设备,建立连接,并与之交换数据。它通常用于需要低功耗、短距离数据传输的应用,如健康监测设备、智能家居传感器或穿戴设备。通过 BLE 客户端,应用程序能够读取或写入服务器上的特性,实现设备间的实时通信和控制。

2.API 介绍

btcore.setscanparam(scanType,scanInterval,scanWindow,filterPolicy,own_addr_type)

设置扫描参数

参数

参数
类型
释义
取值
scanType
number
扫描类型
0 被动扫描
1 主动扫描
scanInterval
number
扫描间隔
范围为 4~16384,
单位 0.625ms,最终时间范围 2.5ms~10.24s
scanWindow
number
扫描窗口
范围为 4~16384,不可大于扫描间隔
单位 0.625ms,最终时间范围 2.5ms~ 10.24s
filterPolicy
number
扫描过滤策略
0:接收所有广播和扫描响应 PDU,除了未定向给本设备的定向广播 PDU(默认)。
1:仅接收来自广播设备地址在白名单中的设备的广播和扫描响应 PDU。未定向给本设备的定向广播 PDU 将被忽略。
2:接收所有广播和扫描响应 PDU,除了发起者的身份地址未定向给本设备的定向广告 PDU。
3:接收所有广播和扫描响应 PDU,除了以下情况:
own_addr_type
number
本地地址类型
0:公共设备地址
1:随机设备地址
2:控制器基于解析列表中的本地 IRK 生成可解析的私有地址。如果解析列表中没有匹配的条目,则使用公共地址
3:控制器基于解析列表中的本地 IRK 生成可解析的私有地址。如果解析列表中没有匹配的条目,则使用 LE_Set_Random_Address 指定的随机地址

返回值

返回值
类型
释义
取值
result
number
返回设置 BLE 扫描参数
成功:0 失败:-1

例子

-- 主动扫描
-- 扫描间隔 : 48 * 0.625ms = 30ms
-- 扫描窗口 : 6 * 0.625ms = 3.75
-- 接收所有广播和扫描响应 PDU,除了未定向给本设备的定向广播 PDU
-- 公共设备地址
btcore.setscanparam(1,48,6,0,0)

btcore.scan(enable)

设置蓝牙扫描开关

参数

参数
类型
释义
取值
enable
number
扫描开关
1 打开扫描
0 关闭扫描

返回值

返回值
类型
释义
取值
result
number
返回打开 BLE 蓝牙扫描开关的结果
成功:0 失败:-1

例子

-- 开启扫描
btcore.scan(1)
-- 关闭扫描
btcore.scan(0)

btcore.connect(addr,addr_type)

建立 BLE 连接

参数

参数
类型
释义
取值
addr_type
number
设备地址类型
sys.waitUntil("BT_SCAN_IND")返回的 addr 成员
addr
number
蓝牙地址
sys.waitUntil("BT_SCAN_IND")返回的 addr_type 成员

返回值

返回值
类型
释义
取值
result
number
返回 BLE 连接的结果
成功:0 失败:-1

例子

_, bt_device = sys.waitUntil("BT_SCAN_IND") -- 等待扫描回复数据
btcore.connect(bt_device.addr,bt_device.addr_type) -- 建立连接

btcore.findservice(handle)

设置 BLE 发现服务

参数

参数
类型
释义
取值
handle
number
连接句柄
sys.waitUntil("BT_CONNECT_IND")返回的 handle 成员
如果是单连接,可以不传入值

返回值

返回值
类型
释义
取值
result
number
返回设置 BLE 发现服务的结果

成功:0 失败:-1

例子

_, bt_connect = sys.waitUntil("BT_CONNECT_IND") --等待连接成功
btcore.findservice() -- 发现所有服务,也可以不传入值,如果是单连接
btcore.findservice(bt_connect.handle) -- 发现所有服务

btcore.findcharacteristic(uuid_s,handle)

发现指定服务 UUID 中的指定特征

参数

参数
类型
释义
取值
uuid_s
16 bit UUID : number 128 bit UUID : string
服务 UUID
16 bit 数 or 16 个有效长度字符串
addr_type
number
连接句柄
sys.waitUntil("BT_CONNECT_IND")返回的 handle 成员
如果是单连接,可以不传入值

返回值

返回值
类型
释义
取值
result
number

返回发现指定服务 UUID 特征的结果
成功:0 失败:-1

例子

_, bt_connect = sys.waitUntil("BT_CONNECT_IND") --等待连接成功
btcore.findcharacteristic(0xfee0,bt_connect.handle) -- 查找 uuid 0xfee0 的服务内所有特征
btcore.findcharacteristic(0xfee0) -- 查找 uuid 0xfee0 的服务内所有特征
btcore.findcharacteristic("9ecadc240ee5a9e093f3a3b50100406e",bt_connect.handle)--服务uuid
btcore.findcharacteristic("9ecadc240ee5a9e093f3a3b50100406e")--服务uuid

btcore.opennotification(uuid_c,handle)

向打开 UUID 的 notify 功能

参数

参数
类型
释义
取值
uuid_c
16 bit UUID : number 128 bit UUID : string
特征 UUID
16 bit 数 or 16 个有效长度字符串
handle
number
连接句柄
sys.waitUntil("BT_CONNECT_IND")返回的 handle 成员
如果是单连接,可以不传入值

返回值

返回值
类型
释义
取值
result
number

返回添加 BLE 服务的结果
成功:0 失败:-1

例子

_, bt_connect = sys.waitUntil("BT_CONNECT_IND") --等待连接成功
btcore.opennotification(0xfee2,bt_connect.handle); -- 打开对应特征 uuid 的 notify 功能
btcore.opennotification(0xfee2); -- 打开对应特征 uuid 的 notify 功能
btcore.opennotification("9ecadc240ee5a9e093f3a3b50200406e",bt_connect.handle); --打开通知,对应特征uuid 
btcore.opennotification("9ecadc240ee5a9e093f3a3b50200406e"); --打开通知,对应特征uuid

3.源码和工具

4.客户端实现

烧录 demo 后,BLE 即可实现。实现客户端的步骤如下:

  1. 使用 rtos.on() 函数创建外部消息的处理函数
  2. btcore.open(1) 启动 BLE 客户端模式
  3. 设置扫描参数,以及要扫描的目标设备名称
  4. 如果扫描到目标设备,打印设备名称,对端设备 MAC 地址,信号强度等信息,并进行连接。

核心代码

local function scan()
    log.info("bt", "scan")
    -- 主动扫描,扫描间隔 48*0.625ms=30ms,扫描窗口 6*0.625ms=3.75ms,接收所有广播包和扫描回应包(除定向广播),公共地址
    btcore.setscanparam(1,48,6,0,0)-- 扫描参数设置(扫描类型,扫描间隔,扫描窗口,扫描过滤策略,本地地址类型)
    btcore.scan(1) -- 开启扫描
    _, result = sys.waitUntil("BT_SCAN_OPEN_CNF", 50000) -- 等待扫描打开成功
    if result ~= 0 then
        return false
    end
    sys.timerStart(
        function()
            sys.publish("BT_SCAN_IND", nil)
        end,
        10000)  
    while true do
        _, bt_device = sys.waitUntil("BT_SCAN_IND") -- 等待扫描回复数据
        if not bt_device then
            -- 超时结束
            btcore.scan(0) --停止扫描
            return false
        else
            log.info("bt", "scan result")
            log.info("bt.scan_name", bt_device.name)  -- 对端蓝牙设备名称
            log.info("bt.rssi", bt_device.rssi)  -- 对端蓝牙设备信号强度
            log.info("bt.addr_type", bt_device.addr_type) -- 对端蓝牙设备地址类型
            log.info("bt.scan_addr", bt_device.addr) -- 对端蓝牙设备地址
            if bt_device.manu_data ~= nil then
                log.info("bt.manu_data", string.toHex(bt_device.manu_data)) -- 如果有厂商数据,那么打印厂商数据
            end
            log.info("bt.raw_len", bt_device.raw_len) -- 扫描到的原始广播包数据长度
            if bt_device.raw_data ~= nil then
                log.info("bt.raw_data", string.toHex(bt_device.raw_data)) -- 广播包原始数据
            end

            --蓝牙连接   根据设备蓝牙广播数据协议解析广播原始数据(bt_device.raw_data)
            if (bt_device.name == "Luat_Air724UG") then   -- 如果扫描到的蓝牙设备名称为"Luat_Air724UG"则连接
                name = bt_device.name
                addr_type = bt_device.addr_type
                addr = bt_device.addr
                manu_data = bt_device.manu_data
                adv_data = bt_device.raw_data -- 广播包数据 根据蓝牙广播包协议解析

                scanrsp_data = bt_device.raw_data -- 响应包数据 根据蓝牙广播包协议解析
                btcore.scan(0)  -- 停止扫描
                btcore.connect(bt_device.addr,bt_device.addr_type) -- 建立连接
                log.info("bt.connect_name", name)
                log.info("bt.connect_addr_type", addr_type)
                log.info("bt.connect_addr", addr)
                if manu_data ~= nil then
                    log.info("bt.connect_manu_data", manu_data)
                end
                if adv_data ~= nil then
                    log.info("bt.connect_adv_data", adv_data)
                end
                if scanrsp_data ~= nil then
                    log.info("bt.connect_scanrsp_data", scanrsp_data)
                end
                return true
            end

        end
    end
    return true
end

local function data_trans()

    _, bt_connect = sys.waitUntil("BT_CONNECT_IND") --等待连接成功
    if bt_connect.result ~= 0 then
        return false
    end
    -- 连接成功
    log.info("bt.connect_handle", bt_connect.handle) -- 蓝牙连接句柄
    log.info("bt", "find all service uuid")
    btcore.findservice() -- 发现所有服务
    _, result = sys.waitUntil("BT_FIND_SERVICE_IND") -- 等待发现服务 uuid 完成
    if not result then
        return false
    end

    btcore.findcharacteristic(0xfee0) -- 查找 uuid 0xfee0 的服务内所有特征
    _, result = sys.waitUntil("BT_FIND_CHARACTERISTIC_IND") -- 等待发现服务包含的特征成功
    if not result then
        return false
    end
    btcore.opennotification(0xfee2); -- 打开对应特征 uuid 的 notify 功能

    --btcore.findcharacteristic("9ecadc240ee5a9e093f3a3b50100406e")--服务uuid
    --_, result = sys.waitUntil("BT_FIND_CHARACTERISTIC_IND") --等待发现服务包含的特征成功
    --if not result then
    --    return false
    --end
    --btcore.opennotification("9ecadc240ee5a9e093f3a3b50200406e"); --打开通知 对应特征uuid  

    log.info("bt.send", "Hello I'm Luat BLE")
    sys.wait(1000)
    while true do
        local data = "123456"
        -- 向特征 uuid 0xfee1 发送数据
        btcore.send(data,0xfee1, bt_connect.handle) -- 发送数据(数据 对应特征uuid 连接句柄)
        --btcore.send(bt_recv.data,"9ecadc240ee5a9e093f3a3b50300406e",bt_connect.handle)
        _, bt_recv = sys.waitUntil("BT_DATA_IND") --等待接收到数据
        local data = ""
        local len = 0
        local uuid = ""
        while true do
            local recvuuid, recvdata, recvlen = btcore.recv(3)
            if recvlen == 0 then
                break
            end
            uuid = recvuuid
            len = len + recvlen
            data = data .. recvdata
        end
        if len ~= 0 then
        log.info("bt.recv_data", data)
        log.info("bt.recv_data len", len)
        log.info("bt.recv_uuid", uuid)
        end
    end
end

服务端效果展示。这里需要注意,不同手机的蓝牙设置规则可能不一样,我当前使用的手机是 OPPO K11 进行的演示。

首先我们使用服务端的例程,使用手机连接开发板。参考下图点击右上角三个点

然后根据右图点击 clone device's services。

我们点击图中左上角的设置选项。

参考下间这张图选择 configure GATT server。

最后我们可以看到把对应的服务信息给复制下来了。

回到主界面,点击 ADVERTISER 中的加号。

之后参考如下两张图进行设置。

最后参考下图修改设备名称。

打开广播功能。

开发板上电,之后就会扫描附近的设备并打印扫描到的设备信息。如果找到的指定的设备名后,将会出现如下的打印内容。

八、总结

在本教程中,我们详细介绍了 iBeacon 的工作原理及其在 BLE 应用中的实现。通过讲解客户端和服务端的交互方式,读者可以掌握如何使用 BLE 广播和扫描机制来实现设备间的通信。同时,教程涵盖了 iBeacon 配置、数据格式以及客户端的监听和解析过程。无论是使用 BLE 技术进行位置追踪还是设备交互,本教程提供了全面的实践指导,帮助开发者快速入门并深入理解 BLE 应用的核心技术。

九、给读者的话

本篇文章由风正豪开发;

本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题;

请登录合宙技术交流论坛,点击文档找错赢奖金-Air724UG-LuatOS-软件指南-外设驱动实现-蓝牙

用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;

我们会迅速核实并且修改文档;

同时也会为您累计找错积分,您还可能赢取月度找错奖金!