STMCU小助手
发布时间:2024-1-18 18:34
|
01前言) Q" m' z- r' S7 P6 ~. t4 b( ? 本文档指导用户快速地对 BlueNRG SDK 有一个直观、清晰的认识,了解其软件架构,以便顺利地学会利用 SDK 开发自己的用户固件。 本文档所述 SDK 为 BlueNRG-LP/LPS 芯片的 SDK。阅读本文档前,用户应先了解BlueNRG-LP/LPS 芯片的一些基本特性,以及其配套开发板的烧录方式。 $ r1 d) p( W/ R, H. C5 G) F 02SDK 目录/ j. C+ `5 s; t2 Q8 ^9 Z: Z7 \ 从 ST 官网下载 SDK 的安装包,成功安装后,即可获得一个 SDK 目录。见图 1: - P" z1 Z, q- O3 K* U$ o/ p
图1.SDK 目录 % c" K$ W+ @2 i7 ?# F' s 各个目录的功能说明见表 1:
表1. SDK 目录说明 % ]% H- @3 ~) T1 {' o+ f ?! Z" Q6 z4 R BlueNRG SDK 安装目录为用户工程师开发 BlueNRG 平台提供了一个便捷的入口,举例来说,有以下几个场景: 1. 硬件工程师设计 PCB 前,可通过 Docs 目录找到硬件设计指导文档。完成 PCBA 制作后,可自行使用 Navigator 工具通过串口烧录 Firmware 下的应用固件,验证板子功能。 2. 当工程师想用板子进行功耗、射频测试时,也可在 Firmware 目录下找到合适的已经编译好的固件(测 SOC 蓝牙功耗可用 Beacon,测射频参数可用 DTM)+ J$ b0 l) a: V8 I, Z% F s2 d9 L0 ` % K5 b! x7 J+ M: M$ x x5 A- Z1 \ 3. 固件工程师可在 Projects 目录下找到丰富的例程,并且可使用 KEIL、IAR、WiSE 任一个IDE 打开工程、编译、下载。) T4 q1 H% ^9 q ) P% v5 k3 |- A" x6 l _* N2 [ 03SDK 例程 SDK Projects 目录包含了以下三类例程: 1. Periph_Examples:包含了芯片外设驱动例程。 2. External_Micro :包含了外部单片机的例程,应用于 BlueNRG 芯片在系统中作为协处理器的场景。 p# N7 b) F5 S: T! z 3. BLE_Examples :包含了蓝牙相关的所有例程,这些例程的工程特性展示如下:
表2. BLE 例程说明 + _: ~, Z* t k2 g6 ^, U( L7 N X2 |) O! d& ~9 T 04快速实现用户固件功能 本章节指导用户如何快速地在 SDK 中找到相应的 API 接口和位置,以便掌握在 SDK 例程上添加自己的配置和用户逻辑代码的方式。 在对 SDK 提供的例程的功能有所了解之后,假设用户面临的一个开发任务是:' q5 S4 B8 n$ u% G. W0 u 1. BLE 从机功能,包含以下配置:. ], |% y# p+ b" L0 z a. 一个服务,一个特征,特征具备 Write、Notify 属性( Z: D2 P4 F$ L% @6 s b. 设备广播名为“Hello” 2. 使用手机 BLE 工具和设备通讯,打印通讯过程产生的数据, z3 |2 c& x) E: V/ Z 3. 自定义协议,实现以下功能:9 c: b3 ^* ^$ ?% o, |5 | a. 控制 LED 亮灭( O/ l8 R# R' `& y' Y* U6 s$ Z9 f J b. 定时 1s 上传心跳包,内容为连接后的秒计数值 c. 每次按键上传按键事件通知 & j K& u+ \; t ^' ]- g" i3 e 基于以上任务,我们可以选择 BLE_SerialPort 工程作为基础工程并以此来进行固件开发。) o, t3 K' w {+ z% h& r 4.1. 验证原始工程" U9 D0 r7 ?0 D0 e( q$ h 在添加用户代码之前,我们最好先验证了原始工程(BLE_SerialPort)的功能,确保开发环境正常。新建一个用户工程目录,比如,test_sdk1.3.0,然后从 SDK 目录拷贝以下文件到我们的用户工程目录,见图 2:7 J$ _' F% r5 M5 P; h1 | ! e! X' w' }9 L/ D9 c
图2.用户工程目录 打开 Projects > BLE_SerialPort 的 Keil 工程,勾选“Browse Information”选项,以便使能工程内函数的跳转,同时选中 Server 工程配置,见图 3,图 4: # K+ S" ^: }3 {# A5 I2 P% ?) `
图3.Browse Information 9 T2 R# D) p5 r. a9 O7 [% f( C
图4.选中 Server 工程配置 编译、下载工程到开发板,工程运行起来后,应能见到以下打印信息:
图5.BLE_SerialPort 工程 LOG 信息 0 ~! [4 H' w6 Y8 m( r* Q% T" ?2 S2 m4 o 使用 STBLE Toolbox 工具扫描该设备,应能看到设备名为“Sport_LP”,见图 6:5 o1 o0 X: R! s. K3 N# T o
图6.STBLE Toolbox 扫描页面 4 N1 @3 f' Q% L8 P' q+ X( T0 G8 G 至此,原始工程已经正常运行起来了。该工程实现了自定义服务、特征的功能,并能通过串口和手机进行数据的收发。要完成此次开发任务,我们只需在特定位置修改一些代码即可。0 H) G: k- K, r! R # E% T, Y3 r+ ^ 4.2. 配置 BLE 从机功能1 q" V' N( c2 h2 z$ F 原始工程有两个特征,一个负责发(TX_CHR_UUID),一个负责收(RX_CHR_UUID)。按照要求,我们需要把他们合并为一个可以收、发的特征。图 6 演示了定义新的特征 UUID 并注释掉旧的两个特征 UUID 的方式:+ s# B; o, T+ G/ I5 h. m 8 a0 }$ ^3 n+ a; c. U/ x3 }
图7.特征 UUID " x3 F# s3 {3 ?: z8 n协议栈提供了 ble_gatt_chr_def_t 类型结构体,用户可以定义一个结构体变量并赋值,以此来声明一个特征。图 7 展示了我们所需的特征配置的相关赋值过程,图中可见特征的 UUID 声明,特征 notify、write 属性声明,特征的特征描述符声明等信息。另外,旧的两个特征应该注释掉。
图8.定义特征 4 u2 W) u: R9 f' u2 h( H将新的特征配置赋值给服务声明,特征的数量修改为 1 个: " M, m$ z# L4 ^1 R( F
图9.特征声明赋值给服务声明 上述服务、特征相关的数据结构配置完毕,我们还需要将这些配置通过 API 传递给协议栈。 # z2 S2 {6 ^5 H# }0 h 首先,需要先定义一个新的句柄,所谓句柄,简单地说,用户在进行数据收发的时候,需要选择在哪个特征上进行数据收发,此时便需要句柄来指定特征(句柄本质上便是 attribute 的handle 字段)。原来的两个句柄也要注释掉,见图 10/ W9 v0 M, ]+ \ g) S& [ . S, b* c+ f8 L8 [0 K" U/ G6 y2 j% M8 Y
图10. 句柄 然后,将上文定义好的服务、特征通过 aci_gatt_srv_add_service 函数一次性传送给协议栈,协议栈对这些配置进行解析、构建完整的 ATT 属性表,保存在内存中。之后,用户可使用aci_gatt_srv_get_char_decl_handle 接口获取已分配好的句柄(见图 11),此后的数据交互过程将频繁使用该句柄。" u( f2 a0 F& t3 i( }* G2 P- G9 T( b1 f & `/ ^+ s) ^& c
图11. 获取句柄 至此,GATT 相关的配置已经完成。但是,由于上层大量引用了旧的两个句柄进行数据收发,因此此时编译会出现比较多的错误,此处暂不处理这些错误,先完成其他的 BLE 配置。 0 H3 U) Y% B6 y) g4 B6 R/ x 接下来修改蓝牙地址,并修改广播名,见图 12: 1 n+ r* ], L! c5 |
图12. 蓝牙地址和广播名 " k& k' |/ U2 n7 ?; B: A8 g% C5 ~ 广播名的长度改变后,应注意指定其长度: ' P) e; R+ f L+ O
图13. 广播名长度 . O& I- Z2 x& E LOCAL_NAME 设置的是广播包里的设备名,当设备连接成功后,主机会从 GAP Profile 的device name 特征里获取另外一个设备名,此处应保持这两个名字一致: 4 Q$ L- p$ C/ k D; ^
图14. 设备名 * m; m: ?& u) v! j
图15. 设置设备名 , I- e6 _5 X3 m, v7 s- e8 z0 B 至此,关于蓝牙的应用配置即告完毕。接下来可进行数据通讯相关的配置、实现。 * ]; L- Z9 t# X 4.3.和手机进行通讯 上一小节配置完从机功能后,编译会产生大量错误,是因为 BLE 的通讯过程会比较多地引用旧的句柄。循着解决这些编译错误的操作,我们能了解到 BLE 通讯的过程。具体操作如下:) B; [0 _. K2 t- s; S. g 全局搜索旧的发送句柄(TXCharHanlde),我们找到了用于数据发送的协议栈 API,修正之 :( r& M6 I3 Z" T- d! e - b1 D; F6 `+ g6 F" l) ^/ B/ m z
图16. 发送 Notify 手机使能订阅后,会通过图 17 的回调函数通知上层。此时应该修改为新的特征句柄,同时,添加一些打印指示 notify 的使能、禁用状态:3 Q1 v3 t, Z2 F: u- D$ k6 z3 S $ u' h7 \6 `6 H, i y6 i8 P# j. f, y
图17. 使能订阅回调 # M1 {3 w9 f( H. v添加新的特征句柄全局变量声明,注释掉旧的: y q( F/ |/ g
图18. 句柄声明 : A2 A* _& r! i* _# p- l( l& _* ]9 ~; Y# n 关于旧的发送句柄(TXCharHanlde)的问题已经全部解决。继续搜索旧的接收句柄(RXCharHanlde),我们应能找到设备接收手机数据的函数接口,将其中的句柄替换为新的特征句柄,见图 19:
图19. 数据接收回调函数 " h! w' N1 }' g7 K$ T至此,我们应该能通过全部编译过程,并且已经找到了数据发送、接收的位置。此时可以在这些位置添加数据发送、接收的打印函数。接收数据的用户接口见图 20:8 Y/ g: J3 k1 C! r( v9 [- W4 I/ B
图20. 用户接收 BLE 数据 8 B' ^ |4 J1 }+ O* [ 关于发送数据,原始工程实现了以下处理流程: 1. 从串口接收数据/ W9 G: H& J. a6 d 2. 解析数据为命令并缓存这些命令 3. 通过轮询的方式,不断将命令缓冲区里的命令发送出去 6 R% K; I- V4 ]. m8 h 该处理流程不适用于我们的任务要求,我们需要先取消这部分功能,见图 21
图21. 取消原有的数据处理流程 * U+ U- b9 t. W n7 ], Z( i# j9 e& d' j- Y9 N0 |- h+ l8 p6 K 然后设计自己的发送函数,见图 22: & q# H* F& K# ]. D- N. s" ?( P
图22. 自定义 BLE 数据发送函数 " \" E( Y+ _9 |, u5 ^ 至此,蓝牙的通讯功能已经全部实现完毕。用户可通过:# J1 h* {' E7 m; Q • Data_Received()接口接收数据/ g- l, q; v/ ?! \ • user_send_data_over_ble()接口发送数据 4.4.添加其它功能 根据任务要求,我们还需实现下面三个功能:4 q9 H5 B5 n% u' J3 O& c7 R- T9 T 1. 控制 LED 亮灭; t- f5 c9 P* s! l7 C0 s 2. 定时 1s 上传心跳包,内容为连接后的秒计数值/ y7 I u: l H; C 3. 每次按键上传按键事件通知下面开始逐个实现: _2 s+ b# I7 b1 F 4.4.1. 控制 LED 亮灭 首先,实现 LED 亮灭处理函数,5 ~; F' j" G. h # s6 N, q* @) f4 Q. W$ `$ |
图23. LED 命令处理函数 0 C b% X( s( \* j/ o0 Q) r 将其添加到 BLE 数据接收函数处,见图 24。LED 控制功能实现完毕。 6 }- J( E8 C/ K% s
图24. 接收数据后进行 LED 命令处理 ( {9 l. `$ k7 I$ |, x 4.4.2. 每秒上传心跳包 首先,实现心跳上传处理函数,实现当设备连接后,每秒上传一个 4 字节的计数值,并使用0xaa 作为命令字。见图 25:+ [9 o6 G: c4 Y4 i8 c3 v% X8 Q
图25. 心跳上传处理 $ s. V9 Z3 a+ g, w I& h* u! \3 M, @* `( N5 J& S 将心跳处理函数添加到系统任务处理函数 App_Tick 中,App_Tick 会在 main loop 中不断地被调用。心跳包需要在蓝牙连接成功并且使能了订阅之后才可以发送。另外,使用 timeout_flag变量来控制其每秒只被调用一次,实现方法如下: 6 g0 b: r9 Q3 A! ~! }( h! ~ S
图26. 心跳处理 ! l: f5 j R! [5 Z- _1 ?3 i1 y( R4 K, h- C2 ~2 K. C 上述 timeout_flag 变量需要使用每秒循环的软件定时器来周期性置位。软件定时器的应用方式很简单。5 Q0 _" {2 h5 x* X 首先,实例化一个定时器,并定义超时回调函数:! g. B9 c- q$ r& N 5 ^6 p& l! K0 _$ T) t' n# p4 p+ q
图27. 软件定时器实例化 $ e" G5 y4 L) _9 p9 I, z* {6 f' q 然后,在 Serial_port_DeviceInit 函数的末端位置注册超时回调函数并启动定时器。) T, I& C# C0 T% C; { # }! l; ?- S$ h6 w* {# n6 C# j$ s& C
图28. 启动定时器 % A# Q. |4 w6 `' H: K% T4.4.3. 上传按键事件 首先,实现按键回调函数,该函数在按键按下时被调用。发送按键事件前,应检查此时蓝牙是否处理连接、已订阅状态。见图 29: 3 H5 E& K) ]4 O! h
图29. 按键回调 按键中断服务函数中调用: 0 x3 N4 q9 v) ]2 p
图30. 按键中断服务函数 # \2 m6 f! f7 N 至此,开发任务的要求已经全部实现完毕。接下来进行功能验证。: [, t5 ]8 e2 G. G0 d. _% e 2 p7 }" O5 @. ^( u 4.5验证功能% [, J6 _9 o; \" Q) r 用户工程运行起来后,用 STBLE Toolbox 扫描,可见广播名已经修改过来了。+ D1 _: t3 y* a# F) D) X , \3 j; u8 {# g* d' z5 t
图31. 用户工程广播名 连上设备并点击 Notify 开关以使能订阅,可观察到底部已经开始接收到设备的心跳包数据(以 AA 开头的 5 字节数据),该数据每秒钟变化一次,见图 32:$ Y. S* f% U0 `3 t* u 0 I S' y# a% o+ g- M
图32. 使能订阅 * X8 l" P$ i4 C 通过 LOG 也能观察到心跳包发送情况,此时如果按动按键,也能观察到按键事件已经发送:
图33. 用户工程 LOG , k4 ?9 s2 n/ s0 ]7 X05小结1 g$ |; x: l& {+ W4 a3 r 跑完了上述用户任务开发的流程后,相信用户对 BlueNRG SDK 的软件架构应有所理解了。BlueNRG SDK 的软件层次架构为 STM32 典型的三层架构,分别为驱动层、中间层、用户层: 9 P* D( z8 d- ^
图34. 软件层次架构 # k# G; J- C; v0 s上述添加用户功能的整个过程,其实只改动到了用户层的功能,用户层包含以下几个文件: I3 Q9 i& I# g
图35. 用户层文件 ; I, t4 D) P i$ ]1 ~ k2 ~+ }2 h5 F d8 l( J: i4 U 这些文件的含义是: • serial_port.c,用户应用逻辑的实现( H6 U/ a, M3 D# k( y2 W • BLE_SerialPort_main.c,程序入口,程序主流程+ F' O1 J9 `( h9 A • gatt_db.c,BLE GATT 层功能的实现 • rf_device_it.c,存放所有的中断服务函数 上述用户固件的功能,大多都在 serial_port.c 中实现。BLE_SerialPort_main.c 函数则实现了系统的主要流程。简单来说,BlueNRG SDK 的裸机系统即是一个前后台系统。蓝牙事件、按键中断等属于前台处理,负责置位相关标志位和状态,main 函数的 while1 属于后台处理,运行蓝牙协议栈、用户任务处理等后台任务,见图 36:" @3 S2 x: O& A: y1 C4 X
图36. 系统流程 # f. l/ c7 w' D* G. A. K$ hBlueNRG SDK 中的绝大多数例程都使用了本文档所述的软件架构,即前后台系统。该软件架构比较简单,优点是用户能非常快速地掌握其流程,能够依据本文档的示例快速构建自己的用户功能。缺点是功能比较简单,用户需要在此基础上再添加一个调度器以应对复杂功能的要求。7 } b# e$ T! g g# L& w5 g9 D 9 j0 S! A5 d2 h% ` 5 m" j" d! ]/ i# e- ]9 Z/ Z 转载自: STM32单片机 如有侵权请联系删除! o+ Y l) m2 b; Y- e6 } % {; L% R( P# t4 F4 M4 y4 I2 U4 c 3 Z5 a( O4 Q& l5 h! L7 q |
【经验分享】STM32语音识别的智能蓝牙音箱(源程序+原理图+PCB+设计说明书+PPT)
想找个ST芯片
[GPIO] 使用新型抽象开始C++嵌入式编程,从GPIO开始
技术手册stm32f1xx中的一个小问题
【经验分享】STM32 HAL库移植FreeModbus详细步骤
【逢7发帖赢大礼】STM32开发之IC门禁卡UID读取方法!
实战经验 | Keil工程使用NEAI库的异常问题
经验分享 | FDCAN数据段波特率增加后发送失败的问题分析
STM32几种流行开发环境的优缺点
好用软件推荐-TouchGFX Designer
微信公众号
手机版