【低功耗蓝牙】③ 蓝牙服务和特性的创建

编程入门 行业动态 更新时间:2024-10-23 08:31:45

【低功耗<a href=https://www.elefans.com/category/jswz/34/1768306.html style=蓝牙】③ 蓝牙服务和特性的创建"/>

【低功耗蓝牙】③ 蓝牙服务和特性的创建

摘要

本文章主要基于ESP32的MicroPython平台,讲解了蓝牙服务和特性的建立,以及基于特性的数据交互,实现手机于蓝牙模块相互通信。主要涉及的概念有 UUIDGATT服务特性

UUID

UUIDUniversity Unique Identifie 的缩写,翻译成中文为 通用唯一标识符。是蓝牙组织联盟定义的用于区分蓝牙服务和特性的的标识符,总长度为128 Bit。
例如:

03B80E5A-EDE8-4B33-A751-6CE34EC4C7007772E5DB-3868-4112-A1A9-F2669D106BF3

128Bit的UUID占用16个字节,在编程和传输的时候都很不方便,所以蓝牙联盟定义了一个UUID的基地址,允许在此基础上使用16Bit的UUID。

UUID基地址: 0x0000xxxx-0000-1000-8000-00805F9B34FB

比如16Bit的UUID : 0x2A37 转换成128Bit的UUID为:

0x00002A37-0000-1000-8000-00805F9B34FB

服务和特性

低功耗蓝牙设备之间通信,都是基于服务和特性。

一个蓝牙设备中可以包含若干个服务
一个服务中可以包含若干个特性
每一个服务或者特性都要有一个UUID

蓝牙的数据交互都是基于一个个特性进行的,数据交互的方式有五种,分别是ReadWriteWrite WithOutResponsNotifyIndication

服务和特性特创建

蓝牙设备要在进入广播态之前创建服务和特性,在MicroPython中大概分为四步:
① 创建要使用的UUID;
② 使用UUID创建特性并设置特性的读写权限;
③ 将创建好的特性添加到服务集合中;
④ 将服务集合注册到协议栈中。

比如我们要创建一个UUID为9011的服务,该服务里面包含两个特性;
这两个特性的UUID分别是9012和9013;
9012的特性拥有Read和Write的权限,9013的特性拥有Read和Notify的权限。

可以使用如下代码实现:

from machine import Pin
from time import sleep_ms
import ubluetooth        #导入BLE功能模块ble = ubluetooth.BLE()   #创建BLE设备
ble.active(True)         #打开BLE#创建要使用的UUID
SERVER_1_UUID = ubluetooth.UUID(0x9011)
CHAR_A_UUID = ubluetooth.UUID(0x9012)
CHAR_B_UUID = ubluetooth.UUID(0x9013)#创建特性并设置特性的读写权限
CHAR_A = (CHAR_A_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, )
CHAR_B = (CHAR_B_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, )SERVER_1 = (SERVER_1_UUID, (CHAR_A , CHAR_B, ) , ) #把特性A和特性B放入服务1
SERVICES = (SERVER_1, ) #把服务1放入服务集和中
((char_a, char_b), ) = ble.gatts_register_services(SERVICES) #注册服务到gatts#设置BLE广播数据并开始广播
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')

运行代码,通过微信小程序谷雨蓝牙连接设备后,可以参看到蓝牙设备上的服务可特性列表如下:

当然,一个蓝牙设备里面也可以创建多个服务,下面给出了实现两个服务的参考代码:

from machine import Pin
from time import sleep_ms
import ubluetooth         #导入BLE功能模块ble = ubluetooth.BLE()    #创建BLE设备
ble.active(True)          #打开BLE#创建要使用的UUID
SERVER_1_UUID = ubluetooth.UUID(0x9011)
CHAR_A_UUID = ubluetooth.UUID(0x9012)
CHAR_B_UUID = ubluetooth.UUID(0x9013)SERVER_2_UUID = ubluetooth.UUID(0x9021)
CHAR_C_UUID = ubluetooth.UUID(0x9022)
CHAR_D_UUID = ubluetooth.UUID(0x9023)#创建特性并设置特性的读写权限
CHAR_A = (CHAR_A_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, )
CHAR_B = (CHAR_B_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, )
SERVER_1 = (SERVER_1_UUID, (CHAR_A , CHAR_B, ) , ) #把特性A和特性B放入服务1CHAR_C = (CHAR_C_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE, )
CHAR_D = (CHAR_D_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, )
SERVER_2 = (SERVER_2_UUID, (CHAR_C , CHAR_D, ) , ) #把特性A和特性B放入服务SERVICES = (SERVER_1, SERVER_2 , ) #把服务1和服务2放入服务集和中
((char_a, char_b), (char_c, char_d), ) = ble.gatts_register_services(SERVICES) #注册服务到gatts#设置BLE广播数据并开始广播
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')

读者可直接运行上述代码,使用谷雨蓝牙小程序观察一下服务和特性的结构与期望是否一致。

数据交互

低功耗蓝牙之间的数据交互都是基于特性,以手机连接蓝牙模块为例,手机读取蓝牙模块的数据,使用的是Read方法,手机发送数据给蓝牙模块使用的是Write方法,蓝牙模块发送数据到手机,一般使用的是Notify方法,而且手机端还要打开Notify监听

通信示例代码如下:


from machine import Pin
from time import sleep_ms
import ubluetooth        #导入BLE功能模块ble = ubluetooth.BLE()   #创建BLE设备
ble.active(True)         #打开BLE#创建要使用的UUID
SERVER_1_UUID = ubluetooth.UUID(0x9011)
CHAR_A_UUID = ubluetooth.UUID(0x9012)
CHAR_B_UUID = ubluetooth.UUID(0x9013)#创建特性并设置特性的读写权限
CHAR_A = (CHAR_A_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_WRITE | ubluetooth.FLAG_NOTIFY, )
CHAR_B = (CHAR_B_UUID, ubluetooth.FLAG_READ | ubluetooth.FLAG_NOTIFY, )SERVER_1 = (SERVER_1_UUID, (CHAR_A , CHAR_B, ) , ) #把特性A和特性B放入服务1
SERVICES = (SERVER_1, ) #把服务1放入服务集和中
((char_a, char_b), ) = ble.gatts_register_services(SERVICES) #注册服务到gatts#设置BLE广播数据并开始广播
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')def ble_irq(event, data): # 蓝牙中断函数if event == 1: #蓝牙已连接print("BLE 连接成功")elif event == 2: #蓝牙断开连接print("BLE 断开连接")ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')elif event == 3: #收到数据onn_handle, char_handle = data #判断是来自那个特性的消息buffer = ble.gatts_read(char_handle) #读取接收到的消息print(char_handle, buffer) #打印消息内容ble.gatts_notify(0, char_handle, 'Hello') #回复Helloble.irq(ble_irq)

在上述代码中,我们创建了一个UUID为9011的服务,并在该服务中创建了一个UUID为9012的特性,该特性的操作权限是 ReadWriteNotify。在手机端打开谷雨蓝牙小程序,连接设备,选择UUID为9012的特性,进入常规试图,点击监听,随便写入一下数据,可以看到,设备回复给手机Hello。

低功耗蓝牙设备之间通信常用的方式是ReadWrite Notify ,必须在创建特性时赋予对应的权限,才能在通信中使用。如果某个特性在创建的时候,没有开启 Write 权限,则手机将无法通过该特性发送数据到设备。

蓝牙联盟已定义的16Bit UUID

对于一些常用的功能,蓝牙组织联盟已经为其定义好了UUID,我们在开发产品的时候直接使用即可。

16 Bit UUID定义文档下载地址:.pdf

电池电量指示

在上述文档(16BitUUID)中定义了电池电量服务的UUID是0x180F,电池电量特性的UUID是0x2A19,我们可以使用这两个UUID实现电池电量指示的功能,代码如下:

from machine import Pin
from time import sleep_ms
import ubluetooth        #导入BLE功能模块ble = ubluetooth.BLE()   #创建BLE设备
ble.active(True)         #打开BLE#创建电池服务和特性的UUID
BATTERY_SERVER_UUID = ubluetooth.UUID(0x180F)
BATTERY_CHAR_UUID = ubluetooth.UUID(0x2A19)#创建特性并设置特性的读写权限
BATTERY_CHAR = (BATTERY_CHAR_UUID, ubluetooth.FLAG_READ , )BATTERY_SERVER = (BATTERY_SERVER_UUID, (BATTERY_CHAR, ) , ) #把电量特性放入电池服务
SERVICES = (BATTERY_SERVER, ) #把电池服务服务放入服务集和中((battery_char,), ) = ble.gatts_register_services(SERVICES) #注册服务到gattsble.gatts_write(battery_char, b'\x50') #设置电池电量为80%#设置BLE广播数据并开始广播
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')def ble_irq(event, data): # 蓝牙中断函数if event == 1: #蓝牙已连接print("BLE 连接成功")elif event == 2: #蓝牙断开连接print("BLE 断开连接")ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')elif event == 3: #收到数据print("收到新消息")ble.irq(ble_irq)

电池电量用一个字节来表示,其单位是电量百分比,16进制数0x50转换成十进制为80,所以运行上述代码,连接该设备后,可以看到该设备的电量显示,如下图所示:

通过手机微信小程序“谷雨蓝牙”连接该设备后,可以看到如下服务列表。

温湿度传感器

在蓝牙组织联盟发布的16Bit UUID 文档中,定义了环境传感器服务的UUID是 0x181A,温度特性的UUID是0x2A6E,湿度特性的UUID是0x2A6F。使用如下代码可实现简单温湿度传感器功能:

from machine import Pin
from time import sleep_ms
import ubluetooth        #导入BLE功能模块ble = ubluetooth.BLE()   #创建BLE设备
ble.active(True)         #打开BLE#创建环境传感器服务和特性的UUID
ENV_SERVER_UUID = ubluetooth.UUID(0x181A) #环境传感器服务
TEM_CHAR_UUID = ubluetooth.UUID(0x2A6E)   #温度特性
HUM_CHAR_UUID = ubluetooth.UUID(0x2A6F)   #湿度特性#创建特性并设置特性的读写权限
TEM_CHAR = (TEM_CHAR_UUID, ubluetooth.FLAG_READ , )
HUM_CHAR = (HUM_CHAR_UUID, ubluetooth.FLAG_READ , )ENV_SERVER = (ENV_SERVER_UUID, (TEM_CHAR, HUM_CHAR, ) , ) #把温湿度特性放入环境服务
SERVICES = (ENV_SERVER, ) #把环境服务放入服务集和中((tem_char, hum_char, ), ) = ble.gatts_register_services(SERVICES) #注册服务到gattsble.gatts_write(tem_char, b'\x06\x08') #设置温度为20.54度(0x0806 = 2054)
ble.gatts_write(hum_char, b'\x09\x07') #设置湿度为18.01%(0x0709 = 1801)#设置BLE广播数据并开始广播
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')def ble_irq(event, data): # 蓝牙中断函数if event == 1: #蓝牙已连接print("BLE 连接成功")elif event == 2: #蓝牙断开连接print("BLE 断开连接")ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')elif event == 3: #收到数据print("收到新消息")ble.irq(ble_irq)

运行上述代码,使用手机APP nRF Connect 连接设备后,可以读取到温湿度数据。温湿度数据使用两个字节来表示(低字节在前,高字节在后),温度的单位是0.01度,湿度的单位是0.01%

蓝牙组织联盟定义了很多常用的UUID,上面的示例只选取了其中的两个用作演示,有兴趣的同学可以自行尝试下别的UUID。

上一章节:【低功耗蓝牙】② 蓝牙状态切换和事件处理

下一章节:【低功耗蓝牙】④ 蓝牙MIDI协议

作者:我是鹏老师

更多推荐

【低功耗蓝牙】③ 蓝牙服务和特性的创建

本文发布于:2023-06-27 08:21:55,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/908712.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:蓝牙   低功耗   特性

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!