蓝牙低能耗(BLE)技术详解与实践指南

目录

前言

蓝牙协议栈

1. GAP 协议

主要特点:

应用场景:

2. GATT 协议

主要特点:

应用场景:

总结🙃🙃🙃

1. 蓝牙广播数据格式

1.1. 蓝牙外观查询表

2. 蓝牙状态机

3. 蓝牙事件处理

4. 蓝牙服务和特性

4.1. UUID

4.2. 服务和特性

4.2.1. 服务(Service)

4.2.2. 特性(Characteristic)

4.2.3. 类比到蓝牙中

4.2.4. 实际例子

4.2.5. 代码演示

4.3. 标准蓝牙UUID

4.3.1. 电池电量

4.3.2. 温湿度传感器

结语


前言

蓝牙低能耗(Bluetooth Low Energy,简称BLE)作为现代物联网和智能设备通信的核心技术,以其低功耗、高效率的特点彻底改变了短距离无线通信的格局。本文将从BLE的基础概念出发,深入剖析其协议架构、数据格式和工作原理,并通过丰富的代码示例展示如何在实际项目中应用BLE技术。无论您是刚接触蓝牙开发的初学者,还是希望深入理解BLE内部机制的专业开发者,本文都将为您提供全面的技术指导和实践参考

BLE(蓝牙低能耗,Bluetooth Low Energy)是一种无线通信技术,主要用于短距离的数据传输。它的设计目的在于低功耗和高效率,适合于需要长时间运行而不频繁充电的设备。

参考链接:bluetooth — low-level Bluetooth — MicroPython v1.23.0 documentation

BLE的特点

  1. 低功耗:BLE设备在待机时消耗的电量非常少,这使得它们可以使用小型电池运行很长时间,甚至几年。
  2. 短距离:BLE通常在10米到100米的范围内工作,适合家庭、办公室等环境。
  3. 快速连接:BLE可以快速建立连接,减少了设备之间的响应时间。
  4. 数据传输:适合传输小量数据,比如传感器读取、健康监测数据等。

蓝牙协议栈

GAP(Generic Access Profile)GATT(Generic Attribute Profile)是蓝牙低功耗(BLE)中的两个核心协议。它们分别定义了设备之间的通信方式和访问规则。以下是这两个协议的简要介绍:

1. GAP 协议

GAP是蓝牙低功耗的通用访问配置文件,定义了设备之间如何发现、连接和交换数据的基本规则。GAP是BLE通信的基础,负责管理设备的发现和连接过程。

主要特点:
  • 设备角色:GAP定义了设备在BLE通信中的角色,包括:
    • 广播设备(Advertiser):发送广播包以进行设备发现。
    • 扫描设备(Scanner):监听并响应广播包,发现其他设备。
    • 主设备(Central):发起连接的设备(通常是手机或主控制器)。
    • 从设备(Peripheral):被连接的设备(如传感器、穿戴设备)。
  • 设备发现:GAP定义了设备如何通过广播和扫描发现其他设备。设备可以处于可发现模式或不可发现模式。
  • 连接管理:GAP负责建立、管理和终止连接。它处理连接间隔、超时和其他连接参数。
应用场景:

GAP广泛应用于各种BLE设备之间的发现和连接过程,确保设备能够有效地找到并连接到彼此。

2. GATT 协议

GATT是蓝牙低功耗中的一种通用属性配置文件,主要用于定义如何在BLE设备之间传输数据。它提供了一种标准化的方式来组织和描述设备中的数据。

主要特点:
  • 服务和特性:GATT基于服务和特性构建,服务是一组相关的特性。每个服务和特性都有唯一的UUID标识符。
  • 数据模型:GATT使用层次结构的数据模型,设备通过服务和特性与其他设备进行交互。
  • 数据传输方式:GATT支持读取、写入、通知和指示等操作:
    • 读取(Read):客户端可以请求服务器读取特性值。
    • 写入(Write):客户端可以向服务器写入特性值。
    • 通知(Notify):服务器可以主动向客户端发送特性值的变化。
    • 指示(Indicate):服务器向客户端发送特性值的变化,并等待客户端的确认。
应用场景:

GATT通常用于传感器、健康设备、智能家居设备等场景,如心率监测器、温度传感器等。这些设备通过GATT服务和特性与其他BLE设备(如手机应用)进行数据交换。

总结🙃🙃🙃

  • GAP:负责设备发现和连接管理,定义设备的角色和连接过程。
  • GATT:负责设备之间的数据交换和数据组织,通过服务和特性来定义如何读取、写入和通知数据。

这两个协议相辅相成,构成了蓝牙低功耗通信的基础,使得不同设备能够高效地进行数据交换和管理。

1. 蓝牙广播数据格式

蓝牙广播包的最大长度是37个字节,其中设备地址占用了6个字节,只有31个字节是可用的。这31个可用的字节又按照一定的格式来组织,被分割为n个AD Structure。

每个AD Structure包含3部分内容,分别是:

  1. Length(1字节): 广播数据包的长度
  2. AD Type(1字节): 广播的类型
  3. AD Data(n字节): 数据

下面有一条广播数据,你能把分析一下它所表示的含义吗?

02 01 06 08 09 69 63 68 65 69 6D 61 03 19 C1 03
arr = bytearray([
    0x02, 0x01, 0x06, 
    0x08, 0x09, 0x69, 0x63, 0x68, 0x65, 0x69, 0x6D, 0x61,
    0x03, 0x19, 0xC1, 0x03
])

常用的广播类型如下:

AD TYPE为0x01时,它的含义说明:

我们的设备只支持BLE, 不支持经典蓝牙, 并且它是处在普通可发现模式,

所以0x01对应的值我们填写为:0x0000 0110

https://btprodspecificationrefs.blob.core.windows.net/gatt-specification-supplement/GATT_Specification_Supplement.pdf

发送蓝牙广播数据所使用的api如下:

# 发送广播
bt.gap_advertise(100, adv_data)

其中第1个参数是时间,单位为ms, 范围为20ms-625ms, 如果你设置的时间超过625ms, 其它设备可能就收不到你的广播了

from bluetooth import BLE
import bluetooth

bt = BLE()        #创建蓝牙对象
bt.active(1)#打开蓝牙

SERVER_1_UUID = bluetooth.UUID(0x9011)
CHAR_A_UUID = bluetooth.UUID(0x9012)
CHAR_B_UUID = bluetooth.UUID(0x9013)

#设置特性的读写权限
CHAR_A = ( CHAR_A_UUID, bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
CHAR_B = ( CHAR_B_UUID, bluetooth.FLAG_READ | bluetooth.FLAG_WRITE,)

#把特性A和特性B放入服务1
SERVER_1 = (SERVER_1_UUID, (CHAR_A, CHAR_B),)
#把服务1放入 服务集合 中
SERVICES = (SERVER_1,)
#注册服务到gatts
((char_a, char_b),) = bt.gatts_register_services(SERVICES)

# BLE 广播包构建
def create_adv_data(name):
    # 构建广播包
    # 格式为:长度, 类型, 数据...
    # 其中,类型 0x01 表示"Flags", 0x09 表示"Complete Local Name"
    # Flags 数据通常设置为 0x06 (通用可发现模式和BR/EDR不支持)
    # 更多类型可以在 Bluetooth SIG 的广告数据类型文档中找到
    adv_data = bytearray([0x02, 0x01, 0x06,  # Flags
                          len(name)*3+1, 0x09]) + bytearray(name.encode("utf-8"))

    return adv_data

#设置广播名称 B站:宝安钢铁侠
adv_data = bytearray([0x02, 0x01, 0x06,  # Flags
                      21, 0x09]) + bytearray([0x42, 0xe7, 0xab, 0x99, 0x3a, 0xe5, 0xae, 0x9d, 0xe5, 0xae, 0x89, 0xe9, 0x92, 0xa2, 0xe9, 0x93, 0x81, 0xe4, 0xbe, 0xa0])

#开启广播
bt.gap_advertise(100, adv_data)
        
 
#蓝牙中断复位函数
def ble_irq(event, data):
    if event == 1:#蓝牙已经连接
        print('bluetooth connection')
        pass
    elif event == 2:#蓝牙断开连接
        print('Bluetooth disconnection')
        bt.gap_advertise(100, adv_data)
    elif event == 3:#写入事件
        print('Write event')
        #将data元素拆分为两个数据
        conn_handle, chan_handle = data
        #读取chan_handle的数据
        buffer = bt.gatts_read(chan_handle)
        #输出接收到的数据
        print(buffer)
        if buffer == b'A': #如果数据为单个字符A
            print('fasong B\r\n')
            #向手机通道(conn_handle)发送数据chan_handle 单个字符B
            bt.gatts_notify(1, char_a, b'B')
            
bt.irq(ble_irq)

答案:🙃

02 01 06                    // 0x06 默认值,可发现模式
08 09 69 63 68 65 69 6D 61  // 蓝牙名称为: "icheima"
03 19 C1 03                 // 外观为键盘:3c1

1.1. 蓝牙外观查询表

Key

Value

Description

0x0000

Unknown

None

0x0040

Generic Phone

Generic category

0x0080

Generic Computer

Generic category

0x00C0

Generic Watch

Generic category

0x00C1

Watch: Sports Watch

Watch subtype

0x0100

Generic Clock

Generic category

0x0140

Generic Display

Generic category

0x0180

Generic Remote Control

Generic category

0x01C0

Generic Eye-glasses

Generic category

0x0200

Generic Tag

Generic category

0x0240

Generic Keyring

Generic category

0x0280

Generic Media Player

Generic category

0x02C0

Generic Barcode Scanner

Generic category

0x0300

Generic Thermometer

Generic category

0x0301

Thermometer: Ear

Thermometer subtype

0x0340

Generic Heart rate Sensor

Generic category

0x0341

Heart Rate Sensor: Heart Rate Belt

Heart Rate Sensor subtype

0x0380

Generic Blood Pressure

Generic category

0x0381

Blood Pressure: Arm

Blood Pressure subtype

0x0382

Blood Pressure: Wrist

Blood Pressure subtype

0x03C0

Human Interface Device (HID)

HID Generic

0x03C1

Keyboard

HID subtype

0x03C2

Mouse

HID subtype

0x03C3

Joystick

HID subtype

0x03C4

Gamepad

HID subtype

0x03C5

Digitizer Tablet

HID subtype

0x03C6

Card Reader

HID subtype

0x03C7

Digital Pen

HID subtype

0x03C8

Barcode Scanner

HID subtype

0x0400

Generic Glucose Meter

Generic category

0x0440

Generic: Running Walking Sensor

Generic category

0x0441

Running Walking Sensor: In-Shoe

Running Walking Sensor subtype

0x0442

Running Walking Sensor: On-Shoe

Running Walking Sensor subtype

0x0443

Running Walking Sensor: On-Hip

Running Walking Sensor subtype

0x0480

Generic: Cycling

Generic category

0x0481

Cycling: Cycling Computer

Cycling subtype

0x0482

Cycling: Speed Sensor

Cycling subtype

0x0483

Cycling: Cadence Sensor

Cycling subtype

0x0484

Cycling: Power Sensor

Cycling subtype

0x0485

Cycling: Speed and Cadence Sensor

Cycling subtype

0x0C40

Generic: Pulse Oximeter

Pulse Oximeter Generic Category

0x0C41

Fingertip

Pulse Oximeter subtype

0x0C42

Wrist Worn

Pulse Oximeter subtype

0x0C80

Generic: Weight Scale

Weight Scale Generic Category

0x0CC0

Generic Personal Mobility Device

Personal Mobility Device

0x0CC1

Powered Wheelchair

Personal Mobility Device

0x0CC2

Mobility Scooter

Personal Mobility Device

0x0D00

Generic Continuous Glucose Monitor

Continuous Glucose Monitor

0x0D40

Generic Insulin Pump

Insulin Pump

0x0D41

Insulin Pump, durable pump

Insulin Pump

0x0D44

Insulin Pump, patch pump

Insulin Pump

0x0D48

Insulin Pen

Insulin Pump

0x0D80

Generic Medication Delivery

Medication Delivery

0x1440

Generic: Outdoor Sports Activity

Outdoor Sports Activity Generic Category

0x1441

Location Display Device

Outdoor Sports Activity subtype

0x1442

Location and Navigation Display Device

Outdoor Sports Activity subtype

0x1443

Location Pod

Outdoor Sports Activity subtype

0x1444

Location and Navigation Pod

Outdoor Sports Activity subtype

<Format>16bit</Format>
<Enumerations>
<Enumeration key="0" value="Unknown" description="None"/>
<Enumeration key="64" value="Generic Phone" description="Generic category"/>
<Enumeration key="128" value="Generic Computer" description="Generic category"/>
<Enumeration key="192" value="Generic Watch" description="Generic category"/>
<Enumeration key="193" value="Watch: Sports Watch" description="Watch subtype"/>
<Enumeration key="256" value="Generic Clock" description="Generic category"/>
<Enumeration key="320" value="Generic Display" description="Generic category"/>
<Enumeration key="384" value="Generic Remote Control" description="Generic category"/>
<Enumeration key="448" value="Generic Eye-glasses" description="Generic category"/>
<Enumeration key="512" value="Generic Tag" description="Generic category"/>
<Enumeration key="576" value="Generic Keyring" description="Generic category"/>
<Enumeration key="640" value="Generic Media Player" description="Generic category"/>
<Enumeration key="704" value="Generic Barcode Scanner" description="Generic category"/>
<Enumeration key="768" value="Generic Thermometer" description="Generic category"/>
<Enumeration key="769" value="Thermometer: Ear" description="Thermometer subtype"/>
<Enumeration key="832" value="Generic Heart rate Sensor" description="Generic category"/>
<Enumeration key="833" value="Heart Rate Sensor: Heart Rate Belt" description="Heart Rate Sensor subtype"/>
<!--  Added Blood pressure support on December 09, 2011  -->
<Enumeration key="896" value="Generic Blood Pressure" description="Generic category"/>
<Enumeration key="897" value="Blood Pressure: Arm" description="Blood Pressure subtype"/>
<Enumeration key="898" value="Blood Pressure: Wrist" description="Blood Pressure subtype"/>
<!--  Added HID Related appearance values on January 03, 2012 approved by BARB  -->
<Enumeration key="960" value="Human Interface Device (HID)" description="HID Generic"/>
<Enumeration key="961" value="Keyboard" description="HID subtype"/>
<Enumeration key="962" value="Mouse" description="HID subtype"/>
<Enumeration key="963" value="Joystick" description="HID subtype"/>
<Enumeration key="964" value="Gamepad" description="HID subtype"/>
<Enumeration key="965" value="Digitizer Tablet" description="HID subtype"/>
<Enumeration key="966" value="Card Reader" description="HID subtype"/>
<Enumeration key="967" value="Digital Pen" description="HID subtype"/>
<Enumeration key="968" value="Barcode Scanner" description="HID subtype"/>
<!--  Added Generic Glucose Meter value on May 10, 2012 approved by BARB  -->
<Enumeration key="1024" value="Generic Glucose Meter" description="Generic category"/>
<!--  Added additional appearance values on June 26th, 2012 approved by BARB  -->
<Enumeration key="1088" value="Generic: Running Walking Sensor" description="Generic category"/>
<Enumeration key="1089" value="Running Walking Sensor: In-Shoe" description="Running Walking Sensor subtype"/>
<Enumeration key="1090" value="Running Walking Sensor: On-Shoe" description="Running Walking Sensor subtype"/>
<Enumeration key="1091" value="Running Walking Sensor: On-Hip" description="Running Walking Sensor subtype"/>
<Enumeration key="1152" value="Generic: Cycling" description="Generic category"/>
<Enumeration key="1153" value="Cycling: Cycling Computer" description="Cycling subtype"/>
<Enumeration key="1154" value="Cycling: Speed Sensor" description="Cycling subtype"/>
<Enumeration key="1155" value="Cycling: Cadence Sensor" description="Cycling subtype"/>
<Enumeration key="1156" value="Cycling: Power Sensor" description="Cycling subtype"/>
<Enumeration key="1157" value="Cycling: Speed and Cadence Sensor" description="Cycling subtype"/>
<!--  Added appearance values for Pulse Oximeter on July 30th, 2013 approved by BARB  -->
<Enumeration key="3136" value="Generic: Pulse Oximeter" description="Pulse Oximeter Generic Category"/>
<Enumeration key="3137" value="Fingertip" description="Pulse Oximeter subtype"/>
<Enumeration key="3138" value="Wrist Worn" description="Pulse Oximeter subtype"/>
<!--  Added appearance values for Generic Weight Scale on May 21, 2014 approved by BARB  -->
<Enumeration key="3200" value="Generic: Weight Scale" description="Weight Scale Generic Category"/>
<!--  Added additional appearance values on October 2nd, 2016 approved by BARB  -->
<Enumeration key="3264" value="Generic Personal Mobility Device" description="Personal Mobility Device"/>
<Enumeration key="3265" value="Powered Wheelchair" description="Personal Mobility Device"/>
<Enumeration key="3266" value="Mobility Scooter" description="Personal Mobility Device"/>
<Enumeration key="3328" value="Generic Continuous Glucose Monitor" description="Continuous Glucose Monitor"/>
<!--  Added additional appearance values on February 1st, 2018 approved by BARB  -->
<Enumeration key="3392" value="Generic Insulin Pump" description="Insulin Pump"/>
<Enumeration key="3393" value="Insulin Pump, durable pump" description="Insulin Pump"/>
<Enumeration key="3396" value="Insulin Pump, patch pump" description="Insulin Pump"/>
<Enumeration key="3400" value="Insulin Pen" description="Insulin Pump"/>
<Enumeration key="3456" value="Generic Medication Delivery" description="Medication Delivery"/>
<!--  Added appearance values for L&N on July 30th, 2013 approved by BARB  -->
<Enumeration key="5184" value="Generic: Outdoor Sports Activity" description="Outdoor Sports Activity Generic Category"/>
<Enumeration key="5185" value="Location Display Device" description="Outdoor Sports Activity subtype"/>
<Enumeration key="5186" value="Location and Navigation Display Device" description="Outdoor Sports Activity subtype"/>
<Enumeration key="5187" value="Location Pod" description="Outdoor Sports Activity subtype"/>
<Enumeration key="5188" value="Location and Navigation Pod" description="Outdoor Sports Activity subtype"/>
<!--  Added appearance values for Generic Environmental Sensor on May 21, 2014 approved by BARB 
                <Enumeration key="5696" value="Generic: Environmental Sensor" description="Environmental Sensor Generic Category" /> -->
</Enumerations>

2. 蓝牙状态机

蓝牙链路层的状态机有五种状态,分别是就绪态,广播态,链接态,扫描态,发起链接态,各个状态间的转换路径如下图所示:

以手机连接ESP32模块为例, 手机为主设备, esp32为从设备

  1. 上电之后,手机和esp32就都处于就绪态
  2. esp32开启广播功能,它就处在了广播态
  3. 手机打开蓝牙,扫描周围的设备,它就处在了扫描态
  4. 手机尝试连接esp32设备,手机此时就处在了发起态
  5. 连接成功之后,二者就都处于连接态

3. 蓝牙事件处理

蓝牙设备通常有蓝牙连接成功,断开连接,收到数据等事件。 在micropython中,通过终端程序来处理这些事件。代码如下:

#蓝牙中断复位函数
def ble_irq(event, data):
    if event == 1:#蓝牙已经连接
        print('bluetooth connection')
        pass
    elif event == 2:#蓝牙断开连接
        print('Bluetooth disconnection')
        bt.gap_advertise(100, adv_data)
    elif event == 3:#写入事件
        print('Write event')
            
bt.irq(ble_irq)

上述代码其实就是一个中断函数,当中断事件产生的时候,我们根据事件的编号去处理对应的事件。

  • 当事件1产生的时候,蓝牙处于连接态
  • 当事件2产生的时候,断开了连接,它就进入到了就绪态,要想让它能继续被其它设备连接,则需要切换到广播态
  • 当事件3产生的时候,说明可以进行数据处理

4. 蓝牙服务和特性

蓝牙服务(Service)和特性(Characteristic)是**蓝牙低功耗(BLE)**通信中的核心概念,它们定义了蓝牙设备如何组织和传递数据 . 在开始学习这一节内容之前,我们先来补充一个小知识点UUID

4.1. UUID

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

03B80E5A-EDE8-4B33-A751-6CE34EC4C700
7772E5DB-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

4.2. 服务和特性

在洗脚城,服务员提供多种服务,比如洗脚、按摩、提供饮料等。每项服务都可以细分为多个特定的操作。

4.2.1. 服务(Service)

在这个例子中,洗脚城的每种服务可以看作是一个服务。例如:

  • 洗脚服务(Foot Washing Service)
  • 按摩服务(Massage Service)

每项服务都有其独特的目的和功能,类似于蓝牙中的服务。

4.2.2. 特性(Characteristic)

每个服务下面又包含具体的特性,表示该服务的不同方面或操作。以下是对每项服务的特性细分:

  • 洗脚服务(Foot Washing Service)
    • 特性:洗脚水温(Water Temperature)
      • 描述:服务员可以读取水温,并确保适合客户。
    • 特性:洗脚时间(Washing Duration)
      • 描述:服务员可以记录洗脚的持续时间。
    • 特性:洗脚方式(Washing Method)
      • 描述:服务员可以选择不同的洗脚方式,如浸泡、擦洗等。
  • 按摩服务(Massage Service)
    • 特性:按摩类型(Massage Type)
      • 描述:服务员可以选择不同的按摩类型,如舒缓按摩、深层按摩等。
    • 特性:按摩时长(Massage Duration)
      • 描述:服务员可以设置按摩的时间。

在这个洗脚城的例子中:

  • 洗脚服务、按摩服务就相当于蓝牙服务,它们代表了洗脚城提供的不同功能。
  • 每项服务下的洗脚水温、洗脚时间、按摩类型等特性就相当于蓝牙特性,它们代表了具体的、可操作的数据。
4.2.3. 类比到蓝牙中
  • 服务(Service)是一个功能的集合(如心率监测、血糖监测)。
  • 特性(Characteristic)是具体的数据项,可以进行读、写或通知(如心率值、血糖值)。
4.2.4. 实际例子

结合前面我们所讲的UUID, 我们以黑马洗脚城的例子来进行说明:

洗脚城有两个服务员,分别是0x9520号服务员和0x9521号服务员

0x9520服务员:你跟他说0x2030,就相当于是选定了按摩的类型

0x9521服务员:你跟他说0x1001,他就把水温调到45°

4.2.5. 代码演示
SERVER_1_UUID = bluetooth.UUID(0x9520)
CHAR_A_UUID = bluetooth.UUID(0x2030)
CHAR_B_UUID = bluetooth.UUID(0x2031)

#设置特性的读写权限
CHAR_A = ( CHAR_A_UUID, bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
CHAR_B = ( CHAR_B_UUID, bluetooth.FLAG_READ | bluetooth.FLAG_WRITE,)

#把特性A和特性B放入服务1
SERVER_1 = (SERVER_1_UUID, (CHAR_A, CHAR_B),)
#把服务1放入 服务集合 中
SERVICES = (SERVER_1,)
#注册服务到gatts
((char_a, char_b),) = bt.gatts_register_services(SERVICES)

4.3. 标准蓝牙UUID

对于一些常用的功能,蓝牙组织联盟已经定义号了UUID,我们在开发的时候,直接使用即可。大家都遵循蓝牙协议,这样其他人去解析数据也比较容易

4.3.1. 电池电量

例如电池电量服务的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) #注册服务到gatts

ble.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)
4.3.2. 温湿度传感器

在蓝牙组织联盟发布的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) #注册服务到gatts

ble.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)

结语

通过本文的系统学习,我们不仅掌握了BLE技术的核心概念和工作原理,还实践了从广播数据构建到服务特性注册的完整开发流程。BLE技术以其独特的低功耗优势,正在智能穿戴、医疗设备、家居自动化等领域发挥着越来越重要的作用。希望本文能成为您BLE开发路上的实用指南,期待看到您利用这些知识创造出更多创新的物联网应用。技术的魅力在于分享与实践,愿您在BLE的世界里探索出更多可能!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛慕昭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值