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

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

[复制链接]
ziziran 发布时间:2020-5-23 16:48
0 前言
- v/ O6 Z/ ]/ R5 L4 C- d. o自己的主要目的是学习BLE相关的知识,以及其具体的应用。因此不会像前一小节那样,组成那么长链路的系统。为最佳的学习BLE,就需要组成最小的闭环回路。
- G& p! x- ?* H( e" }5 j0 s0 w! }% |9 l
1 最小闭环回路' j# H" d% c+ o2 ?6 n2 g
最小闭环系统,就是STM32WB的开发板和笔记本组成的系统。现在基本的笔记本自带蓝牙。( J0 z' r1 z, F5 \

1

1
! \( M+ M; x. n) R' G+ F

) p7 [" A/ C2 p

9 i4 d' w* P4 X& }$ {1 Q1 K- Y$ C
4 h0 K) a& P# M, ^/ z- k
% M  _- [3 u& o" ^& a* @* s& O0 [( W5 Z+ a/ y1 b; W* _  Z
2 系统软件环境
& V! \* [$ @8 `2 t7 {8 G5 d在开发板中的软件使用的是:P-NUCLEO-WB55.Nucleo\Applications\BLE\BLE_HeartRate项目工程。/ j) P) ]/ E: ^9 @+ s
笔记本使用上位机是自己编写的python代码。( J! U. B4 ?$ T1 j7 M0 U8 }

2

2
! [6 v; R. M% A5 B

5 d) f5 s+ s9 w我们将开发板当作外围设备。将笔记本作为中心设备。
  |7 e. T: Q7 t5 L  ]# Q$ w/ E: Q8 j1 l; l
3 连接实验
( W! m& r* V. a* A5 D3.1 发现设备
! e' W* E9 ^8 D' {下载好单片机程序,给单片机上电。
- h0 m4 g% F) f! h在笔记本设置中打开蓝牙,并点击添加蓝牙。
2 w! W' N9 a$ u$ u

3

3
, W9 \8 c6 @4 c5 T& {& m

; G  K- q+ h% ?9 {2 g6 E3 B1 b# {
3 M3 x8 ?" d2 q; c可以看到我们的设备HRSTM。
, ~; X, M! b+ A+ D接下来使用我编写好代码:
; U! _: m, G) cimport bleak.backends.dotnet.discovery as Discovery
, d( m7 T' M/ t  h  rimport asyncio% U! X9 S' g; v  e5 Z; o$ G6 y
async def run():
9 z$ J+ G' P1 c3 Q1 S6 w) p    devices = await Discovery.discover()( O( q. O# v& e, y$ _+ \3 a+ f
    for d in devices:
/ G* Q( J/ U3 _/ H$ d        print(d)  Z2 F/ |+ j- ^' r/ q1 A) i' W
loop = asyncio.get_event_loop(), C5 D( A1 {3 Q: {# C0 {2 Y3 {+ L
loop.run_until_complete(run())* ~; f* E' z- ]2 N  X+ e
% L/ i3 J, e% T8 A5 B$ n, A5 |
在输出窗口可以看到可以被发现了的蓝牙:
8 Q' I8 ]$ @" _3 ~, tB8:7C:6F:47:81:BF: MiKettle/ x0 a0 W. ~. b  K
6B:96:A5:AF:06:A7: Apple, Inc. (b'\x10\x05Q\x1c\x82.\xec')
  O! H. E9 A/ J  @: K80:E1:26:00:68:7C: HRSTM) |1 w6 d" _4 p, h2 r
1 m; a* X+ K: s/ [( J3 g) _! o
我们也可以看到我们的蓝牙应用HRSTM。其中,一个很重要的东西就是设备的ID,这个是我们连接的一个关键,就和电话号码一样,而HRSTM就是持有人的别名。
' @* _. o* w: T+ c) v  s- M! X* z6 O  L

: H- G. l/ ^9 {7 u1 n4 f  {& L) `3.2 连接和发现服务
! S7 d, K* ~& }8 G接下来,我们应用上面的地址,来连接和发现一下HRSTM有哪些服务:
& B  t4 i  c0 h" O2 pasync with BleakClient(address, loop=loop) as client:
0 L. r; V8 T6 X% u+ z; T- k    x = await client.is_connected()
; u3 _9 i! f; A" d" W    log.info("Connected: {0}".format(x))
: Q! j: Q! `4 \7 ^        log.info("[Service] {0}: {1}".format(service.uuid, service.description))& N- B9 U& r, P% I; P4 R
        for char in service.characteristics:
2 ~1 [+ _0 ^" L: Z$ X% f6 r0 k            if "read" in char.properties:
3 ?2 R- i0 r" ~$ z6 A                try:1 Z7 Q, H( R% y2 B* O- e
                    value = bytes(await client.read_gatt_char(char.uuid))$ ]2 s: N5 `/ r; R; ]+ Q( t  Z
                except Exception as e:
1 O, a0 K: f8 f- Z                    value = str(e).encode()
( m7 }$ R5 [3 a  W% T            else:3 L& i: ?) D) e+ u& F: t, c, H
                value = None9 F; H* a2 X8 `8 ]  B: |
log.info(
9 [; T0 B. V0 l( b4 Y                "\t[Characteristic] {0}: ({1}) | Name: {2}, Value: {3} ".format(' g& t3 {+ r4 d  G6 P9 E, H% \
                    char.uuid, ",".join(char.properties), char.description, value  G7 [' M( O: O1 z5 b9 I) Q
                )( r6 B! B! H+ F- h1 J0 ]1 P  I
            )
0 r! U; |1 Y/ q4 j            for descriptor in char.descriptors:* ^! i, j$ t. a& b! [
                value = await client.read_gatt_descriptor(descriptor.handle)
2 P( `& N, h, D6 x/ n                log.info(% C) J+ [' l$ u* w* l4 P: g
                    "\t\t[Descriptor] {0}: (Handle: {1}) | Value: {2} ".format(
9 ]5 d1 [- g& @# Z8 c" h                        descriptor.uuid, descriptor.handle, bytes(value)
) k0 L# o7 D* P8 i/ q7 N                    )
. b/ P, Q( o: B% y, U5 H8 ~( O                )9 U9 D7 l( k6 x* F1 y% Q# @$ C- n

" s  _, @  j8 r4 [& r2 X输出的结果:3 F, F7 Q, f/ b6 q* h
Connected: True
  z, \: f3 M: O  i6 R4 q! m6 S[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
5 y+ @3 v& S5 g% O8 e         [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb: (indicate) | Name: , Value: None& J2 W5 U; O/ n# J' H  g0 H
                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 4) | Value: b'\x02\x00'
% z9 z3 \: w) L+ {$ j9 U3 Z) F# ?/ R[Service] 00001800-0000-1000-8000-00805f9b34fb: Generic Access Profile, R, S: n$ o; V4 E4 f% i
         [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'STM32WB'3 D8 A  S* A2 R# Q6 p+ i2 b8 d' Q
         [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb: (read,write-without-response,write,authenticated-signed-writes) | Name: , Value: b'@\x03'$ j% X1 [: Z; B9 z4 Q' u1 `
         [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\xff\xff\xff\xff\x00\x00\xff\xff'( [0 g/ }7 Z2 d6 P. C, G
[Service] 0000180a-0000-1000-8000-00805f9b34fb: Device Information
6 g& Y; G* W+ _: \; D         [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'STM\x00'' U3 D* t# X6 ]5 u8 `( _* ^
[Service] 0000180d-0000-1000-8000-00805f9b34fb: Heart Rate
% s: Y: t. {$ V/ _* y1 R2 I         [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb: (notify) | Name: , Value: None
# l$ _* v! w+ `! M- u/ v; s; ~5 I                   [Descriptor] 00002902-0000-1000-8000-00805f9b34fb: (Handle: 18) | Value: b'\x00\x00'9 {& H& Q! y% m2 A7 L
         [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb: (read) | Name: , Value: b'\x04'9 ]8 K6 V( F3 i8 w1 I9 @( m9 r( `) D
         [Characteristic] 00002a39-0000-1000-8000-00805f9b34fb: (write) | Name: , Value: None
" V  v( s. o% o, [6 I6 x
  O- _/ z. l; d1 c6 X观察,返回的信息,我们大致可以通过,服务、特性、描述等知道其性能和功能。其中,发现UUID都是单片机中定义好的,在UUID.h 文件目录下:
' w  z  q: ^& b4 j8 F/ ?/* UUIDs for Heart Rate Service */( D; Q* l  w5 P, K! d( H7 E$ C
#define HEART_RATE_SERVICE_UUID                                        (0x180D)
3 ]' h4 x9 [$ n) U* N. w#define CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID                   (0x2902)
* e) H0 A: B1 Y+ x7 Y#define HEART_RATE_MEASURMENT_UUID                                   (0x2A37)
2 i/ T3 e! h) R. g  C#define SENSOR_LOCATION_UUID                                           (0x2A38)/ r1 o8 s# [+ \1 q
#define CONTROL_POINT_UUID                                             (0x2A39)
0 G; l" q9 q' Z0 x- D2 d' ?) ]% P' E% ~: `, v& z8 N0 ^
3.3 通知和获取数据
1 y% Z( u% C2 u( s6 {通过STM的蓝牙软件,发现软件是有数据传递的。
( S0 K  Y/ f; l; v( }4 Q

4

4

) i; [" k# n. s- R
5 ?# ]  r* v" a) B* t  E' S) }! G% {# Q" x/ S0 x
其采用的方式是通知的方式,我是用了一下程序:( z  C+ x" y/ ^
) {6 E: ~4 D0 I$ ^7 R
def notification_handler(sender, data):. n" A( j0 w9 b2 c' l
    # strs=data.hex
7 d# X3 B+ }4 u6 X; t    print(f"{sender}: {data}")
! {$ r$ f, s! E    byarray = bytearray(data)
# P  o" d: E. ]6 T+ Q( I    print(byarray.hex())/ Y0 e- O- p4 ?0 [% J7 ^* D5 i& W. [! n
' @" ]6 B; V7 n+ E
async def run(address, loop, debug=False):
/ ~! U6 t+ `+ }+ T; g# D    async with BleakClient(address, loop=loop) as client:* s$ r* M2 u: e" E
        x = await client.is_connected()/ E% L- d& ^  N# y9 a3 \5 r/ F
        await client.start_notify(CHARACTERISTIC_UUID, notification_handler)% L- m$ ^9 J  Y! y0 K# T3 y
        await asyncio.sleep(5.0, loop=loop)4 M7 J5 X/ a) Z5 [9 v
        await client.stop_notify(CHARACTERISTIC_UUID)
( J; k0 x6 K: c4 _/ A# ^, O8 hif __name__ == "__main__":
8 y( ]& Y1 G; _2 e- ?, G# yif __name__ == "__main__":
( S) i/ H. f# E  c3 Y7 X% F0 h    address = ('80:E1:26:00:68:7C')  #你的地址
& C2 W/ @7 R9 A: \    loop = asyncio.get_event_loop()3 n3 N* `. t4 {7 T
    loop.run_until_complete(run(address, loop, True))/ x1 f) x  j3 X! z. T0 M4 ?# F
' f$ V  R) p! X' u/ j; ~
返回了一下数据:
. W  ?8 J6 `4 ?+ E( _9 Y+ ?. Q00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f7\x00\x14\x00\x00\x04')) E/ f+ a% o% M1 }- \, |
1f3700140000043 y0 V) t& ]; Z5 S" W  [
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f6\x00\x1e\x00\x00\x04')' G: u" A0 O7 s" R2 |1 f
1f36001e0000047 E4 {9 g" O1 v
00002a37-0000-1000-8000-00805f9b34fb: bytearray(b'\x1f4\x00(\x00\x00\x04')  w7 t0 \7 D7 P( f, W
1f340028000004
. O1 r2 X2 y* k& X1 q5 ]. i- r4 ?( }! b) S* N3 \
其中00002a37是HEART_RATE_MEASURMENT_UUID ,数据是十六进制的1f36001e000004,其中0x36是心跳,1e是能量消耗,我将能量变化修改为,每次+10,从每次读回的值就可以看到。
5 z% t& [, N8 Y. @6 j4 XHRSAPP_Context.MeasurementvalueChar.EnergyExpended += 10;/ Q8 Q: w& a: [- G; m
& {* F! o, s, W3 C
4 小结
3 P: Z% q- H/ ~6 A, C5 N( U: T/ P以上步骤,从发现蓝牙,连接蓝牙,获取蓝牙服务,以及获取数据。其实,实验中还有许多的小问题,比如指示灯的闪烁,为啥STM官方的APP可以直接连接,自己的却不行?. M9 I) E8 d" k2 T/ p) b  i$ [
我相信,在后面一步一步的代码解析,就会解释这些现象。
4 y* ~- o# P. G0 P% ?, S4 P. c+ m. c; ?( K( S

2 P% j% C2 _* j& R$ n% l" w/ N* T# m2 x5 Z& x/ ?0 m

0 [( F$ A- U6 K, R, f7 P, o& I, s% f7 I5 P9 W! P, |
赞 收藏 评论0 发布时间:2020-5-23 16:48

举报

0个回答

所属标签

相似技术帖

官网相关资源

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