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

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

[复制链接]
ziziran 发布时间:2020-5-23 16:48
0 前言
7 B) w$ _4 i/ X$ p& R2 K0 q自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。
( z* T2 x# o5 U( n
4 ]9 E7 ]6 e  g$ f, X; @1 最小闭环回路6 Q0 [+ n, j; V  X9 m
最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。
$ Z( d8 }+ S% A- f: T

1

1

9 Y# c2 }! h) ^' ~
8 R0 `! `# |5 {" F) H# z
: {3 G" p4 b9 X9 k

: S$ u$ D: m8 t5 Q# Q4 ~' e6 k: K/ b3 o- J( j

: k2 o' f, x- X' o2 系统软件环境% N8 L( u4 @* p- r
在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。
5 |* \+ e" D3 e* M: T笔记本使用上位机是自己编写的python代码。
7 l! d6 q) {/ \4 M3 T5 D

2

2

0 O! @- x# y" ]+ E$ j; V; |# y8 a. R: J( Q$ v* @9 d; m9 r( ?/ W
我们将开发板当作外围设备。将笔记本作为中心设备。$ W+ |  G% h0 w3 i" \# g, {4 M

6 y4 s7 t5 o, v, @5 f4 k+ U; h3 连接实验4 K2 {3 V$ O, R, \! o- [
3.1 发现设备4 T* Z- j3 ^. X+ K" Q9 n1 [- |
下载好单片机程序,给单片机上电。( K+ Y7 N; m$ }+ [, r
在笔记本设置中打开蓝牙,并点击添加蓝牙。
0 i& M( s! V( S

3

3

. `! m' b+ T6 R% e. R) R: z( V& j  f7 x, p# f) S5 F+ A! S
! A; ?8 i; U3 y  b
可以看到我们的设备HRSTM。2 X6 N' N- o+ X1 l: p* {3 Z9 V
接下来使用我编写好代码:7 Z" s1 t6 N8 p+ e! u2 B" S
import bleak.backends.dotnet.discovery as Discovery
" Z) `6 H! b  }" \5 [" B7 ]6 Dimport asyncio
+ j8 E  U( Y$ i1 k  Y# A+ y: |, w: Oasync def run():# {* M( _% x' @9 q$ |9 ]3 T0 J
    devices = await Discovery.discover()
6 P: F# B! w2 J* L9 t    for d in devices:
" Z6 H% d% ?! U# o        print(d)3 G8 y4 y! s9 E
loop = asyncio.get_event_loop()4 M8 [1 I7 X. T/ a" p
loop.run_until_complete(run())! ]8 B- k8 _' h3 V1 j/ O

8 B  r# d% w! p- ~在输出窗口可以看到可以被发现了的蓝牙:
: E! b8 S7 j5 k0 S4 ^: s6 d2 m0 ?; M( dB8:7C:6F:47:81:BF: MiKettle; A  C* B/ B& A' l! b
6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec')
% L7 x5 \8 _( Y, X80:E1:26:00:68:7C: HRSTM
) j3 B- D+ S/ G# w: b) F0 h- w+ h' ?8 B( i
我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。8 T$ w! k! }# z+ f

  r3 n1 s, J% L; c" k1 R& p" Q, a# A+ c9 o; [/ @
3.2 连接和发现服务8 E  m- c) b- J8 z$ s) L6 Z
接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务:, M$ W. l2 E1 D6 H8 S- _3 n6 U
async with BleakClient(address, loop=loop) as client:
$ `9 J0 P  w2 a    x = await client.is_connected()
$ z# j. Y1 l2 z7 C5 q4 L6 M    log.info("Connected: {0}".format(x))- ]5 a6 X+ |  K1 o" Z
        log.info("[Service] {0}: {1}".format(service.uuid, service.description))" U' C. Z2 Z, f; a$ k
        for char in service.characteristics:- ^) L$ M+ i- k* ]1 D# e, E2 h
            if "read" in char.properties:
3 U6 ]& h- i/ ?$ m$ {# d+ L                try:
. V7 a' q$ H0 h/ @8 h% e4 N                    value = bytes(await client.read_gatt_char(char.uuid))
7 I  `! m0 V/ w& b7 g8 y. |                except Exception as e:
3 H& b. B/ P$ K                    value = str(e).encode()3 w% g* |  c" h3 @
            else:
6 |4 A: X* c1 F& k                value = None
* M2 H  G! a% Ulog.info(* K6 S; Q) |: H. @; U4 w4 k
                "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(7 V1 x# i4 N' ^; S8 ~: B2 ^. V
                    char.uuid, ",".join(char.properties), char.description, value
' K9 J* `" M1 y' m: e" a- x                )
/ A4 U# t8 I* V- K$ X1 e8 n5 H) w            )1 S( J& k1 s+ q4 k/ U
            for descriptor in char.descriptors:: _! a. {3 v5 O2 v1 c/ b' O! p
                value = await client.read_gatt_descriptor(descriptor.handle)
: x9 Q: v- i5 H+ R' |' ?                log.info(
6 P" w; Y% K/ y9 W- z                    "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(5 n& n' Y! u$ N) l! k) Y
                        descriptor.uuid, descriptor.handle, bytes(value)2 [# |" i. E. \& |
                    )
+ x; t; x5 Y# V# A: C* @                )4 d& l# q2 X) l' u: y

7 T2 ]  k: u( q输出的结果:
% [4 J) d9 b& c' GConnected: True" r7 w1 o$ H" z" p
[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
! d8 W% y& v1 R# X         [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None
" j5 b& Y# s( b& }% x9 A4 R1 @+ V( n                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'
, x* i/ j- n- y6 s; ~[Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile- J9 f) Q4 M* l* T$ K
         [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'
. }4 Q8 E- A2 u  `8 I9 }         [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'
) w3 |  h2 }% Y/ [# E- O         [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'; y/ Z1 i* a: X8 u' Z/ T) W, L; J
[Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information
. D# |* V  B5 e4 ?6 ^% `# o! j         [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'! v1 v( w* v9 ^$ i% M7 ?7 S
[Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate
7 U: D9 A" x' Z+ t         [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None$ Z/ w% R. X/ W! \7 }- }6 f1 C: B6 _
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'# H' D6 D) t# N; x; O
         [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'% A0 x: o$ R, P2 B+ A5 A" z+ C
         [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None
8 }* o5 _* l2 |% |
3 z3 {4 R# l- A观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:6 F7 L3 r7 \. q) x* @8 s
/* UUIDs for Heart Rate Service */4 D& B7 S% w: h% E- D% L
#define HEART_RATE_SERVICE_UUID                                        (0x180D)
5 S7 {6 s% M8 ]+ T#define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID                   (0x2902)
0 c" u. I" e5 H5 g1 }#define HEART_RATE_MEASURMENT_UUID                                   (0x2A37); ^5 A- k& x* V' e4 L
#define SENSOR_LOCATION_UUID                                           (0x2A38)$ t3 d9 ]% z/ J' J: m! t
#define CONTROL_POINT_UUID                                             (0x2A39), p4 N% Y; b+ J; R; U0 o

  S: o2 a1 w) Y! g/ C3.3 通知和获取数据
/ }- y7 Y0 e7 }8 D- _: V2 R" ?通过STM的蓝牙软件,发现软件是有数据传递的。+ l5 ]' }) r" e

4

4

- v1 e* w9 o& N+ a1 |* w  O& S! I( N/ q* J, ]

0 Z$ k. C2 S/ @2 w其采用的方式是通知的方式,我是用了一下程序:  l# G  ~/ C1 L

5 `2 {0 y- R$ k- Q5 K2 Z1 Bdef notification_handler(sender, data):& r3 I# D' E/ ^0 K, E4 S" [8 ?
    # strs=data.hex6 J! f2 v& q/ |. B
    print(f"{sender}: {data}")
, w8 X! A7 T! J8 M7 p    byarray = bytearray(data)
1 N4 F3 ]& n3 V: |# R1 s    print(byarray.hex())) \9 w/ b4 Y) ~7 h

$ k2 ~. _4 t0 ~% Nasync def run(address, loop, debug=False):
& [# n- b& o4 R! l8 R$ d7 w5 a3 r; y    async with BleakClient(address, loop=loop) as client:
7 K) p5 O( o- p2 P        x = await client.is_connected()
8 k; ^3 {, M! w; f        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)+ Z+ w) R# t9 z4 p% I) q. e
        await asyncio.sleep(5.0, loop=loop)  T6 D- q- e+ s, Y4 x1 k
        await client.stop_notify(CHARACTERISTIC_UUID)
$ D& P9 b1 Z/ ]  ~if __name__ == "__main__":/ d- P% D8 Q0 n
if __name__ == "__main__":
* j; ]* J4 t) y. P3 Z    address = ('80:E1:26:00:68:7C')  #你的地址
4 z8 Q& F& b  Z/ w- X    loop = asyncio.get_event_loop()
7 _# f4 q0 }# H( p/ K    loop.run_until_complete(run(address, loop, True))  k2 c  q/ w: C% F6 f! m! o! P. m7 }

6 A* I, F, C- c& q8 c返回了一下数据:# E) ~" k7 t7 A/ |) a5 a; [
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04')) Q+ {7 [6 E" G# |
1f370014000004/ S6 M4 G  V* U
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')2 u( A1 q, x# j# W/ ~3 d: t; ]
1f36001e000004% V8 _% u/ m% V& `6 H/ t% f" e
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')
/ A6 J5 s: C& k4 K# Z6 j7 C' o2 M1f340028000004
% K8 e; T+ H8 v$ F+ [
* S8 F# ^  K" x/ b其中00002a37是HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。0 t3 `% c4 c  [" x, l" f
HRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;2 E) r' t3 Y. V4 O! g
$ H0 U$ j6 |! |* y! @
4 小结
  W- D8 G4 N! N, @7 t& K# h' l0 y以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?9 I, b  W! v* c! y4 J- n) n
我相信,在后面一步一步的代码解析,就会解释这些现象。% q5 X- j3 S0 {( @, R5 d9 X5 K
2 q! b  F1 P6 [$ t; V- h1 B" L
* P" X8 A1 U8 v* P# M

: n7 D0 `- m' |6 |# a; `

) m: v& d) h8 d/ X
3 n- }: B7 P: Q/ i* c
赞 收藏 评论0 发布时间:2020-5-23 16:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

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