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

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

[复制链接]
ziziran 发布时间:2020-5-23 16:48
0 前言
8 R3 l+ V0 Z$ _自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。
8 z( q8 C& I1 z9 @; [6 t# h7 u0 I$ d  R1 V2 h
1 最小闭环回路) ?  b% g1 P( t  j# L9 [% `
最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。8 X" _& Z) a6 r

1

1
% D* D& A4 \  w) C( _8 X
0 H$ E1 b) g4 X8 k  P9 |

8 A9 x3 J! e& G1 y- B+ {) k) D! p; G+ [  G/ k3 _- C+ O) e

1 `6 ~% a! o# J3 y& s. n1 i' M3 M# J: k6 b6 g2 K
2 系统软件环境' u& J1 q) a0 R8 s9 |; F4 ?% |
在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。
# y. e4 e- Y) G笔记本使用上位机是自己编写的python代码。
# \: o) E( @8 n

2

2
- o; X! \# J- D! M* X, ^* H

/ E& B, u/ ~- Z我们将开发板当作外围设备。将笔记本作为中心设备。
" H! T% x1 S/ b5 \! Q1 T
& o: ^4 m# w+ ^5 N3 连接实验
- ]5 l/ m' t: Y' E0 P! C0 B3 T3.1 发现设备4 L' A+ P; O5 a' @$ n7 j
下载好单片机程序,给单片机上电。# X: j- x! i4 @0 p) J
在笔记本设置中打开蓝牙,并点击添加蓝牙。1 W5 z. b+ E3 A  a  D  v

3

3

- n9 h/ |1 k5 f! E( ~( r% ~0 l2 h  n; Y# A8 A7 x8 H2 c
- D. C: |, q, B# Y3 T# V: P% Z
可以看到我们的设备HRSTM。
* v, H- f5 T& S" x. X接下来使用我编写好代码:2 k- |# i" G- ~
import bleak.backends.dotnet.discovery as Discovery
6 x: S; }& @/ V( A$ S3 Rimport asyncio
! O# m- W% S( x& v$ K' O) V* A/ Sasync def run():$ d* S) K, K) |6 I$ n. F- u  m$ A9 k/ \
    devices = await Discovery.discover()9 _& U" t6 T& q2 t& W# `# i' u# M
    for d in devices:* \: B- f% s7 Q# w
        print(d)) d' l/ V  t1 k- W
loop = asyncio.get_event_loop()3 m$ {7 h/ l% ?. b: y: S3 u8 Y
loop.run_until_complete(run())
, j; B* i0 X  T, d; p
( E* _! R' K! ~. ]# t在输出窗口可以看到可以被发现了的蓝牙:/ u9 J3 Z# L* K: c
B8:7C:6F:47:81:BF: MiKettle# z" _) C, g. v* H( p
6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec')- r- @- r1 r) t% [+ O  D
80:E1:26:00:68:7C: HRSTM
% J- M8 W$ s4 v5 X3 Q/ f/ K5 y+ y5 N$ z' P& Q
我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。9 ]9 S" U& S" @- s, e9 k

) }: @, W6 z/ V2 T. m
0 Z/ G9 d' ?5 ^% ~3.2 连接和发现服务0 W+ I3 c0 q! j1 M7 K# f) r
接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务:8 x: P" J' h$ W& S5 c; I
async with BleakClient(address, loop=loop) as client:# l3 y# u3 ]1 D. e) e/ |5 s
    x = await client.is_connected()
1 D' M7 ~4 S) y: J5 N5 j    log.info("Connected: {0}".format(x)). I$ b% P6 h1 \% O2 i& o/ l
        log.info("[Service] {0}: {1}".format(service.uuid, service.description))& i) n0 J! G* z: d
        for char in service.characteristics:
$ F& Z- m/ Y2 Y* D9 j            if "read" in char.properties:: ~% y; B; Z4 a! E" [: E1 v: A  z
                try:2 W; F% C# I5 s7 n$ R
                    value = bytes(await client.read_gatt_char(char.uuid))
' |- P. a1 N) O                except Exception as e:+ J. F  T( v" y" ?+ f: N2 B% r
                    value = str(e).encode()5 H' n, i/ a$ L7 x7 }
            else:7 U2 M/ D. \# d! a" W+ {' n& ]
                value = None- D/ P* y. P* |# i+ N
log.info(3 v. i1 O9 X' {! R6 h/ E1 i
                "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(
& @2 k' g* N( |* p" m' a                    char.uuid, ",".join(char.properties), char.description, value
. G" i8 [/ @3 c0 J* f                )# \/ u8 V$ }/ J! P
            )2 M/ y* }4 S- }( H: N
            for descriptor in char.descriptors:. H- q: A8 F6 V% N9 b, \
                value = await client.read_gatt_descriptor(descriptor.handle)
  _* s" ^+ D- j6 O( F( K- ^                log.info($ X  p& J3 o2 W4 N2 L3 A# O/ d# j
                    "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(
( d# b! ~- ~$ C; I                        descriptor.uuid, descriptor.handle, bytes(value)" q! h4 I0 L( D) l& m
                    )
  k4 X( x- S5 N% x" @( Z' [5 N                )6 F4 \' B  O) x
6 G; D! d; }1 g; I. y$ N2 J
输出的结果:
. G! G, _" x6 ^0 iConnected: True
0 k' J8 Q/ }  G  j! r9 k[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
7 C" s2 n  |' ?* x4 G         [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None- V' }, e  l* v0 G( o: t" z
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'
$ ~1 u& B0 w7 R! x$ e* r7 x% x[Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile
, B; a. m# L/ ^  h. p         [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'2 P  A5 \' O; H
         [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'# |, @0 @- b% [3 ^( t
         [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'
$ K# H+ |9 q9 L7 A[Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information
- w: J% g8 p4 ]* D/ K8 V         [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'8 {4 A/ {  a8 B, N. h
[Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate$ F. i$ U. Z3 f
         [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None
" @4 g5 O3 H- z# P2 B9 t  P: a/ a                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'+ ^# y2 E8 {; {+ a4 y8 b/ V  ~3 `
         [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'9 u5 U" d" y! a, n9 p4 K
         [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None
: `# z7 y1 w: \
  J  z+ h. }% O. s观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:: U2 F1 c" X  `* V
/* UUIDs for Heart Rate Service */
2 L2 ^3 n" E2 b#define HEART_RATE_SERVICE_UUID                                        (0x180D)2 V2 i$ f# J3 F, O8 E0 K: x- e% A
#define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID                   (0x2902)" T/ p* Q8 `7 n: G" \& U* H
#define HEART_RATE_MEASURMENT_UUID                                   (0x2A37)
7 c% ?4 e" a+ \) D#define SENSOR_LOCATION_UUID                                           (0x2A38)
: c0 u5 X$ N. T; W% K4 N#define CONTROL_POINT_UUID                                             (0x2A39)' a5 @' q4 m9 m7 k3 @

0 @/ ]! \/ H0 l, n8 I6 d+ E3.3 通知和获取数据
) \4 L! m" n( i通过STM的蓝牙软件,发现软件是有数据传递的。
. }) ]. y# ~  ]$ z

4

4

0 g* q( B/ q( e- _+ q# K) y/ m' U& v; T" G+ x( @7 ~
" M, e  a% @% p; _% ~! ]# ?
其采用的方式是通知的方式,我是用了一下程序:% o( W# I9 B0 |; Y* D8 I, d

! K9 F% X( W. D! ~& H( j, mdef notification_handler(sender, data):
: {: I: R9 ~4 N, c& q# s' w/ X6 P    # strs=data.hex1 n2 p. o0 v1 z( I
    print(f"{sender}: {data}")
* g  z- ~. V# E    byarray = bytearray(data)
+ y. ~0 W% I: v- T    print(byarray.hex())6 H6 m2 L3 y& X, P

" Z1 F3 Y8 T8 qasync def run(address, loop, debug=False):" S( |4 E9 `* j5 ^( t
    async with BleakClient(address, loop=loop) as client:
2 Z  \" Y, f2 F8 w; N% I0 U        x = await client.is_connected()# s! `+ _/ F4 H8 T+ O, p
        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)
/ s- B* D* ^* R& z7 T' l5 ^        await asyncio.sleep(5.0, loop=loop)
. w  g$ G( Y! O# Y9 M' \$ l        await client.stop_notify(CHARACTERISTIC_UUID)
2 [! X5 h. Z* Z+ A, f" |* m6 n1 Cif __name__ == "__main__":0 f  j* v. {; C$ @" i8 e- s
if __name__ == "__main__":1 l2 p$ W9 J, |
    address = ('80:E1:26:00:68:7C')  #你的地址
* k: W" h9 B+ g' p8 ~5 J    loop = asyncio.get_event_loop()  N/ v7 f* a* d3 z2 @
    loop.run_until_complete(run(address, loop, True))/ P/ \0 Y+ v% U3 a+ K

& v. L! u/ R. l2 T) m返回了一下数据:
4 Q* X+ S5 M( w6 n/ |* J+ g00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04')
& g  f1 E1 c2 ~1f370014000004
9 m$ l1 Z& W( Q00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')
3 ?: n+ B2 E! S, P, P1f36001e000004  @  |0 K8 o9 h  u
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')
; k9 c& X% P# b7 O% Q) C' B1f340028000004
5 B6 @# ~3 ^/ N! s. \$ L& p$ Q6 A9 F( p- H
其中00002a37是HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。
$ l) C* H8 a: iHRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;* _$ Y) U! a9 D, }  b3 o

+ u5 n: |/ w- z7 i  W 4 小结7 s; @( w1 h" R- R7 G5 r, p
以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?
5 W. r  F: a5 X. u$ T我相信,在后面一步一步的代码解析,就会解释这些现象。3 L) S; W1 u' q  C- z) Q; A% W

; N# F7 B" Z0 o2 J7 d7 x
" V8 a3 q) M& }1 L4 a+ l% e

' S7 Z9 h3 u! c) W2 U& Z1 s2 U
2 c/ b+ `& S- Z0 m# a  F
* s: }2 P0 `$ @/ Z0 n( O1 |0 ]
赞 收藏 评论0 发布时间:2020-5-23 16:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

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