0 前言 自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。' q+ x) ^" E2 h( A# u" Z 1 最小闭环回路& k$ A. c+ P, t+ y% T 最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。 1 ; l; N( ` h I( e ) p9 e0 {+ P$ N4 [ ; Y( u: A5 N2 U" w9 r& v( K # g: V$ d1 X" R) q * `% [1 G2 J; E+ b 2 系统软件环境 在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。2 l2 |6 `% Q: D9 s2 F. H 笔记本使用上位机是自己编写的python代码。 2 我们将开发板当作外围设备。将笔记本作为中心设备。5 ~* _2 o+ y+ v : v* [7 q# E$ x) b1 M! w# F& T( L 3 连接实验 3.1 发现设备 下载好单片机程序,给单片机上电。& p; r, _" Q! t& m; R7 b& @+ } 在笔记本设置中打开蓝牙,并点击添加蓝牙。 3 可以看到我们的设备HRSTM。 接下来使用我编写好代码:0 q8 W2 ]- L5 f+ I7 O import bleak.backends.dotnet.discovery as Discovery; e$ b) B; y q import asyncio! s& o' w) K& v async def run(): devices = await Discovery.discover()6 m4 [* U/ r8 E8 j8 f9 X for d in devices: print(d)2 i" w% Q! y- e. R/ b6 [1 R5 L8 F( \ loop = asyncio.get_event_loop()5 e4 y, r/ D! _7 b loop.run_until_complete(run()) 在输出窗口可以看到可以被发现了的蓝牙: B8:7C:6F:47:81:BF: MiKettle G" a8 V" V" ]8 r 6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec')$ f$ h0 l5 W# o$ O% Z! }/ p 80:E1:26:00:68:7C: HRSTM ' D8 H7 p, y' W J# h5 N 我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。 8 B+ e3 t1 B% c- c7 y2 i 3.2 连接和发现服务% z0 ?2 K. Q: y 接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务: async with BleakClient(address, loop=loop) as client:1 @1 p B7 F+ V. q4 B3 U x = await client.is_connected()# t, w+ O/ f3 Q8 {1 o. z log.info("Connected: {0}".format(x))( R4 c! u! |8 t3 t" N log.info("[Service] {0}: {1}".format(service.uuid, service.description)) for char in service.characteristics: if "read" in char.properties:4 R! e. t. L! A4 M, m5 d try:& R$ ~# f! A/ ` value = bytes(await client.read_gatt_char(char.uuid)) S+ M5 L3 s) f except Exception as e: value = str(e).encode()8 L' e8 e$ Z& t- A, k F Q0 O- s4 p5 T else: value = None, ~; K' D. g+ ] e+ \7 S log.info( "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(! L0 n' u- K7 P* O3 r$ ] char.uuid, ",".join(char.properties), char.description, value )4 p* b! |2 F# ~9 W3 u )# v+ m- L9 d7 ~: { for descriptor in char.descriptors: value = await client.read_gatt_descriptor(descriptor.handle). \* M# P' B9 B( i, H log.info( "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(. M/ A! k5 X2 a2 L2 l: l6 |6 z descriptor.uuid, descriptor.handle, bytes(value)6 ]% Q% k% N- h/ [9 d; @ ) ) ' a$ I" A8 A. M; U' d 输出的结果: Connected: True7 i1 g b4 |. e+ t# ?8 l [Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile: _" z7 g6 }5 ?$ W [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None8 B& a% N5 v7 h: g$ |: r M1 R1 e [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00') F: b* @ X2 h: w3 w7 J# U [Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB' W- B! J$ {0 Y [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'+ D- _% Z. {* x& H* J4 @ [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff' [Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information" b! r- |* T' [. A+ n9 d' m [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00' [Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate" K6 ^0 E( f6 ^0 Y [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None5 F3 v: G. D' ~( M8 _ [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'" n' k7 X5 Z# t+ l' U [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'; x& z( `! M$ o0 R( M" E0 m8 E [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None# ~5 f0 m: r! n! m+ J g& A * Y+ M+ q) A/ H. m5 K9 z 观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:7 ~- Q7 h1 C% f- B /* UUIDs for Heart Rate Service */ #define HEART_RATE_SERVICE_UUID (0x180D) #define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID (0x2902)% z( K' I; m5 ] #define HEART_RATE_MEASURMENT_UUID (0x2A37) #define SENSOR_LOCATION_UUID (0x2A38) #define CONTROL_POINT_UUID (0x2A39)1 E# n% K1 o3 l9 t( ^/ s 3.3 通知和获取数据; S: Q8 N( Z3 W2 | 通过STM的蓝牙软件,发现软件是有数据传递的。 4 3 U% K6 x) V" f) {4 z8 t; U 其采用的方式是通知的方式,我是用了一下程序:9 u& b2 n+ C/ R' V$ [8 c9 j def notification_handler(sender, data):, p, r+ m7 a. Q; \5 N- a # strs=data.hex' V: G" X" q4 L! d: T2 M q print(f"{sender}: {data}"): q8 c- a/ o* ^( e8 x! x+ L byarray = bytearray(data)2 B- Q& U" x2 u5 f: K print(byarray.hex()) async def run(address, loop, debug=False): async with BleakClient(address, loop=loop) as client: x = await client.is_connected() await client.start_notify(CHARACTERISTIC_UUID, notification_handler)4 C$ \; { ?" S _3 m3 Y await asyncio.sleep(5.0, loop=loop)# E0 [7 x; q: f% Q$ i6 d4 l v await client.stop_notify(CHARACTERISTIC_UUID) if __name__ == "__main__":* s/ q: ^2 ~7 t; F# F if __name__ == "__main__":. M: X2 o% [5 \! t7 N/ F address = ('80:E1:26:00:68:7C') #你的地址 loop = asyncio.get_event_loop()+ x" v& C. U6 T loop.run_until_complete(run(address, loop, True)) * ?, e5 M4 f) A& r3 L 返回了一下数据:# I9 X ]; X/ y, h! b% S5 O 00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04') 1f370014000004 00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04'), a6 T0 T0 z6 ~3 w' D9 y& g 1f36001e000004 00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')' F5 t1 V+ D" {! A& s6 \- O! D 1f340028000004 其中00002a37是HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。0 @: Y& N8 Q8 r2 R/ t( ^8 f HRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10; / e( q1 C" G; i' t( f, _0 _6 c+ h9 A( v 4 小结# g- j7 J, h, s5 l 以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?, P/ q+ s/ K o4 m 我相信,在后面一步一步的代码解析,就会解释这些现象。4 _2 l9 \4 o% S9 t ( `. h; D" w6 i% ~ & [/ Q& @9 F# K/ u6 F 9 A( J+ }2 G& E$ e |
4月25日培训|基于ST 双核多协议STM32WB55的Matter方案开发
实战经验 | 关于STM32WB OTA 速率提升引发的讨论
基于STM32WB55的配置串口打印Debug经验分享
基于创建STM32WBA BLE_Custom工程经验分享
来看直播了,就在明天 | STM32 Matter 解决方案,轻松实现智能家居无缝连接
基于STM32WB55开发之套件概述(1)
基于STM32WB55开发之监测STM32WB连接状态(1)
基于STM32WB55开发之修改蓝牙地址(2)
STM32WB基于Custom Template实现客户定制BLE私有协议
如何基于STM32WB一次性烧写FUS+STACK+APP