STMCU小助手
发布时间:2024-1-18 18:34
|
01前言6 p7 {" S j \: ?5 G 本文档指导用户快速地对 BlueNRG SDK 有一个直观、清晰的认识,了解其软件架构,以便顺利地学会利用 SDK 开发自己的用户固件。 3 o$ p- V. S0 [4 F2 c0 P 6 b; k5 C+ x Q' d' F: U; p6 g 本文档所述 SDK 为 BlueNRG-LP/LPS 芯片的 SDK。阅读本文档前,用户应先了解BlueNRG-LP/LPS 芯片的一些基本特性,以及其配套开发板的烧录方式。 6 p q- s+ U9 W% q 02SDK 目录6 G/ c, ?( K! G% b1 Q- W 从 ST 官网下载 SDK 的安装包,成功安装后,即可获得一个 SDK 目录。见图 1:8 O: D- E* b( K) J& i5 ]0 {, m 1 b0 M3 e8 K& d2 p
图1.SDK 目录 各个目录的功能说明见表 1:% |5 c$ Q" J y1 f8 p7 d; p
表1. SDK 目录说明 5 @( J/ e) @2 G& m% c3 g* D! i% X. B9 J2 q BlueNRG SDK 安装目录为用户工程师开发 BlueNRG 平台提供了一个便捷的入口,举例来说,有以下几个场景: 1. 硬件工程师设计 PCB 前,可通过 Docs 目录找到硬件设计指导文档。完成 PCBA 制作后,可自行使用 Navigator 工具通过串口烧录 Firmware 下的应用固件,验证板子功能。# k+ e4 G# E+ x9 Y 3 n0 B8 z& _# q6 Q7 Z8 h, n) K. B 2. 当工程师想用板子进行功耗、射频测试时,也可在 Firmware 目录下找到合适的已经编译好的固件(测 SOC 蓝牙功耗可用 Beacon,测射频参数可用 DTM)5 Z- a# ` p$ m* @- i. b; R- S % T) {' ^. ]. j' K- x 3. 固件工程师可在 Projects 目录下找到丰富的例程,并且可使用 KEIL、IAR、WiSE 任一个IDE 打开工程、编译、下载。( U7 [" n4 W# B) w7 f 6 V- [4 f# I, ~ 03SDK 例程 R' j# m5 H$ l$ ?) v( ` SDK Projects 目录包含了以下三类例程:" G7 h5 S! c! d9 P0 O& D7 D 1. Periph_Examples:包含了芯片外设驱动例程。 2. External_Micro :包含了外部单片机的例程,应用于 BlueNRG 芯片在系统中作为协处理器的场景。 3. BLE_Examples :包含了蓝牙相关的所有例程,这些例程的工程特性展示如下:; ?' c7 `' }+ e+ G
表2. BLE 例程说明 & S' W0 i$ h; Y% j7 ]; i* q04快速实现用户固件功能# O6 H1 a4 E; @9 T2 O6 i2 q 本章节指导用户如何快速地在 SDK 中找到相应的 API 接口和位置,以便掌握在 SDK 例程上添加自己的配置和用户逻辑代码的方式。 $ {- E \% |; U u% a 在对 SDK 提供的例程的功能有所了解之后,假设用户面临的一个开发任务是:1 c; y1 t8 |2 P h: V$ @7 K+ B1 I 1. BLE 从机功能,包含以下配置: a. 一个服务,一个特征,特征具备 Write、Notify 属性 b. 设备广播名为“Hello” 2. 使用手机 BLE 工具和设备通讯,打印通讯过程产生的数据' o" J( m4 x( Y7 G 3. 自定义协议,实现以下功能: a. 控制 LED 亮灭" t! z7 i$ V3 a; V; ^ v, | z b. 定时 1s 上传心跳包,内容为连接后的秒计数值 c. 每次按键上传按键事件通知7 H+ B/ J3 E$ c, w5 o, l 0 s4 y; g( `3 s8 j 基于以上任务,我们可以选择 BLE_SerialPort 工程作为基础工程并以此来进行固件开发。' u+ ?# U* X6 h# \2 ~4 Q$ Q/ c 4.1. 验证原始工程! |; q: {. S/ z+ V: t 在添加用户代码之前,我们最好先验证了原始工程(BLE_SerialPort)的功能,确保开发环境正常。新建一个用户工程目录,比如,test_sdk1.3.0,然后从 SDK 目录拷贝以下文件到我们的用户工程目录,见图 2:
图2.用户工程目录 . u* G7 X, Z5 S/ `8 Do8 u: d# I# N) {5 n 打开 Projects > BLE_SerialPort 的 Keil 工程,勾选“Browse Information”选项,以便使能工程内函数的跳转,同时选中 Server 工程配置,见图 3,图 4: * d6 l' @ s4 R! c9 G% x* N3 i7 I
图3.Browse Information " h6 {" j. B( ^5 c- ~, R
图4.选中 Server 工程配置 5 L6 a/ h) ^: m& A' H% r3 ? t9 [ 编译、下载工程到开发板,工程运行起来后,应能见到以下打印信息:6 @; l" l1 L+ i% K2 J ! k: C" S" p% J
图5.BLE_SerialPort 工程 LOG 信息 $ u B% S; K0 ?, E, w3 D; b/ y 使用 STBLE Toolbox 工具扫描该设备,应能看到设备名为“Sport_LP”,见图 6:8 F# k+ [) \" S' `) t5 n- V8 B
图6.STBLE Toolbox 扫描页面 & p, A0 w* Z) o* q9 J( r/ f 至此,原始工程已经正常运行起来了。该工程实现了自定义服务、特征的功能,并能通过串口和手机进行数据的收发。要完成此次开发任务,我们只需在特定位置修改一些代码即可。1 W7 K+ s8 \, v2 m1 j- i 6 n, G3 E0 z, h 4.2. 配置 BLE 从机功能6 u+ r' P% w8 c' B+ }6 } 原始工程有两个特征,一个负责发(TX_CHR_UUID),一个负责收(RX_CHR_UUID)。按照要求,我们需要把他们合并为一个可以收、发的特征。图 6 演示了定义新的特征 UUID 并注释掉旧的两个特征 UUID 的方式:% {8 j( o7 L" e # r0 U u7 [ G0 m( c
图7.特征 UUID # O4 A$ s" \) P4 ]; j 协议栈提供了 ble_gatt_chr_def_t 类型结构体,用户可以定义一个结构体变量并赋值,以此来声明一个特征。图 7 展示了我们所需的特征配置的相关赋值过程,图中可见特征的 UUID 声明,特征 notify、write 属性声明,特征的特征描述符声明等信息。另外,旧的两个特征应该注释掉。 + k' |& ]" A9 ]4 D% _
图8.定义特征 将新的特征配置赋值给服务声明,特征的数量修改为 1 个: b: F5 }& n3 o1 @& }3 d
图9.特征声明赋值给服务声明 " ~. U- H' u- N% N, u5 t 上述服务、特征相关的数据结构配置完毕,我们还需要将这些配置通过 API 传递给协议栈。 首先,需要先定义一个新的句柄,所谓句柄,简单地说,用户在进行数据收发的时候,需要选择在哪个特征上进行数据收发,此时便需要句柄来指定特征(句柄本质上便是 attribute 的handle 字段)。原来的两个句柄也要注释掉,见图 10
图10. 句柄 * n$ } N8 K5 J" L 然后,将上文定义好的服务、特征通过 aci_gatt_srv_add_service 函数一次性传送给协议栈,协议栈对这些配置进行解析、构建完整的 ATT 属性表,保存在内存中。之后,用户可使用aci_gatt_srv_get_char_decl_handle 接口获取已分配好的句柄(见图 11),此后的数据交互过程将频繁使用该句柄。1 q) H* h! x9 v/ K9 `6 a
图11. 获取句柄 0 A5 ^: l' @8 l1 N5 f& _0 }至此,GATT 相关的配置已经完成。但是,由于上层大量引用了旧的两个句柄进行数据收发,因此此时编译会出现比较多的错误,此处暂不处理这些错误,先完成其他的 BLE 配置。 接下来修改蓝牙地址,并修改广播名,见图 12:: i6 P! J% Q$ H% h2 }: z: u
图12. 蓝牙地址和广播名 5 l. E; l& o( n/ w# T4 T 广播名的长度改变后,应注意指定其长度:+ ^" X, N( F/ y$ n N5 Q , O6 V: t: A. g* p6 O. ]2 P
图13. 广播名长度 9 e! ?" Z5 c& BLOCAL_NAME 设置的是广播包里的设备名,当设备连接成功后,主机会从 GAP Profile 的device name 特征里获取另外一个设备名,此处应保持这两个名字一致:9 B. A0 `0 q0 G+ m. m 3 e7 \9 \- I0 @( P; x0 b+ e
图14. 设备名 / {9 F7 ]0 E( d/ f. T
图15. 设置设备名 至此,关于蓝牙的应用配置即告完毕。接下来可进行数据通讯相关的配置、实现。 4.3.和手机进行通讯 上一小节配置完从机功能后,编译会产生大量错误,是因为 BLE 的通讯过程会比较多地引用旧的句柄。循着解决这些编译错误的操作,我们能了解到 BLE 通讯的过程。具体操作如下:7 f& J+ H* @# z9 P1 D% C 全局搜索旧的发送句柄(TXCharHanlde),我们找到了用于数据发送的协议栈 API,修正之 :' h# P( A1 H7 a9 G1 b% _) ] e ) ~' Z" L9 L: y- U
图16. 发送 Notify 手机使能订阅后,会通过图 17 的回调函数通知上层。此时应该修改为新的特征句柄,同时,添加一些打印指示 notify 的使能、禁用状态:
图17. 使能订阅回调 ; D3 y4 O+ d- t4 t& l" C$ Y添加新的特征句柄全局变量声明,注释掉旧的:6 x- ~2 u/ ?. r% n9 \6 r- D7 | 0 M1 r/ ]3 j1 ]# A2 `7 I& C
图18. 句柄声明 关于旧的发送句柄(TXCharHanlde)的问题已经全部解决。继续搜索旧的接收句柄(RXCharHanlde),我们应能找到设备接收手机数据的函数接口,将其中的句柄替换为新的特征句柄,见图 19: H+ u' t) I0 E
图19. 数据接收回调函数 ' ~1 P8 u i0 s$ y, _9 A4 n# F$ Z- l 至此,我们应该能通过全部编译过程,并且已经找到了数据发送、接收的位置。此时可以在这些位置添加数据发送、接收的打印函数。接收数据的用户接口见图 20: + v2 M7 `8 s0 l7 q: B7 M' }
图20. 用户接收 BLE 数据 0 z) c& J+ D4 n: m/ ~ ' P, x9 c" M/ I/ ^/ T6 [# j关于发送数据,原始工程实现了以下处理流程: 1. 从串口接收数据 2. 解析数据为命令并缓存这些命令' O" o8 a9 k, v7 s4 y, O6 S6 S 3. 通过轮询的方式,不断将命令缓冲区里的命令发送出去 6 T+ l% |* ^% l* h ) K+ z$ u3 {/ z3 `8 L. |% _ 该处理流程不适用于我们的任务要求,我们需要先取消这部分功能,见图 21
图21. 取消原有的数据处理流程 " c' ^: B) y, b4 i" d然后设计自己的发送函数,见图 22:
图22. 自定义 BLE 数据发送函数 " ?1 g0 f' \! |; o$ l& Z3 l- ^; N3 d- a+ \' f' h 至此,蓝牙的通讯功能已经全部实现完毕。用户可通过: • Data_Received()接口接收数据 • user_send_data_over_ble()接口发送数据: x- ^0 C9 _( ]& j" D 4.4.添加其它功能 根据任务要求,我们还需实现下面三个功能: 1. 控制 LED 亮灭; E( }8 P" o. N! w+ ?* u 2. 定时 1s 上传心跳包,内容为连接后的秒计数值 3. 每次按键上传按键事件通知下面开始逐个实现: 4.4.1. 控制 LED 亮灭 首先,实现 LED 亮灭处理函数,
图23. LED 命令处理函数 ' X! z$ |, |0 Y: o9 d 将其添加到 BLE 数据接收函数处,见图 24。LED 控制功能实现完毕。) y( E/ p/ ]" D5 Z2 l# @
图24. 接收数据后进行 LED 命令处理 # x8 H9 W, X9 g3 n 4.4.2. 每秒上传心跳包 首先,实现心跳上传处理函数,实现当设备连接后,每秒上传一个 4 字节的计数值,并使用0xaa 作为命令字。见图 25: % p+ y. \# w1 v
图25. 心跳上传处理 ; D# M& m5 n) q9 k6 R# p; V6 f9 a将心跳处理函数添加到系统任务处理函数 App_Tick 中,App_Tick 会在 main loop 中不断地被调用。心跳包需要在蓝牙连接成功并且使能了订阅之后才可以发送。另外,使用 timeout_flag变量来控制其每秒只被调用一次,实现方法如下:
图26. 心跳处理 ) _# |2 _9 u9 k+ N 7 `5 J J& Q7 N w: z3 u上述 timeout_flag 变量需要使用每秒循环的软件定时器来周期性置位。软件定时器的应用方式很简单。, o- V# K- F& P/ _' } 首先,实例化一个定时器,并定义超时回调函数:
图27. 软件定时器实例化 然后,在 Serial_port_DeviceInit 函数的末端位置注册超时回调函数并启动定时器。
图28. 启动定时器 7 v% |7 c/ q7 Y5 U4.4.3. 上传按键事件 首先,实现按键回调函数,该函数在按键按下时被调用。发送按键事件前,应检查此时蓝牙是否处理连接、已订阅状态。见图 29:% a" d0 D* z) a1 \( t0 E( X: ]: R 0 ~ O7 I2 z5 z3 ?
图29. 按键回调 按键中断服务函数中调用:& v, D; j& s1 u5 q' v, P( ?1 l W; P
图30. 按键中断服务函数 : Z" h3 N: r! e% p% D1 I至此,开发任务的要求已经全部实现完毕。接下来进行功能验证。 4.5验证功能 用户工程运行起来后,用 STBLE Toolbox 扫描,可见广播名已经修改过来了。 2 J& _7 ~! O- ?8 I: Y
图31. 用户工程广播名 连上设备并点击 Notify 开关以使能订阅,可观察到底部已经开始接收到设备的心跳包数据(以 AA 开头的 5 字节数据),该数据每秒钟变化一次,见图 32:
图32. 使能订阅 通过 LOG 也能观察到心跳包发送情况,此时如果按动按键,也能观察到按键事件已经发送:
图33. 用户工程 LOG + H! S( y: B4 b/ `& i/ l05小结; W, Q$ l9 E5 A 跑完了上述用户任务开发的流程后,相信用户对 BlueNRG SDK 的软件架构应有所理解了。BlueNRG SDK 的软件层次架构为 STM32 典型的三层架构,分别为驱动层、中间层、用户层: : `7 }7 ~$ g7 S$ y0 A
图34. 软件层次架构 f: W; n/ c2 `, X7 s: x9 I! A: r, C o h) v 上述添加用户功能的整个过程,其实只改动到了用户层的功能,用户层包含以下几个文件:& T) D) X$ e( k6 A- r f
图35. 用户层文件 " J5 \' T! m( K, L* i2 ^+ S) r# H+ \ 这些文件的含义是: • serial_port.c,用户应用逻辑的实现 • BLE_SerialPort_main.c,程序入口,程序主流程$ _, v" E2 w: T4 u- W( j • gatt_db.c,BLE GATT 层功能的实现 • rf_device_it.c,存放所有的中断服务函数 上述用户固件的功能,大多都在 serial_port.c 中实现。BLE_SerialPort_main.c 函数则实现了系统的主要流程。简单来说,BlueNRG SDK 的裸机系统即是一个前后台系统。蓝牙事件、按键中断等属于前台处理,负责置位相关标志位和状态,main 函数的 while1 属于后台处理,运行蓝牙协议栈、用户任务处理等后台任务,见图 36:) i3 Y5 \9 d& z, _. f: K" P8 N
2 _# h* a! w/ n 图36. 系统流程 2 E0 [6 M8 ?3 C, H1 j% Z0 e3 m BlueNRG SDK 中的绝大多数例程都使用了本文档所述的软件架构,即前后台系统。该软件架构比较简单,优点是用户能非常快速地掌握其流程,能够依据本文档的示例快速构建自己的用户功能。缺点是功能比较简单,用户需要在此基础上再添加一个调度器以应对复杂功能的要求。; l% A7 x4 h: q6 ~2 O( d% w # x" T% E. i0 d( K; m( e5 l2 } ; ^7 d7 V' A3 F# T6 \: Y+ W 转载自: STM32单片机4 d% j; j' _. o 如有侵权请联系删除 & W% H; T- K2 B- u; u! F0 R# K& Q |
【经验分享】STM32语音识别的智能蓝牙音箱(源程序+原理图+PCB+设计说明书+PPT)
想找个ST芯片
[GPIO] 使用新型抽象开始C++嵌入式编程,从GPIO开始
技术手册stm32f1xx中的一个小问题
【经验分享】STM32 HAL库移植FreeModbus详细步骤
【逢7发帖赢大礼】STM32开发之IC门禁卡UID读取方法!
实战经验 | Keil工程使用NEAI库的异常问题
经验分享 | FDCAN数据段波特率增加后发送失败的问题分析
STM32几种流行开发环境的优缺点
好用软件推荐-TouchGFX Designer
微信公众号
手机版