ESP32-Micropython-蓝牙串口

教程经验 · 2022-11-17 · 56 人浏览

毕设还是准备玩esp32加小屏幕了,记录一下开发心得,虽然都做到一半多了,但是为了防止忘记或者是因为习惯性记录,还是准备将新学的给记下来,之前WIFI配网都做好了,那就从蓝牙开始吧...
原文参考链接:https://www.bilibili.com/read/cv15007387

环境配置

硬件:ESP32
编程语言:Micropython
编译器:Thonny

Micropython蓝牙

目标:让esp32模块发出蓝牙信号,手机连接并通过软件发送串口数据,模块接收数据并实现点灯效果

基础测试代码:

from machine import Pin
from time import sleep_ms
import ubluetooth   #导入BLE功能模块

ble = ubluetooth.BLE()  #创建BLE设备
ble.active(True)  #打开BLE

#设置BLE广播数据并开始广播
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x03\x09\x41\x42')

运行后,可以在手机上搜索到一个蓝牙设备名为“AB"

如要修改蓝牙名称,可这样修改:

name = bytes("aabbcc", 'UTF-8')
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x02\x0A\x08' + bytearray((len(name)+1,0x09))+name)

一个中文占用3字节储存,而广播数据最多只有31字节,除去硬件配置外,命名也要限制一定字数

广播数据格式可参考:https://www.bilibili.com/read/cv15007387

注:由于esp32模块功率很小,发射的蓝牙信号较小,手机经常连接不上,可通过在广播数据格式内修改发射功率调整,对应的数据为x02x0Ax08 ,完整代码为:

name = bytes("aabbcc", 'UTF-8')
print("蓝牙开始广播")
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x02\x0A\x08' + bytearray((len(name)+1,0x09))+name)


蓝牙可连接后,需要让其处理各种事件,如蓝牙断开、连接以及收发等,可参考以下代码
详情:https://www.bilibili.com/read/cv15039837

from machine import Pin
from time import sleep_ms
import ubluetooth   #导入BLE功能模块

ble = ubluetooth.BLE()  #创建BLE设备
ble.active(True)  #打开BLE(此时设备将处于就绪态)

#设置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: # 收到新write消息
      print("BLE 收到新消息")

ble.irq(ble_irq) #注册蓝牙中断函数


有了中断函数后,可以更方便监听到蓝牙状态。接下来就是准备连接手机并交互了

蓝牙服务与特性创建,详情:https://www.bilibili.com/read/cv15049793

通过注册蓝牙服务,可以使用安卓APP nRF Connect或者微信小程序 谷雨蓝牙调试 进行数据传输,其中服务id为9011特性一9012为可读可写,9013为可读与通知,从esp32到手机上的消息就是通过9013 Notify这个权限获取信息的。

完整代码:

from machine import Pin
from time import sleep_ms,sleep
import ubluetooth   #导入BLE功能模块
sleep(1)
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广播数据并开始广播(开始广播后设备将处于广播态)
name = bytes("aabbcc", 'UTF-8')
print("蓝牙开始广播")
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x02\x0A\x08' + bytearray((len(name)+1,0x09))+name)

#定义一个函数,用作蓝牙事件中断
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\x02\x0A\x08' + bytearray((len(name)+1,0x09))+name)#再次启动广播

    elif event == 3: # 收到新write消息
      onn_handle, char_handle = data #判断是来自那个特性的消息
      buffer = ble.gatts_read(char_handle) #读取接收到的消息
      print(char_handle, buffer) #打印消息内容
      ble.gatts_notify(0, char_handle, 'Hello') #回复Hello

ble.irq(ble_irq) #注册蓝牙中断函数

这段代码运行后,通过蓝牙调试软件连接模块后,监听9012特性,可对其发送数据,同时在thonny终端内也可以看到发送的数据,并且每发送一条数据,都会收到来自模块的Notify通道的”Hello"回复。

上述为读写数据创建特定的uuid,下面是较为常用的两种实际应用:
注册电池服务

#创建电池服务和特性的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%

注册温湿度服务

#创建环境传感器服务和特性的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)

对于一些常用的功能,蓝牙组织联盟已经为其定义好了UUID,我们在开发产品的时候直接使用即可。
16BitUUID定义文档下载地址:https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf

最后把上面代码结合一起,就可以愉快用蓝牙点灯了!

使用方法:执行代码后,使用谷雨蓝牙连接,并监听9012服务中的read,发送任意数据,收到回复“hello”,发送“led_on”,led打开,收到回复“led on!”;发送“led_off”,led关闭,收到回复“led off!”

from machine import Pin
from time import sleep_ms,sleep
import ubluetooth   #导入BLE功能模块
sleep(1)
ble = ubluetooth.BLE()  #创建BLE设备
ble.active(True)  #打开BLE(此时设备将处于就绪态)
led = Pin(2, Pin.OUT) #led引脚

#创建可读可写可通知的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广播数据并开始广播(开始广播后设备将处于广播态)
name = bytes("aabbcc", 'UTF-8')
print("蓝牙开始广播")
ble.gap_advertise(100, adv_data = b'\x02\x01\x06\x02\x0A\x10' + bytearray((len(name)+1,0x09))+name)

#定义一个函数,用作蓝牙事件中断
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\x02\x0A\x08' + bytearray((len(name)+1,0x09))+name)#再次启动广播

    elif event == 3: # 收到新write消息
      onn_handle, char_handle = data #判断是来自那个特性的消息
      buffer = ble.gatts_read(char_handle) #读取接收到的消息
      print(char_handle, buffer,str(buffer, 'UTF-8')) #打印消息内容
      if str(buffer, 'UTF-8')=="led_on":
          led.on()
          ble.gatts_notify(0, char_handle, 'led on!')
      elif str(buffer, 'UTF-8')=="led_off":
          led.off()
          ble.gatts_notify(0, char_handle, 'led off!')
      else:
          ble.gatts_notify(0, char_handle, 'Hello')#回复Hello

ble.irq(ble_irq) #注册蓝牙中断函数
电子 物联网 esp32 micropython 技术分享
Theme Jasmine by Kent Liao
皖公网安备34122202000364号