蓝牙
一、简介
蓝牙低功耗(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 下载
五、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.源码和工具
- 724UG 模块使用固件为 LuatOS-Air_V4030_RDA8910_TTS_NOLVGL_FLOAT.pac
- 将固件和脚本烧录到模块中,使用说明参考:Luatools 下载和详细使用 源码和固件已打包,如下所示:
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.源码和工具
- 724UG 模块使用固件为 LuatOS-Air_V4030_RDA8910_TTS_NOLVGL_FLOAT.pac
- 将固件和脚本烧录到模块中,使用说明参考:Luatools 下载和详细使用 源码和固件已打包,如下所示:
4.服务端实现
烧录 demo 后,BLE 即可实现。实现服务端的步骤如下:
- 使用 rtos.on() 函数创建外部消息的处理函数
- 启动 BLE 服务端模式
- 设置广播数据、 GATT 服务、广播参数,启动广播
- 等待连接成功后轮询收到的蓝牙数据,将所有收到的数据拼接起来直至没有数据退出
- 将收到的数据打印出来,并且返回到 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.源码和工具
- 724UG 模块使用固件为 LuatOS-Air_V4030_RDA8910_TTS_NOLVGL_FLOAT.pac
- 将固件和脚本烧录到模块中,使用说明参考:Luatools 下载和详细使用 源码和固件已打包,如下所示:
4.客户端实现
烧录 demo 后,BLE 即可实现。实现客户端的步骤如下:
- 使用 rtos.on() 函数创建外部消息的处理函数
- btcore.open(1) 启动 BLE 客户端模式
- 设置扫描参数,以及要扫描的目标设备名称
- 如果扫描到目标设备,打印设备名称,对端设备 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-软件指南-外设驱动实现-蓝牙
用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;
我们会迅速核实并且修改文档;
同时也会为您累计找错积分,您还可能赢取月度找错奖金!