大家好,我是ST!
上次给大家分享了如何使用ESP32实现UDP通信,今天跟大家聊聊如何使用ESP32实现蓝牙通信。
目录
一、蓝牙简介
二、miropython有关蓝牙的实现方法
三、我的实验代码
四、手机调试APP
蓝牙是一种无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之间的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的LE蓝牙称为低功耗蓝牙。目前,蓝牙技术已经应用到各个领域,并已经成为接入物联网的主要技术。如今,借助于ESP32平台,MicroPython中也能够使用蓝牙BLE协议进行通信。这对MicroPython平台而言,自然丰富了其生态,增强了其技能,反过来讲,蓝牙BLE能够在MicroPython中得以集成,借助Python语言的易用性,亦将大大降低其入门门槛。
在miropython官网中,提供蓝牙接口模块为bluetooth,下面简单介绍一下本次实验用到的一些方法。
网址:http://docs.micropython.org/en/v1.18/library/bluetooth.html
1)BLE.active([active, ]/)
可选地更改BLE无线电的活动状态,并返回当前状态。在此类上使用任何其他方法之前,必须使无线电处于活动状态。
2)BLE.config(*, param=value, ...)
获取或设置 BLE 接口的配置值。要获取一个值,参数名称应该作为字符串引用,并且一次只查询一个参数。要设置值,请使用关键字语法,一次可以设置一个或多个参数。
3)BLE.irq(handler, /)
为来自 BLE 堆栈的事件注册回调。如下官方给出的事件处理程序(部分截图):
4)BLE.gap_advertise(interval_us, adv_data=Non,*,resp_data=None,...)
以指定的时间间隔(以微秒为单位)开始广播。此间隔将向下舍入到最接近的 625us。要停止广播,请将interval_us设置为None。
adv_data和resp_data可以是实现缓冲协议的任何类型(例如bytes, bytearray, str)。adv_data包含在所有广播中,resp_data发送以回复主动扫描。
注意:如果adv_data(或resp_data)是None,那么传递给先前调用的数据gap_advertise将被重新使用。这允许广播公司仅使用gap_advertise(interval_us). 要清除广告有效载荷,请传递一个空的bytes,即b''。
5)BLE.gatts_register_services(services_definition, /)
用指定的服务配置服务器,替换任何现有的服务。services_definition是一个服务列表,其中每个服务是一个包含一个UUID和一个特征列表的双元素元组。每个特征都是两个或三个元素的元组,包含一个UUID、一个标志值和可选的描述符列表。每个描述符都是一个包含UUID和标志值的双元素元组。这些标志是下面定义的标志的位或组合。这些设置了特征(或描述符)的行为以及安全和隐私需求。返回值是一个元组列表(每个服务一个元素)(每个元素是一个值句柄)。按照定义的顺序,特征和描述符句柄被平展到同一个元组中。
以下官方示例注册了两个服务(Heart Rate, and Nordic UART):
HR_UUID = bluetooth.UUID(0x180D)
HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
HR_SERVICE = (HR_UUID, (HR_CHAR,),)
UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,)
UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,)
UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),)
SERVICES = (HR_SERVICE, UART_SERVICE,)
( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES)
6)BLE.gatts_read(value_handle, /)
读取此句柄(已由gatts_write或远程客户端写入)的本地值。
7)BLE.gatts_notify(conn_handle, value_handle, data=None, /)
向已连接的客户端发送通知请求。
如果data不是None,那么该值将作为通知的一部分发送给客户端。本地值不会被修改。否则,如果data为None,则将发送当前本地值(与gatts_write设置的一样)。注意:无论客户端对该特性的订阅状态如何,通知都将被发送。
8)bluetooth.UUID(value, /)
使用指定的值创建一个UUID实例。取值为:
16位整数,例如0 x2908
128位的UUID字符串,例如:'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
from machine import Pin
from machine import Timer
from time import sleep_ms
import bluetooth
BLE_MSG = ""
class ESP32_BLE():
def __init__(self, name):
self.led = Pin(22, Pin.OUT)
self.timer1 = Timer(0) #创建定时器0对象
self.name = name
self.ble = bluetooth.BLE() #创建蓝牙对象
self.ble.active(True) #启动蓝牙
self.ble.config(gap_name=name) #给蓝牙设置一个名字
self.disconnected()
self.ble.irq(self.ble_irq) #蓝牙中断函数
self.register()
self.advertiser()
def connected(self):
self.led.value(0) #点亮LED指示灯
self.timer1.deinit() #取消定时器
def disconnected(self): #100ms调用一次 mode循环计时 lambda匿名函数
self.timer1.init(period=100, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))
def ble_irq(self, event, data):
global BLE_MSG #替换外部的同名变量
if event == 1: #_IRQ_CENTRAL_CONNECT 手机链接了此设备
self.connected()
elif event == 2: #_IRQ_CENTRAL_DISCONNECT 手机断开此设备
self.advertiser() #向外发送信号,广播
self.disconnected()
elif event == 3: #_IRQ_GATTS_WRITE 手机发送了数据
buffer = self.ble.gatts_read(self.rx)
BLE_MSG = buffer.decode('UTF-8').strip()
def register(self):
service_uuid = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
reader_uuid = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
sender_uuid = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
#创建一个元组
services = (
(
bluetooth.UUID(service_uuid), #服务ID,可以定义多个服务
(
(bluetooth.UUID(sender_uuid), bluetooth.FLAG_NOTIFY), #服务具体类型
(bluetooth.UUID(reader_uuid), bluetooth.FLAG_WRITE), #服务具体类型
)
),
)
((self.tx, self.rx,), ) = self.ble.gatts_register_services(services)
def send(self, data):
self.ble.gatts_notify(0, self.tx, data + '\n')
def advertiser(self):
name = bytes(self.name, 'UTF-8')
adv_data = bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name
self.ble.gap_advertise(100, adv_data) #100us发布一次广告
print(adv_data)
print("\r\n")
def buttons_irq(pin):
led.value(not led.value())
print('LED is ON.' if led.value() else 'LED is OFF')
ble.send('LED is ON.' if led.value() else 'LED is OFF')
if __name__ == "__main__":
ble = ESP32_BLE("ESP32BLE")
but = Pin(0, Pin.IN)
but.irq(trigger=Pin.IRQ_FALLING, handler=buttons_irq)
led = Pin(22, Pin.OUT)
while True:
if BLE_MSG == 'read_LED':
led.value(not led.value())
print(BLE_MSG)
BLE_MSG = ""
print('LED is ON.' if led.value() else 'LED is OFF')
ble.send('LED is ON.' if led.value() else 'LED is OFF')
sleep_ms(100)
程序代码思路:蓝牙在未连接时,指示灯不断闪烁,当蓝牙被连接时,指示灯由闪烁变为常亮。当用户用手机APP发送“read_LED”时,指示灯翻转,并打印出接收到的消息。用户可通过手机APP设置提醒功能。ESP32可通过中断控制指示灯亮灭并提醒手机用户。
IOS用户可下载LightBlue
安卓用户可下载BLE调试宝