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

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

[复制链接]
ziziran 发布时间:2020-5-23 16:48
0 前言8 m; |$ j' c! q% j9 x2 n
自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。9 y* v- j: E, l, {
0 o% }: h( o  Y! N
1 最小闭环回路
$ c) }7 R, f; d( X7 k% ]- V8 d8 }& w最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。
7 s9 f" H6 A1 ^6 r" ?

1

1

" B# ~. E2 e. b. Q. r9 K
% R5 l# ^7 g1 `% ]

8 D; i- C4 W/ l9 i+ ]/ p# U! H6 [9 z0 D: I0 s5 a
7 R5 N2 I: \5 s6 Y* ~3 [; H

* I0 x7 t% [* F  z2 系统软件环境. T4 m  D6 A8 {! ]
在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。. `# G5 ?  G! o4 `
笔记本使用上位机是自己编写的python代码。
, H  [9 Q) e% P, d

2

2
) A: V, \+ ?, ^+ r

' P- t9 p1 Z* n* L$ C7 @7 V/ j& ]我们将开发板当作外围设备。将笔记本作为中心设备。9 }1 Y9 Y7 e8 x4 @. f2 ^; f
! y' a. S& l8 K5 P. X; k- d* X
3 连接实验
& t4 k2 x3 L3 N( }9 b  k( J% e3.1 发现设备
* l, z6 J+ \9 U下载好单片机程序,给单片机上电。- _- ?6 [$ \! w( \- q3 x( a
在笔记本设置中打开蓝牙,并点击添加蓝牙。
* Z2 D* ?, q- U* v. Z5 t7 X/ j

3

3
0 g5 F# T. |9 `" {7 @+ m# M1 k
5 }. \" W; E% _" a- `
: H* p0 L5 i5 j8 `0 x' B7 L& M  c
可以看到我们的设备HRSTM; p* D/ R0 \' P+ Z. x
接下来使用我编写好代码:+ Z* j3 U; W' B$ |
import bleak.backends.dotnet.discovery as Discovery% M- O' V& b( j
import asyncio
4 j& f! X3 [2 l% \4 o1 Vasync def run():
9 L; V5 G4 b* C/ s" Q7 o    devices = await Discovery.discover()
% k) I+ o* Q: b% J  `/ y1 O    for d in devices:
2 b0 T/ T( [! t/ b; V* r        print(d)
, R# f; E* J& F) Nloop = asyncio.get_event_loop()
, A1 C. f7 u8 ^7 l1 S  p$ wloop.run_until_complete(run())) u: H1 c: q- D/ Y: B
, n8 s2 @( s! t. H$ q( l. G; u6 B
在输出窗口可以看到可以被发现了的蓝牙:
* g. g* w- L( J1 ]- f7 nB8:7C:6F:47:81:BF: MiKettle- e) o  ]1 b5 \6 G
6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec')
1 b) P1 {/ T5 E. s! H% c$ J/ T80:E1:26:00:68:7C: HRSTM6 }7 D2 x4 t0 W* t/ f. f$ o6 W
8 n- G+ ^/ P, X& K; V
我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。, T; ]9 S- E2 s& l7 D' A& Q
5 K4 Z4 C% D; i

9 u, s) h8 E3 l% [+ d! R3.2 连接和发现服务
) |% }6 u, B# x- g" P接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务:4 x# m5 p* k0 d
async with BleakClient(address, loop=loop) as client:+ c7 E& h% r9 M: C
    x = await client.is_connected()
1 ]2 o4 |, P6 F8 {( k' s7 f1 K    log.info("Connected: {0}".format(x))
( b- y) L$ x& A$ I( q        log.info("[Service] {0}: {1}".format(service.uuid, service.description))
) E  @/ s( e& R        for char in service.characteristics:! S3 ~. N" A( w& q9 T. c4 y0 S
            if "read" in char.properties:
/ q3 L9 D; L# c" f                try:
; {! @' K  t3 W; I* D* B                    value = bytes(await client.read_gatt_char(char.uuid))- J4 m) L$ F/ i4 p7 P6 N# I$ U
                except Exception as e:
$ l' `$ R: `2 H' }                    value = str(e).encode()/ n4 A. N$ z- J; H5 Y; T
            else:) z% _9 y9 X2 C1 N( b7 Y
                value = None
0 i: f! e% L0 I) T6 q  ?' wlog.info(' T0 h1 p5 u, S
                "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(
$ I, g3 Q9 F$ Z/ ~- J  Y                    char.uuid, ",".join(char.properties), char.description, value
1 G6 r, R4 B/ ]4 S                )
; Y5 L; m5 ~/ s. N9 s: d/ i9 I3 |: t            )
$ \3 y( l: a7 G, t% [, ~4 i            for descriptor in char.descriptors:8 C' A0 s$ s! G: S3 B3 N
                value = await client.read_gatt_descriptor(descriptor.handle)
5 h& V& j4 ^- U! U9 x                log.info(
' n0 C3 j8 T" O0 H' w, {                    "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(
" w5 O4 G: I# i. F8 @0 S0 z                        descriptor.uuid, descriptor.handle, bytes(value)1 a) ]' L" Q9 r4 Y
                    )
6 ]3 N) Z$ j! n# [" P                ): z8 j& }9 J& N5 q- ^4 [- }* D6 P
/ U) n) W7 u+ z3 \5 J7 ]
输出的结果:5 n5 D3 v. V8 K! d7 x5 a
Connected: True0 Q( d1 g: S3 y: ?) @; u- k5 b$ s" u: e
[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
. w2 V+ A5 b! w- P3 A5 ?6 G8 D! _         [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None6 K2 m) J7 e! E$ {- c
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'# m/ R& i% g: N$ _6 s% J
[Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile* P& z/ ^; R1 m" ?9 ^; I& P0 e
         [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'* p( Q/ O% i- K! ]
         [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'
0 J$ I! u3 H, m; R         [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'1 A& l% F8 H1 p* Q: t3 _
[Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information" e9 t( l& I, Q, b6 O2 D4 W
         [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'1 _6 ]/ J6 O& o/ m' x0 X
[Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate2 O: I) }+ _# z$ c& R( ~, K
         [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None
- k  v& E6 Q- p4 O                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'9 _7 M3 }) [7 w) @% ?4 i0 R
         [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'4 ~5 R" N/ z5 P
         [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None
. B: u9 q8 T  Z8 a7 Y8 ~/ X) U+ W/ ~  z
观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:3 p7 H% W8 Y" c% J
/* UUIDs for Heart Rate Service */
7 {& T% L  J: O: E2 e# L#define HEART_RATE_SERVICE_UUID                                        (0x180D)
; t8 C# t' x4 y' U2 n# |#define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID                   (0x2902)
: E: u/ d; ]1 h7 k' i9 p#define HEART_RATE_MEASURMENT_UUID                                   (0x2A37)
; Y/ U% C/ c; Y+ f% N#define SENSOR_LOCATION_UUID                                           (0x2A38)
2 w  u9 _5 L8 p5 i- i#define CONTROL_POINT_UUID                                             (0x2A39)
. U4 k- o, }/ _
+ n* W. \. `/ e8 y3.3 通知和获取数据# ^, a3 M! H1 G9 w- q( k
通过STM的蓝牙软件,发现软件是有数据传递的。" Y' _7 {% V+ y# ^6 W

4

4
/ r) i/ E3 ^, D

6 A: \9 G3 f. n! V0 h7 j# Z
8 e  f& k: b, ~9 y1 W- \其采用的方式是通知的方式,我是用了一下程序:0 [& l& G# w; o0 |% }  J( _
3 t3 K' Y$ @. d- o1 W$ o
def notification_handler(sender, data):' ]2 V- M  u) \2 t% }2 y3 n
    # strs=data.hex0 e* _" k4 L4 O! P* @; @8 Q: k: z
    print(f"{sender}: {data}")
# n, U8 ~3 V: \& G* ~/ D    byarray = bytearray(data)
( v4 K# q6 w, J1 P- V    print(byarray.hex())3 Z$ N$ t0 q: N) d8 ^! R
, S2 c" ^6 P9 N: {9 G" c
async def run(address, loop, debug=False):
8 C: h0 n. L* w6 H. P0 W" y    async with BleakClient(address, loop=loop) as client:
8 o2 W6 t) M4 s        x = await client.is_connected()& d$ y! z8 M: \9 e1 u
        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)6 c" O  M% Z1 T4 H) W3 ]
        await asyncio.sleep(5.0, loop=loop)
# ]1 m7 `: b4 L9 t; S& z4 B" O1 s        await client.stop_notify(CHARACTERISTIC_UUID)
& L: i6 J+ A* U/ R0 w& W0 ?if __name__ == "__main__":/ O% i$ C" D! ^( g9 k- l
if __name__ == "__main__":
  n9 c  \/ N  z2 w5 A    address = ('80:E1:26:00:68:7C')  #你的地址
. P! M6 L% G& G2 b% o) A9 D. }    loop = asyncio.get_event_loop()  u" d' f1 {# s! m- k4 y5 v
    loop.run_until_complete(run(address, loop, True))! j# w8 a! O1 I

& }  S1 K' ]# k7 d% E& H+ n% b返回了一下数据:
  l  z( J, Q& _7 @  [" d; R5 o00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04'). N0 l8 p: O( C% t+ P4 I! a
1f3700140000047 |2 J% s8 ^6 E/ a2 N4 k
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')
/ @/ x: O" T1 w4 ^1f36001e000004, I: ~) \2 n: \5 D7 B
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')
  ^( z' M* O" Y1f340028000004
; N% x' R7 G  f, ?4 i7 x9 x7 z5 w5 K0 L
其中00002a37HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。% ]  L, E& P( Q
HRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;4 X1 Z8 X1 C: W$ B

' _# n& L3 m- i1 \. v3 f 4 小结' I! a3 J, ~  O/ h& y& D8 k
以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?0 l! ?& c' N7 r- ]9 u2 n' v
我相信,在后面一步一步的代码解析,就会解释这些现象。
3 k6 O& ~% Y0 o5 u) c; F+ }0 s; m6 _) t. _% p) [. O$ `
6 ^. ^$ H5 S* Q7 v9 }

" m: e! I$ x% h9 [! z) J7 m
- l$ Y, |) |' ^6 D1 j0 u" F
& j/ x: |3 _5 ?9 a+ B
收藏 评论0 发布时间:2020-5-23 16:48

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版