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

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

[复制链接]
ziziran 发布时间:2020-5-23 16:48
0 前言
" J( f6 k3 ~* c& Y自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。# E* q6 O, ?" S* w4 V

0 \) w6 \+ M$ j, v# x  G1 最小闭环回路
% `+ S0 ~; d% n: d; g最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。3 W! d5 ^1 p2 y: A, D: }: j" R

1

1

. ~# C( j+ N2 r6 s9 l4 L
; `, O: n: b" {/ |& Q; H' k
, G' G! _* o3 J: p" J! Y- o

2 I7 [3 ]) |3 l) ^5 p  m, x# i4 s. g. ~1 l  }- B! G: D
: I9 A4 B5 a1 d% ]- V0 A! |  H: P8 t
2 系统软件环境
% \% o6 M& c8 |5 ~在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。
, P7 p1 A& r3 s2 H2 d+ r笔记本使用上位机是自己编写的python代码。
9 ~& t0 v0 R0 L4 j) W' e" w3 d* n' m

2

2
( _2 ]; H! A+ k& d' A! x

; [5 V# ?- P4 ~我们将开发板当作外围设备。将笔记本作为中心设备。
. K  J, \* t) r4 N: v
6 O$ |  z8 p; v# k! I4 H3 连接实验; e; ?& G8 a2 Y. @
3.1 发现设备
1 |2 X/ O: B( z% Q5 k+ J下载好单片机程序,给单片机上电。
) \- g) Z4 {( ?) s在笔记本设置中打开蓝牙,并点击添加蓝牙。
* N4 C, E3 Q' I" n. [6 ]

3

3

, e+ a2 }, G/ w3 }- k. D7 g& a$ E) S! R  Z" n; |8 |! J+ X

/ N0 ^1 n2 s. r( C& n1 ?$ I可以看到我们的设备HRSTM9 q) r+ K% Y: `1 A. g
接下来使用我编写好代码:
! i0 e3 r& A% b/ E& k: }0 G: z& Pimport bleak.backends.dotnet.discovery as Discovery2 Q. z( M% ^, {6 u3 }
import asyncio7 @1 C. n  W8 A
async def run():+ N* X& m6 a1 s+ D% v
    devices = await Discovery.discover()2 o( ?( B/ u$ g! G+ N9 s2 h! d
    for d in devices:# {% `0 H, B6 m4 _4 d2 W, J3 F
        print(d)$ Z! P5 U% Z- w3 k; O
loop = asyncio.get_event_loop()0 W* R7 ?- \, u1 f  }
loop.run_until_complete(run())1 e# R. C1 ~. W  q( ]

0 [* {- P8 W& S- `9 [在输出窗口可以看到可以被发现了的蓝牙:4 l8 C+ [! m/ f1 |  g; i
B8:7C:6F:47:81:BF: MiKettle
( ~  Z" }/ u+ e/ d- P9 M6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec')5 r* g% s; Z8 i
80:E1:26:00:68:7C: HRSTM
' ]+ o+ m. u- x$ [# L  v; l6 |0 ^/ U; N+ |
我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。
7 W) z! s; T7 c+ @& w* t% g$ E3 l( ~+ b) @" V; W& e* F3 M. ~
! ^- a4 a6 _- [( E3 \% ~
3.2 连接和发现服务
3 e8 j% g3 J6 I/ P+ ^接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务:
# N/ v3 X5 h, ^6 e  C- O5 B) h3 jasync with BleakClient(address, loop=loop) as client:
! e) C8 w$ v$ C% T6 W    x = await client.is_connected()
" U" v5 \, J! J+ j$ I3 U" x    log.info("Connected: {0}".format(x))
0 |: N+ q& h9 }# x( d1 ?        log.info("[Service] {0}: {1}".format(service.uuid, service.description))! S6 d$ g) n' E& V( y% W: H
        for char in service.characteristics:* J. |, N. ]/ S4 B  u. p) v
            if "read" in char.properties:
; U. f9 ?5 Z' p7 A( J% R% {8 d* i                try:
0 A# \6 b- c  N' _, [2 K                    value = bytes(await client.read_gatt_char(char.uuid))
# t' B/ y3 h* m# K, y6 u) T% ^                except Exception as e:
; F2 W. H9 C) D# V1 V                    value = str(e).encode()
2 m& S+ Y" Q% S: z) U  s/ H            else:  H: B# C6 L' H2 v
                value = None
4 _) N' [" E; V) a# h; H6 A9 ~log.info(
" a: Z2 O/ i& V& f8 @                "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format($ U2 H6 d. o; K' d) u1 M) F
                    char.uuid, ",".join(char.properties), char.description, value
* M" T  A( a" _0 v                )
6 X/ h2 a( t$ W5 f4 y- s            )' N$ R) [, K: X8 L/ R2 d! F
            for descriptor in char.descriptors:
, u/ F+ `7 ]2 z' R1 L                value = await client.read_gatt_descriptor(descriptor.handle)+ C* D/ W, @0 ^
                log.info(
7 e! ]) \& y5 n4 g' J                    "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(
5 A/ x+ X7 g# ]$ f                        descriptor.uuid, descriptor.handle, bytes(value)
( T1 s$ Z1 t% N( S/ R# ~                    )$ X& K6 h! ]( |
                )
% w. m5 T- J( o5 o. s3 Z, l2 M6 l# A' H0 w) C. D# V: x2 }
输出的结果:
0 y4 i( R+ j9 W7 v7 ]! J# UConnected: True- k. J  |6 v/ g' Y
[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
, n# x9 o* a- G4 p6 i+ q1 P         [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None0 f8 B4 H: B+ C5 o% o+ W6 Q$ ^
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'
+ D, o1 d' y; T% w* F$ c% @[Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile6 \( J. i% D/ T9 P/ F0 ?
         [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'- j/ `, t% n9 Z; n2 J$ ~4 J
         [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'5 L  p+ d% E: I! c9 D, j7 Y  i
         [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'! s& s, R+ W) S+ ?
[Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information
5 G2 E4 H# E1 \! A8 {; Y  v         [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'
% K) s+ [& B; a7 X8 X[Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate1 L3 A. s9 }# C! ~$ k; X" v# \8 W' J
         [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None( _4 [# I% J7 P$ `& U
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'
+ n4 _' l# R3 J         [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'
% j# r$ E& t, l; v1 j/ t: v8 i- ?         [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None
# ^) _! Q- t% e1 g6 Z, I5 K! ^8 }: A; J
4 M. a) V+ Z$ x4 ?( D# x观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:
7 W( Q- M) y$ N; A/* UUIDs for Heart Rate Service */
. E/ K+ p3 S* v" O+ T# c% ~#define HEART_RATE_SERVICE_UUID                                        (0x180D)
6 E, x5 Z: h& E#define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID                   (0x2902), r- H$ R" @0 U- Q
#define HEART_RATE_MEASURMENT_UUID                                   (0x2A37)7 ]+ t$ y* [: q
#define SENSOR_LOCATION_UUID                                           (0x2A38)
( I! Q6 P( B/ b#define CONTROL_POINT_UUID                                             (0x2A39)9 X: g$ y! Q) ?: g: d9 ]" X

- x+ ?4 E+ o0 B" Y4 z! r' \3.3 通知和获取数据
3 ^" l7 |% C3 ^! s6 f2 m. p$ @% w通过STM的蓝牙软件,发现软件是有数据传递的。
, [. c: E: W  B) w2 U  `" l

4

4
6 B" Y: ]! V. e7 Q' e1 `5 u

& w. K# L5 Q. r; W% J2 R) S( ~  ~$ M) {5 Q/ E
其采用的方式是通知的方式,我是用了一下程序:
6 d) N4 t6 D( i+ D9 S8 c  I" y- q% u* _+ F! G9 t% }
def notification_handler(sender, data):; Q2 b& N6 j+ {! Z; W
    # strs=data.hex
0 N/ l8 s6 q% ~& i    print(f"{sender}: {data}")( r* {% e7 l  T
    byarray = bytearray(data)5 C' E% i4 d& P* k
    print(byarray.hex())) |, n) B! _) w' t5 n8 W
; r, ]4 r0 R: j, S! s1 b2 }/ y
async def run(address, loop, debug=False):
4 x) W5 ?0 q7 t# z7 i* w% P+ a; X    async with BleakClient(address, loop=loop) as client:0 Z1 Y, R3 J/ |# W
        x = await client.is_connected()1 u! l' ?8 z; o( B, ]/ p" y
        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)! ?! ^+ V; t: z) L
        await asyncio.sleep(5.0, loop=loop)
# L2 `6 R# y- O0 |        await client.stop_notify(CHARACTERISTIC_UUID)- q, v2 B/ {' K" t8 L8 x
if __name__ == "__main__":
( w" n! n. h1 }if __name__ == "__main__":
* A" g, L) |- ~7 x+ h2 ~  h' t$ Y) n    address = ('80:E1:26:00:68:7C')  #你的地址( g8 y; J" s5 G1 `: ]. n# b
    loop = asyncio.get_event_loop()
/ y9 d5 L' W+ g( t2 I    loop.run_until_complete(run(address, loop, True)), J9 O/ r; V: |, g) y$ |& f5 Z

2 G3 q, h% P  c& i9 A返回了一下数据:
6 _2 i# A& R5 g8 W# M00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04')' g4 U; [7 ?0 {" Z1 \* x0 G
1f370014000004
  m0 `2 K1 j* V- c  B9 a1 i" L00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')
2 [% X/ G  O, h1f36001e0000040 _. Z. |* v' S" I3 a/ o, F
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')8 e! s, m7 X, M: r0 `
1f340028000004
, d  P- b% u  G6 a9 [$ S* y+ N5 k' F  k* w
其中00002a37HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。
0 C; {: l+ r1 k) D8 U6 T2 WHRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;
- T, K7 L* Q4 C; k% f: T# Y  c% U! V% v, s+ g" b& x
4 小结: I7 h  i) _! q
以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?, [* B6 G* F1 Z$ T) e! {3 V, r
我相信,在后面一步一步的代码解析,就会解释这些现象。3 Z2 v* `6 P, Y5 i- F

% Q' Z0 [. s! P

/ P3 k4 }4 V3 n7 w/ b
7 Q8 W; t; Y7 h3 J6 b

# @. W$ A" Y$ ]( M$ D: n+ @2 E
; Y3 V2 {% p/ p8 ?
收藏 评论0 发布时间:2020-5-23 16:48

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版