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

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

[复制链接]
ziziran 发布时间:2020-5-23 16:48
0 前言' E' J. h4 Q+ X1 U$ Q" o3 v* H5 N
自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。
0 ]' w3 ^3 T: n; ]7 G
  k+ h4 T- @2 ^3 a1 最小闭环回路9 b7 j, z$ `! W0 k
最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。7 A, g) x. K: Y7 o/ Q$ y. P" h* w4 a) _

1

1
" X* E% V5 C5 l& q' d
/ N  F+ \' d) K: L# [9 }+ [
/ H" l& B  a, Y0 K8 T- J

& B" u( }0 |4 R
, P& @8 e# Q, K5 W8 O& d. k  [& J4 w8 f
2 系统软件环境
* m, N5 ]: y* w) c; J0 u& |5 Y在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。3 m  v) [3 u5 j+ W! E3 R
笔记本使用上位机是自己编写的python代码。
) f: y7 n. d+ [$ K& u( C) ?

2

2
" [. T6 |( {3 _3 q

0 b# \7 g3 S1 M6 ?' M0 ?: ]我们将开发板当作外围设备。将笔记本作为中心设备。: l, g  ~6 [: N& N6 U) r

  I& |: o4 O! c5 \2 q9 x: C3 连接实验" i( A' r- u! n/ `6 Q. H
3.1 发现设备
; i8 m+ b% W* X7 P, X下载好单片机程序,给单片机上电。4 s! [# K+ M; u8 s- K
在笔记本设置中打开蓝牙,并点击添加蓝牙。3 b) ~: G' A* |' [

3

3

# O  h4 G( E- t4 ^% F) m1 d* V
+ w' o* H# E! X. g) P: V  O
: `8 F. b! ^/ n可以看到我们的设备HRSTM5 o4 R" m4 f1 w5 T
接下来使用我编写好代码:9 a3 v! |+ Y( s* b
import bleak.backends.dotnet.discovery as Discovery& j1 W5 l& P( j, D/ L6 s% v
import asyncio3 s4 I( t4 l: ?5 O
async def run():
; ^- D- A" {) @2 R4 n/ K    devices = await Discovery.discover()
! c6 E! Y4 M- A4 N6 E% _& K    for d in devices:) {2 w/ g9 C9 F, U3 M# x/ T8 J  O
        print(d)
& w: i6 o+ v0 A8 i7 F0 H) lloop = asyncio.get_event_loop()& q6 Z( k! \$ z. z' M
loop.run_until_complete(run())
7 L/ v, O9 ?6 f9 K8 [  ]
$ I3 Z$ |5 X+ G; `在输出窗口可以看到可以被发现了的蓝牙:
; `7 V& y  @! P! ~" s, {' tB8:7C:6F:47:81:BF: MiKettle6 Y! a! ~2 e9 ^; u
6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec')
. w- Z* X3 G  _2 }80:E1:26:00:68:7C: HRSTM
0 X' W4 F1 L# d6 w. N0 m' t
) M) L" C: u+ ^+ E# b: s# l我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。: ?5 W' w% ~$ i" h# ]

3 q4 [2 s$ M8 l; ?3 |5 j7 |3 z
( ], |% w* F8 F3.2 连接和发现服务
) C* A- r! r& e. `3 q* W: E* u% s接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务:
/ k% S6 b8 J* _, W. X5 F. f5 z0 basync with BleakClient(address, loop=loop) as client:
6 u$ Q$ `/ f$ g7 x" {! n    x = await client.is_connected()0 F$ ~6 M9 ~$ `. S; ]6 T, d
    log.info("Connected: {0}".format(x))
. d) s  `3 i8 F$ Z        log.info("[Service] {0}: {1}".format(service.uuid, service.description))0 l# F0 |0 q3 y9 C
        for char in service.characteristics:! C, P( _' j; |- i
            if "read" in char.properties:
7 f4 p( `7 e0 y                try:8 S7 M' H8 @) {. p
                    value = bytes(await client.read_gatt_char(char.uuid))  V* X$ T7 \* ]
                except Exception as e:/ e# E# o1 p6 k; x$ G
                    value = str(e).encode()
$ M+ T: i7 h3 u9 ?; ^            else:" K, T+ G4 n) [2 ~* G: l) ]0 v
                value = None  s. W$ g" C) O3 o' y
log.info(
1 R5 c( a) Y! e/ j2 h                "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(
! J& \4 m0 i+ ^+ U4 f1 a% L                    char.uuid, ",".join(char.properties), char.description, value
3 K1 L, l- E4 C" I8 |2 }- Z                )8 k! w: e! E1 v: l, i5 f
            )
+ J  j$ Y: K9 E+ y- e            for descriptor in char.descriptors:
9 S; [* ^- G4 a9 X- E                value = await client.read_gatt_descriptor(descriptor.handle)
6 C$ s7 y5 Q' K* X1 c# G- g0 @                log.info(
& ~$ e5 R0 }+ j: d/ e0 F                    "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(
; D6 E' g6 w) \. L                        descriptor.uuid, descriptor.handle, bytes(value)& V5 D* i/ B9 i9 S0 S# K
                    )$ A1 |3 a7 N/ _  J4 A  S8 G9 H
                )
% z/ ?$ r5 h6 I& T- Z) {5 t! h& M! P
输出的结果:
, r7 w; S% \4 ^- g$ k# ^2 {Connected: True4 s2 o) A! m# e7 T' R& q" c: I
[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile# J! s# e! i6 a! M+ E' b
         [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None
, L' N% ~0 _. p& j0 a; @                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'1 o: S- @% O' @/ C
[Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile; g: N" \6 q4 Q! a& \
         [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'
9 Y% R) w& ~, \1 D2 x- J+ D         [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'
6 s0 x/ p* e& z         [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'  k$ M+ i; H* g/ [6 L
[Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information2 I( {  x" H3 W% ~0 c
         [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'
  ?( n- m: l& x1 x, E0 [1 ~0 T[Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate3 R7 C& {( R' E3 j$ ^3 N
         [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None% C/ Z; k0 [% z
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'
6 u5 p( d; f" o& t         [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'1 C& s- D1 E2 v( U2 z( H
         [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None7 U* a8 F# Y/ k. O! h5 {, |* ~2 D

! D9 M0 C4 Z8 ^8 n, e- h; Z观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:
" R! s# ], R. u, E# Q: e/* UUIDs for Heart Rate Service */
( T) r2 I. X; n; j5 c/ }. P: u#define HEART_RATE_SERVICE_UUID                                        (0x180D)1 `5 q5 e0 i( @/ C2 n% Y& l
#define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID                   (0x2902)& u" \( g2 h. [) \  l
#define HEART_RATE_MEASURMENT_UUID                                   (0x2A37)
# [/ s' Q, S! P2 B#define SENSOR_LOCATION_UUID                                           (0x2A38)) R! {. H3 t; j4 w0 |: t
#define CONTROL_POINT_UUID                                             (0x2A39)8 D- t$ N4 [: L! f( @  K; F

4 d; d* F( O  g5 X/ n3.3 通知和获取数据
# [6 y: M4 {  V. O# k通过STM的蓝牙软件,发现软件是有数据传递的。
1 b  |- |, i7 i- H8 q& T, `" N# I

4

4

* y& m& \, I7 Z1 k' k8 H/ U% k, |, l4 y1 h

. q! L% n. d3 Y; Q" g# @0 ?( x6 ?其采用的方式是通知的方式,我是用了一下程序:
. u0 c4 \' e3 ]8 f
% ]" q; [5 A, A" E) Odef notification_handler(sender, data):" K) K0 f. W5 T4 Z- K
    # strs=data.hex0 a: ~2 m3 f& K4 }* g
    print(f"{sender}: {data}")# T8 |- E, |( C, o
    byarray = bytearray(data)
' y+ P% `, i2 X* ^; O. ~* {    print(byarray.hex())  i6 e3 @' B; f" S0 i4 W

* M4 w% H  N  u5 ~1 F* o. {async def run(address, loop, debug=False):, q  ^6 a, z* a1 R
    async with BleakClient(address, loop=loop) as client:5 y# _6 p0 _' j( W+ Z
        x = await client.is_connected()
5 w& D7 n; H' L0 v7 J        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)
, J9 z6 t" a) n) Y' A        await asyncio.sleep(5.0, loop=loop)
% {- A8 y" Y: K, p        await client.stop_notify(CHARACTERISTIC_UUID)
* l2 i8 J. Z" X8 w7 k$ w9 S/ Zif __name__ == "__main__":
  B" B9 h+ P3 V4 Q( n  S8 Lif __name__ == "__main__":2 A7 Y" v% \2 ~& K( V* {
    address = ('80:E1:26:00:68:7C')  #你的地址
2 m$ }/ M! y0 G: R: C    loop = asyncio.get_event_loop(): M8 k. |/ W+ I/ Z
    loop.run_until_complete(run(address, loop, True))
$ |  w7 w* w3 p& b& v
/ w9 B8 _, i! C2 y" u返回了一下数据:
$ [- c5 l9 b; I' d1 K00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04')5 c/ N; P. [2 A* X: z1 K
1f370014000004
6 t* X5 i/ f+ {. \5 F" H00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')& |4 J( e6 z$ I; Y  C
1f36001e0000048 ?" B$ l8 h6 T( o/ Z
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')" M9 H4 \+ Z/ s
1f340028000004
. N: E& A1 L6 j
( h$ v$ F/ K7 `/ L! q其中00002a37HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。
0 M8 a" n. }! d9 H9 c8 E, `HRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;
& X5 C9 }7 F8 V( K5 k: A* N! z4 q4 Z7 P; u. j' Q
4 小结8 B* F$ }4 k0 S. P8 ]: \8 u
以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?
& N$ n$ z6 R4 i; R我相信,在后面一步一步的代码解析,就会解释这些现象。3 I( ^) F3 W# p& b7 Z4 A, |
! a' J( c4 c2 ?6 t3 ]
& B2 v& h/ N1 m! ~& ]+ D

2 f7 l1 r' w  F

6 R- h& p7 U. o- i0 ]9 U
% P! ?( N, Z/ o$ N6 U$ `! h0 Z
收藏 评论0 发布时间:2020-5-23 16:48

举报

0个回答

所属标签

相似分享

官网相关资源

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