大家好,我是ST!
上次給大家分享了如何使用ESP32實(shí)現(xiàn)UDP通信,今天跟大家聊聊如何使用ESP32實(shí)現(xiàn)藍(lán)牙通信。
一、藍(lán)牙簡(jiǎn)介
藍(lán)牙是一種無(wú)線通訊技術(shù),可實(shí)現(xiàn)固定設(shè)備、移動(dòng)設(shè)備之間的數(shù)據(jù)交換。一般將藍(lán)牙3.0之間的BR/EDR藍(lán)牙稱為傳統(tǒng)藍(lán)牙,而將藍(lán)牙4.0規(guī)范下的LE藍(lán)牙稱為低功耗藍(lán)牙。目前,藍(lán)牙技術(shù)已經(jīng)應(yīng)用到各個(gè)領(lǐng)域,并已經(jīng)成為接入物聯(lián)網(wǎng)的主要技術(shù)。如今,借助于ESP32平臺(tái),MicroPython中也能夠使用藍(lán)牙BLE協(xié)議進(jìn)行通信。這對(duì)MicroPython平臺(tái)而言,自然豐富了其生態(tài),增強(qiáng)了其技能,反過(guò)來(lái)講,藍(lán)牙BLE能夠在MicroPython中得以集成,借助Python語(yǔ)言的易用性,亦將大大降低其入門門檻。
二、miropython有關(guān)藍(lán)牙的實(shí)現(xiàn)方法
在miropython官網(wǎng)中,提供藍(lán)牙接口模塊為bluetooth,下面簡(jiǎn)單介紹一下本次實(shí)驗(yàn)用到的一些方法。
網(wǎng)址:http://docs.micropython.org/en/v1.18/library/bluetooth.html
可選地更改BLE無(wú)線電的活動(dòng)狀態(tài),并返回當(dāng)前狀態(tài)。在此類上使用任何其他方法之前,必須使無(wú)線電處于活動(dòng)狀態(tài)。
2)BLE.config(*,?param=value,?...)
獲取或設(shè)置 BLE 接口的配置值。要獲取一個(gè)值,參數(shù)名稱應(yīng)該作為字符串引用,并且一次只查詢一個(gè)參數(shù)。要設(shè)置值,請(qǐng)使用關(guān)鍵字語(yǔ)法,一次可以設(shè)置一個(gè)或多個(gè)參數(shù)。
3)BLE.irq(handler,?/)
為來(lái)自 BLE 堆棧的事件注冊(cè)回調(diào)。如下官方給出的事件處理程序(部分截圖):
4)BLE.gap_advertise(interval_us,?adv_data=Non,*,resp_data=None,...)
以指定的時(shí)間間隔(以微秒為單位)開(kāi)始廣播。此間隔將向下舍入到最接近的 625us。要停止廣播,請(qǐng)將interval_us設(shè)置為None。
adv_data和resp_data可以是實(shí)現(xiàn)緩沖協(xié)議的任何類型(例如bytes,?bytearray,?str)。adv_data包含在所有廣播中,resp_data發(fā)送以回復(fù)主動(dòng)掃描。
注意:如果adv_data(或resp_data)是None,那么傳遞給先前調(diào)用的數(shù)據(jù)gap_advertise將被重新使用。這允許廣播公司僅使用gap_advertise(interval_us).?要清除廣告有效載荷,請(qǐng)傳遞一個(gè)空的bytes,即b''。
5)BLE.gatts_register_services(services_definition,?/)
用指定的服務(wù)配置服務(wù)器,替換任何現(xiàn)有的服務(wù)。services_definition是一個(gè)服務(wù)列表,其中每個(gè)服務(wù)是一個(gè)包含一個(gè)UUID和一個(gè)特征列表的雙元素元組。每個(gè)特征都是兩個(gè)或三個(gè)元素的元組,包含一個(gè)UUID、一個(gè)標(biāo)志值和可選的描述符列表。每個(gè)描述符都是一個(gè)包含UUID和標(biāo)志值的雙元素元組。這些標(biāo)志是下面定義的標(biāo)志的位或組合。這些設(shè)置了特征(或描述符)的行為以及安全和隱私需求。返回值是一個(gè)元組列表(每個(gè)服務(wù)一個(gè)元素)(每個(gè)元素是一個(gè)值句柄)。按照定義的順序,特征和描述符句柄被平展到同一個(gè)元組中。
以下官方示例注冊(cè)了兩個(gè)服務(wù)(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或遠(yuǎn)程客戶端寫(xiě)入)的本地值。
7)BLE.gatts_notify(conn_handle,?value_handle,?data=None,?/)
向已連接的客戶端發(fā)送通知請(qǐng)求。
如果data不是None,那么該值將作為通知的一部分發(fā)送給客戶端。本地值不會(huì)被修改。否則,如果data為None,則將發(fā)送當(dāng)前本地值(與gatts_write設(shè)置的一樣)。注意:無(wú)論客戶端對(duì)該特性的訂閱狀態(tài)如何,通知都將被發(fā)送。
8)bluetooth.UUID(value,?/)
使用指定的值創(chuàng)建一個(gè)UUID實(shí)例。取值為:
16位整數(shù),例如0 x2908
128位的UUID字符串,例如:'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
三、我的實(shí)驗(yàn)代碼
?
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) #創(chuàng)建定時(shí)器0對(duì)象 self.name = name self.ble = bluetooth.BLE() #創(chuàng)建藍(lán)牙對(duì)象 self.ble.active(True) #啟動(dòng)藍(lán)牙 self.ble.config(gap_name=name) #給藍(lán)牙設(shè)置一個(gè)名字 self.disconnected() self.ble.irq(self.ble_irq) #藍(lán)牙中斷函數(shù) self.register() self.advertiser() def connected(self): self.led.value(0) #點(diǎn)亮LED指示燈 self.timer1.deinit() #取消定時(shí)器 def disconnected(self): #100ms調(diào)用一次 mode循環(huán)計(jì)時(shí) lambda匿名函數(shù) 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 手機(jī)鏈接了此設(shè)備 self.connected() elif event == 2: #_IRQ_CENTRAL_DISCONNECT 手機(jī)斷開(kāi)此設(shè)備 self.advertiser() #向外發(fā)送信號(hào),廣播 self.disconnected() elif event == 3: #_IRQ_GATTS_WRITE 手機(jī)發(fā)送了數(shù)據(jù) 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' #創(chuàng)建一個(gè)元組 services = ( ( bluetooth.UUID(service_uuid), #服務(wù)ID,可以定義多個(gè)服務(wù) ( (bluetooth.UUID(sender_uuid), bluetooth.FLAG_NOTIFY), #服務(wù)具體類型 (bluetooth.UUID(reader_uuid), bluetooth.FLAG_WRITE), #服務(wù)具體類型 ) ), ) ((self.tx, self.rx,), ) = self.ble.gatts_register_services(services) def send(self, data): self.ble.gatts_notify(0, self.tx, data + ' ') def advertiser(self): name = bytes(self.name, 'UTF-8') adv_data = bytearray('x02x01x02') + bytearray((len(name) + 1, 0x09)) + name self.ble.gap_advertise(100, adv_data) #100us發(fā)布一次廣告 print(adv_data) print(" ") 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)
?
程序代碼思路:藍(lán)牙在未連接時(shí),指示燈不斷閃爍,當(dāng)藍(lán)牙被連接時(shí),指示燈由閃爍變?yōu)槌A痢.?dāng)用戶用手機(jī)APP發(fā)送“read_LED”時(shí),指示燈翻轉(zhuǎn),并打印出接收到的消息。用戶可通過(guò)手機(jī)APP設(shè)置提醒功能。ESP32可通過(guò)中斷控制指示燈亮滅并提醒手機(jī)用戶。
四、手機(jī)調(diào)試APP
?
安卓用戶可下載BLE調(diào)試寶
?
評(píng)論
查看更多