|
0 前言 自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。 0 s0 w! }% |9 l 1 最小闭环回路' j# H" d% c+ o2 ?6 n2 g 最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。( J0 z' r1 z, F5 \ 1
* s& O0 [( W5 Z+ a/ y1 b; W* _ Z 2 系统软件环境 在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。/ j) P) ]/ E: ^9 @+ s 笔记本使用上位机是自己编写的python代码。( J! U. B4 ?$ T1 j7 M0 U8 } 2
我们将开发板当作外围设备。将笔记本作为中心设备。 ]# Q$ w/ E: Q8 j1 l; l 3 连接实验 3.1 发现设备 下载好单片机程序,给单片机上电。 在笔记本设置中打开蓝牙,并点击添加蓝牙。 3
可以看到我们的设备HRSTM。 接下来使用我编写好代码: import bleak.backends.dotnet.discovery as Discovery import asyncio% U! X9 S' g; v e5 Z; o$ G6 y async def run(): devices = await Discovery.discover()( O( q. O# v& e, y$ _+ \3 a+ f for d in devices: print(d) Z2 F/ |+ j- ^' r/ q1 A) i' W loop = asyncio.get_event_loop(), C5 D( A1 {3 Q: {# C0 {2 Y3 {+ L loop.run_until_complete(run())* ~; f* E' z- ]2 N X+ e % L/ i3 J, e% T8 A5 B$ n, A5 | 在输出窗口可以看到可以被发现了的蓝牙: B8:7C:6F:47:81:BF: MiKettle/ x0 a0 W. ~. b K 6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec') 80:E1:26:00:68:7C: HRSTM) |1 w6 d" _4 p, h2 r 1 m; a* X+ K: s/ [( J3 g) _! o 我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。 s- M! X* z6 O L 3.2 连接和发现服务 接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务: async with BleakClient(address, loop=loop) as client: x = await client.is_connected() log.info("Connected: {0}".format(x)) log.info("[Service] {0}: {1}".format(service.uuid, service.description))& N- B9 U& r, P% I; P4 R for char in service.characteristics: if "read" in char.properties: try:1 Z7 Q, H( R% y2 B* O- e value = bytes(await client.read_gatt_char(char.uuid))$ ]2 s: N5 `/ r; R; ]+ Q( t Z except Exception as e: value = str(e).encode() else:3 L& i: ?) D) e+ u& F: t, c, H value = None9 F; H* a2 X8 `8 ] B: | log.info( "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(' g& t3 {+ r4 d G6 P9 E, H% \ char.uuid, ",".join(char.properties), char.description, value G7 [' M( O: O1 z5 b9 I) Q )( r6 B! B! H+ F- h1 J0 ]1 P I ) for descriptor in char.descriptors:* ^! i, j$ t. a& b! [ value = await client.read_gatt_descriptor(descriptor.handle) log.info(% C) J+ [' l$ u* w* l4 P: g "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format( descriptor.uuid, descriptor.handle, bytes(value) ) )9 U9 D7 l( k6 x* F1 y% Q# @$ C- n 输出的结果:3 F, F7 Q, f/ b6 q* h Connected: True [Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None& J2 W5 U; O/ n# J' H g0 H [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00' [Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile, R, S: n$ o; V4 E4 f% i [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'3 D8 A S* A2 R# Q6 p+ i2 b8 d' Q [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'$ j% X1 [: Z; B9 z4 Q' u1 ` [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'( [0 g/ }7 Z2 d6 P. C, G [Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'' U3 D* t# X6 ]5 u8 `( _* ^ [Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'9 {& H& Q! y% m2 A7 L [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'9 ]8 K6 V( F3 i8 w1 I9 @( m9 r( `) D [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None 观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下: /* UUIDs for Heart Rate Service */( D; Q* l w5 P, K! d( H7 E$ C #define HEART_RATE_SERVICE_UUID (0x180D) #define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID (0x2902) #define HEART_RATE_MEASURMENT_UUID (0x2A37) #define SENSOR_LOCATION_UUID (0x2A38)/ r1 o8 s# [+ \1 q #define CONTROL_POINT_UUID (0x2A39) 2 d' ?) ]% P' E% ~: `, v& z8 N0 ^ 3.3 通知和获取数据 通过STM的蓝牙软件,发现软件是有数据传递的。 4
' S) }! G% {# Q" x/ S0 x 其采用的方式是通知的方式,我是用了一下程序:( z C+ x" y/ ^ ) {6 E: ~4 D0 I$ ^7 R def notification_handler(sender, data):. n" A( j0 w9 b2 c' l # strs=data.hex print(f"{sender}: {data}") byarray = bytearray(data) print(byarray.hex())/ Y0 e- O- p4 ?0 [% J7 ^* D5 i& W. [! n ' @" ]6 B; V7 n+ E async def run(address, loop, debug=False): async with BleakClient(address, loop=loop) as client:* s$ r* M2 u: e" E x = await client.is_connected()/ E% L- d& ^ N# y9 a3 \5 r/ F await client.start_notify(CHARACTERISTIC_UUID, notification_handler)% L- m$ ^9 J Y! y0 K# T3 y await asyncio.sleep(5.0, loop=loop)4 M7 J5 X/ a) Z5 [9 v await client.stop_notify(CHARACTERISTIC_UUID) if __name__ == "__main__": if __name__ == "__main__": address = ('80:E1:26:00:68:7C') #你的地址 loop = asyncio.get_event_loop()3 n3 N* `. t4 {7 T loop.run_until_complete(run(address, loop, True))/ x1 f) x j3 X! z. T0 M4 ?# F ' f$ V R) p! X' u/ j; ~ 返回了一下数据: 00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04')) E/ f+ a% o% M1 }- \, | 1f3700140000043 y0 V) t& ]; Z5 S" W [ 00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')' G: u" A0 O7 s" R2 |1 f 1f36001e0000047 E4 {9 g" O1 v 00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04') w7 t0 \7 D7 P( f, W 1f340028000004 1 q5 ]. i- r4 ?( }! b) S* N3 \ 其中00002a37是HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。 HRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;/ Q8 Q: w& a: [- G; m & {* F! o, s, W3 C 4 小结 以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?. M9 I) E8 d" k2 T/ p) b i$ [ 我相信,在后面一步一步的代码解析,就会解释这些现象。 % ?, S4 P. c+ m. c; ?( K( S * T# m2 x5 Z& x/ ?0 m 7 I5 P9 W! P, | |
低功耗蓝牙无线升级:STM32WB OTA 固件更新技术解析
STM32WB Zigbee 自定义集群开发实战:AN5491 应用笔记深度解读
吃透:STM32WB 上 Zigbee 睡眠终端设备开发攻略
STM32 无线 MCU HSE 频率与启动时间精确调谐实战指南
深度解读:STM32WB 2.4GHz 低成本 PCB 蛇形天线设计实战指南
经验分享 | STM32WB 双核无线 MCU 开发全流程实战指南
STM32WB 基于 Custom Template 实现 BLE 私有协议 实操开发指南
详解STM32单片机的堆栈
STM32单片机进行除零运算,为何程序不崩溃?
从照明到楼宇:STM32WBx5 BLE Mesh 落地指南
微信公众号
手机版