你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

[STM32WB 蓝牙探学] 2 BLE的连接与操作

[复制链接]
ziziran 发布时间:2020-5-23 16:48
0 前言
0 Z8 n1 d0 p0 |$ `2 P自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。
0 J( i$ Z* q% H2 G9 ~6 c3 ~, Q9 G, K% [4 ]4 O+ a) X% o
1 最小闭环回路
) I5 W; }2 G6 f  i" w  w3 R最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。
2 Q+ m9 B( s* I0 ^. y! {! f$ W" ^; w

1

1
0 y0 K$ w2 N* S
# b2 P- ~: a; O" J( i
/ ^. a5 `0 U  @  |" t

& a: G( \2 p5 S5 `
' g& K& r( B, Z
# I; X! u( F0 M9 Z& K9 T7 Z2 系统软件环境
: V5 M. k7 _: M) n在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。) F; u  x6 J4 t! e
笔记本使用上位机是自己编写的python代码。
! ]& Y% Z, W8 [, G7 f  n

2

2

0 ?# B7 Y' s/ ?+ `9 `: j2 u
% \: i( N- J4 [4 H我们将开发板当作外围设备。将笔记本作为中心设备。
7 m0 F8 ]  z, p2 e% a. c. v) ?1 ^0 x: @: `$ Q
3 连接实验
8 n# D4 G% f& w$ {& [. r9 \# X  H  E3.1 发现设备
% ~3 f. b8 ^: I( O" ^, U下载好单片机程序,给单片机上电。* E2 I: c" u. e% W/ E% T' C% g
在笔记本设置中打开蓝牙,并点击添加蓝牙。
" b2 T7 e; M" f

3

3

1 `( w$ y) C  @& Y7 P
% n! ]$ w+ D& `9 w8 k! H* N/ \8 L, ~/ Y9 S  m6 o
可以看到我们的设备HRSTM。; B+ r8 V7 G1 G! g
接下来使用我编写好代码:
+ m" c) \" M- b5 B, R, }9 [4 limport bleak.backends.dotnet.discovery as Discovery
4 m9 z6 h( U' t3 @/ K8 N; {import asyncio
; u5 q4 N8 W5 Z) ]% Z: q# e) ?async def run():
' I9 j0 N0 d' W) _    devices = await Discovery.discover()6 R9 E  t9 o( J0 }
    for d in devices:( G9 k# \- @, x9 C( F
        print(d)
* S3 {2 e" h- Nloop = asyncio.get_event_loop()9 S% Y% S" s2 G) T0 c
loop.run_until_complete(run())
* {. y/ c, i2 Q# X2 f) z9 o( |9 i! K# R7 \7 J% q
在输出窗口可以看到可以被发现了的蓝牙:, Y0 T8 {- U" |. ?9 Q
B8:7C:6F:47:81:BF: MiKettle
3 L; N) F- v! I! M" H6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec'); c  q; e* R2 J* @* v3 k: S
80:E1:26:00:68:7C: HRSTM
( V( J+ ]) ]5 x6 G2 @( P2 K
( N/ @7 N: t  ~我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。
) H  Q+ d0 s( \" A
+ e, M2 g9 Z3 O& @
, K, d- F5 F1 o! y) B, c3.2 连接和发现服务& }2 W- l  ^( S. X0 ]9 z: T' b% f
接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务:# x  H$ t) f0 E/ \/ s
async with BleakClient(address, loop=loop) as client:
9 ~& f. w) ]- Z+ Q$ ?    x = await client.is_connected()0 _  n# l' G! R# q* _4 [
    log.info("Connected: {0}".format(x))
' w7 ]% _8 K7 B8 t$ [        log.info("[Service] {0}: {1}".format(service.uuid, service.description))
+ d) G" i% j1 ^+ {* n8 T        for char in service.characteristics:) l! ]: [- G+ F  b: f4 d- ]& y
            if "read" in char.properties:( G, t! L. A0 l& h2 H1 T/ s
                try:4 E+ I# s; n$ _
                    value = bytes(await client.read_gatt_char(char.uuid)). P  q8 _5 a: l; |" M/ E
                except Exception as e:, @  q' V( ^  F- I; {9 m
                    value = str(e).encode()" W0 i4 u  w, V7 @8 z
            else:8 |1 V. C7 @" s! S- B- p
                value = None
1 R- `, ]0 a$ Q4 ^6 Vlog.info(
1 D- P/ n+ ]8 j8 Q+ e8 _9 n                "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(
( R/ z$ s' @7 U                    char.uuid, ",".join(char.properties), char.description, value
$ V" P# f( u, U7 }                )
8 t% p# s+ u0 a$ N% E2 o            )+ S! j4 R- v' k
            for descriptor in char.descriptors:
! M3 r6 I2 W6 U9 d% l                value = await client.read_gatt_descriptor(descriptor.handle)
- z8 \( m. X- l' o- G, l' y                log.info(" P0 M; o9 y# f- I( R* O
                    "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(- x1 z' L& V# e8 o2 l  T7 T5 s% v
                        descriptor.uuid, descriptor.handle, bytes(value)& Q9 X+ q: U7 ~% o6 [. b
                    )$ B% \; v1 h( T! r; N2 |1 N
                )7 C- I6 @. p4 C2 b# L8 Y' i5 E
2 t2 q' E, ^. Y3 ]  n- D
输出的结果:
) \7 u$ O- h0 S8 U+ M/ `Connected: True
9 ^) I0 k* G5 [8 Q5 O# A4 S/ y[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
& m3 i0 a! n5 C0 B- ?9 r& t. ]         [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None  ^6 J3 R( }; p
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'
$ n" I& J5 [  p( G- d! X[Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile
( K# t1 @1 W% @5 P$ ?6 N         [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'$ m# n5 n1 E) f1 S; P
         [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'# I& v4 `4 }% T) A
         [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'( e* s" z9 j+ a
[Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information
, ]$ s% g7 ^. \; T, k         [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'
& D& P6 c4 @* U6 F, k5 v; o[Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate
/ Q" j3 W" n! P         [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None" P3 h: s, g: P& f
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'
% {/ W( C3 E+ T$ a# h8 z         [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'
! J# G7 Q  U$ L1 F6 L8 ]         [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None' F0 a. Z+ r# W# S" C! d
9 M; q$ y" x( _. w3 K# k
观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:. s: D/ c  h: c  i
/* UUIDs for Heart Rate Service */
. V# u# U. B* y/ A  e& v' K7 W9 d#define HEART_RATE_SERVICE_UUID                                        (0x180D)
3 h, ]) F' I! b+ _#define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID                   (0x2902)
9 |* G' _. p/ Y0 Y! T#define HEART_RATE_MEASURMENT_UUID                                   (0x2A37)6 Q4 i# w" J) m4 z. e
#define SENSOR_LOCATION_UUID                                           (0x2A38)) ]  s, l# `3 m  T- |
#define CONTROL_POINT_UUID                                             (0x2A39)
% O3 r: J& S: N9 k4 O9 }& B/ C
" E3 k' F  X; V5 i7 `( r1 J; ]3.3 通知和获取数据
# d* z& W6 ?( V$ f5 E% u通过STM的蓝牙软件,发现软件是有数据传递的。
; s4 _! w# a1 [: \

4

4

6 z' N$ Q) }) o# _) B9 x) o
/ G  j6 i! ]/ }5 U& N3 ~0 J. {% z2 G" r! r* e
其采用的方式是通知的方式,我是用了一下程序:. m: t8 a2 y6 Y' S- U

9 ]5 S: N* i+ y4 ?. T# `6 N# b) wdef notification_handler(sender, data):+ b% A7 j: _2 c2 K  Y
    # strs=data.hex3 y/ e  A% o3 X# w
    print(f"{sender}: {data}")
3 j0 q/ ^9 l/ x! Y3 P4 w    byarray = bytearray(data): K5 h9 z( O. c4 h
    print(byarray.hex()); X8 t( w1 j" u8 T9 }+ n

$ j: s- N. M, v6 q/ Vasync def run(address, loop, debug=False):' o! L5 e+ ?/ ~' k4 u  u
    async with BleakClient(address, loop=loop) as client:" e0 r7 N" I0 C
        x = await client.is_connected()/ a' ]4 k$ _/ S
        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)
/ m) C1 d4 S! ?2 Q; F- p" ?        await asyncio.sleep(5.0, loop=loop)% f* ?, A! G- Z5 J. ]
        await client.stop_notify(CHARACTERISTIC_UUID)2 l" ~3 i6 q5 T) }! n+ X; g
if __name__ == "__main__":
* ^7 ~* d$ w" f, n5 Zif __name__ == "__main__":% @5 ~' l' c: E4 q5 O8 q
    address = ('80:E1:26:00:68:7C')  #你的地址, R2 J  v) i) y- z& e! ]5 j6 q
    loop = asyncio.get_event_loop()4 ]( U% z1 [/ Q* u& _
    loop.run_until_complete(run(address, loop, True))
& I0 d# b4 r# S9 D& V0 L) m+ t" G0 p- p+ |6 c
返回了一下数据:
; @0 a  b. i- Y/ w5 Z" w' y1 F5 B00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04')
7 J$ r9 x1 ]3 b( Z1f370014000004
) ^$ z7 u0 j1 O/ f% v* u9 N00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')2 d& q! A% ]1 O. N# H5 a8 h* V, m
1f36001e000004% b9 U' O, y+ [" l  Y% s% Y
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')' q  |, Y) l4 L
1f3400280000042 b8 s/ y  [5 x$ W$ N" O
. w5 H7 D6 u/ K
其中00002a37是HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。
9 P6 O+ s9 g3 ^# l3 vHRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;
3 B9 O8 D% X6 X2 r/ |0 k1 c# }/ C$ Y! }
4 小结. D, L0 `3 g' R( c1 _* m  O5 m
以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?4 v* S- Z- D! t$ Y
我相信,在后面一步一步的代码解析,就会解释这些现象。8 |' M5 U5 h0 B
) s7 h& x! {; [* x' p8 C+ _

- z& G2 V- @- w; [+ l$ E2 C% t$ p( p0 x& I$ X
0 c6 p( V4 c, w
3 _; i& m. {$ B0 D+ Q& V+ [5 c
赞 收藏 评论0 发布时间:2020-5-23 16:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版