从零开始的nrf52832蓝牙开发--蓝牙模板解析

李肖遥 2022-05-26 08:01
    关注、星标公众号,直达精彩内容

来源:https://blog.csdn.net/qwe5959798/article/details/120152350



本篇文章使用SDK版本为 15.3.0,开发板使用官方开发板PCA10040。


我们打开nRF5_SDK_15.3.0\examples\ble_peripheral\experimental\bluetoothds_template\pca10040\s132\ses
由SDK说明文档可知,这个例子是用Bluetooth Developer studio生成的一个模板工程,这个开发工具是由SIG推出的,不过感觉国内用的人很少。

代码功能

LED1指示连接状态,如果蓝牙未被连接,LED1闪烁,如果蓝牙被连接,则LED1常亮。按键1连接状态下长按2S可以断开连接并重新开启一个无白名单广播,未连接状态下按下会进入休眠状态,再按下唤醒。按键2也可以唤醒设备但会删除所有绑定信息,正常运行中按下会关闭白名单。广播超过3分钟未连接设备则会自动休眠。使用nrf connect这个APP连接开发板如下:

main


main函数里面包含所有功能的初始化。我们详细看一下和蓝牙有关的初始化。

timers_init


因为蓝牙协议栈使用到了app定时器,所以app定时器初始化是必须的,即使你没有使用到,使用的方法官方已经给出,如上图红框。

buttons_leds_init


这个函数第一初始化了LED和按键,第二把蓝牙事件与LED和按键绑定起来。
LED和按键初始化中,按键初始化如下:

按键的设计思路是:通过定时器去实现按键按下、按键释放、按键长按三种情况判断,每种动作情况可以配置相同或者不同的事件类型,根据事件类型去处理不同情况。
bsp_init里还有LED的初始化:

可以看到在这里创建了一个有关LED的定时器,这个定时器里通过判断当前BSP的事件状态去改变LED状态:

bsp_led_indication这个函数因为处理的状态比较多所以很长,这里我们只看用到的:


按键初始状态事件绑定在函数bsp_btn_ble_init里:

因为有两种唤醒方式(删除绑定和不删除),所以需要在程序唤醒后判断是用哪一个按键唤醒的,从而决定要不要删除所有绑定信息。

而函数 advertising_buttons_configure里则更改了按键动作触发的事件:

函数bsp_event_to_button_action_assign主要用来把事件对应到哪个按键完成什么动作触发这个绑定:

这个函数上面还有一个差不多的连接状态下的按键配置函数connection_buttons_configure

这个函数在何处被调用?首先在bsp_btn_ble.c中注册了一个观察者:

它的回调函数中处理了连接和断开两种事件:

也就是连接后用connection_buttons_configure配置按键,断开后用advertising_buttons_configure配置按键。关于观察者详细查看下一节。

ble_stack_init


函数nrf_sdh_enable_request内容如下:

注意这里用到的通知函数有两种:
sdh_request_observer_notify
sdh_state_observer_notify
如何通知所有观察者?如把类型为request的信息通知给所有观察者:

通知 state 类型如下:

这两个段被注册在nrf_sdh.c内:

用来定义段的宏定义为 NRF_SECTION_SET_DEF

关于宏和段的使用,可以参考我之前剖析RT-Thread那篇自动初始化部分
剖析RT-Thread中console与finsh组件实现(1)
什么是观察者?
详细解析参考下面博文:
BLE事件回调机制解析

还有在这个函数里我们需要特别注意函数 nrf_sdh_ble_enable 函数内容:

由上一章我们知道了其实所有数据在服务端都以attribute呈现,就像古代的药店,有一面墙都是抽屉,每个抽屉的标签写了药材的名字,里面则放的相应的药材,类比一下,每个attribute就是一个抽屉,attribute的handle就像药材的名字,attribute的内容就像药材本身,而attribute的权限就像药性。客户端就像配药的大夫,需要什么药得根据名字去找,然后根据药材的药性去决定取的量。所有的attribute组成一个表叫attribute table如下:

所以每当你添加服务或者特征,都会增大attribute table的大小,而这个attribute table是直接分配在协议栈所用ram里的,这里需要提一下,协议栈其实就是一段代码,也需要运行空间,nrf的做法就像用OS创建了两个任务,一个任务专门跑协议栈,一个任务跑你的应用代码,我们知道创建任务是需要分配任务空间的,attribute table就占用协议栈的任务空间大小。因为协议栈的ram是从芯片ram起始地址开始的,所以我们只需要设置应用程序的ram从哪开始、有多大就可以了,这样前面的就全部分配给协议栈。所以回到前面,当attribute table变大了,就需要把应用程序的起始ram往后推,应用程序ram大小当然也要减去增加的,因为芯片ram总大小是一定的。
所以如果当你代码没有问题,但是程序跑不起来或者蓝牙服务异常,有可能就是你的attribute table太大了导致数据溢出,如果只影响到协议栈,那你的蓝牙服务就会崩溃,如果严重到影响到应用代码,你的整个程序都会崩溃。但是你并不能直接去修改应用ram起始和大小,而是应该先去增加attribute table的大小:

然后上面函数里的打印会告诉你应该把起始地址和大小调整为多少。调整方法:


修改格式IDE已经给出,仿照上图红框,修改参数填入到下图即可。

比如我的这段代码LOG:

我只需要修改:

最后在此函数中还初始化了一个观察者:

该宏NRF_SDH_BLE_OBSERVER如下:

sdh_ble_observers段定义在nrf_sdh_ble.c内:

如果我们后续添加自己的服务也应该注册在该段内。该观察者事件回调为:

可以看到连接成功后,会触发一次LED状态指示函数,也就是常亮LED1。

peer_manager_init


有关配对与绑定,其实主要是为了安全,详细解析推荐博文:
低功耗蓝牙配对绑定解读和实践
除了注意配对的一些参数,需要注意配对事件的回调函数。

在协议栈收到一些配对有关信息,它会处理好分为不同事件类型上报给应用层,方法就是触发事件回调。上图回调函数里并没有处理任何事件,实际我们写为:

上图只处理了一种情况 PM_EVT_PEERS_DELETE_SUCCEEDED 如果你需要处理其他情况,直接添加不同的case即可:

gap_params_init


这个函数里可以修改加密模式、设备名称、还有一些GAP连接参数。中间注释掉的那段代码是添加设备外观的,如果添加的是SIG所制定的一些标准profile是有设备外观的,而自定义的则无。

gatt_init


可以看到gatt初始化很简单,实际在自己的项目中基本会提供一个GATT的事件回调函数,如:


可以看到就两种事件,一种是ATT的MTU大小更新,另一种是数据长度更新。

advertising_init


这个函数是设置广播相关内容的,也就是在广播阶段你想要展示的内容都在这里设置。最开始手机截图可以看到没有连接的时候也有显示180A这个服务。

services_init

这个函数里就是我们要实现的功能,如果我们要添加自己的服务,就在下图红框内的服务初始化函数内添加,如果是多个服务,你可以添加多个服务初始化函数。


可以看到上图就是一个服务的模板文件,实际开发时,我们最好把每个服务放在单独的.c文件里,这里服务初始化是空的,也就是没有我们自己的服务。

conn_params_init


这个函数主要设置了连接参数协商参数,因为连接参数是由连接发起方设置的,我们作为被连接方,如果想要改变连接参数,只能通过协商的方式,即告诉连接方我们想如何连接,但是连接方可以选择采纳也可以拒绝。

advertising_start


可以看到广播一开始就以快速广播模式开始广播,这个函数里面比较复杂,我们不过多关注,只需要注意一个地方:

假如你前面没有设置快速广播的相关参数,实际开启的广播可能会变成其他广播模式。

这里case中没有break,也就是返回值是最近能得到的广播模式。

变量定义


还有一些需要使用到的全局变量都定义在main.c最开始的位置。分别是与队列模块相关的、GATT模块相关的、与广播模块相关的、保存当前连接句柄的全局变量。

这里看一下广播的结构体变量,因为它和广播如果3分钟没有设备连接就自动休眠有关。
先看一下广播结构体变量初始化:

这里很重要的宏是 NRF_SDH_BLE_OBSERVER,它用来注册观察者,上面在蓝牙协议栈初始化已经讲过。我们看一下广播的事件回调ble_advertising_on_ble_evt

连接成功和连接断开不做展开,但是广播超时后广播就立马停止了吗?

可以看到无论哪种超时原因,最后的结果都是继续广播,函数adv_mode_next_get会返回下个广播模式,但是因为我们只配置了快速广播模式一种,所以ble_advertising_start这个启动广播的函数里面
在判断所选广播模式是否配置过会判断不过,最终函数adv_mode_next_avail_get只能返回BLE_ADV_MODE_IDLE

最终这个状态会在广播事件回调on_adv_evt里被触发

on_adv_evt被调用的位置在函数ble_advertising_start结尾:

而在休眠函数sleep_mode_enter里设置如下:

免责声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

关注我的微信公众号,回复“加群”按规则加入技术交流群。


点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

李肖遥 公众号“技术让梦想更伟大”,作者:李肖遥,专注嵌入式,只推荐适合你的博文,干货,技术心得,与君共勉。
评论
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 134浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 178浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 194浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 123浏览
  • 故障现象 一辆2007款日产天籁车,搭载VQ23发动机(气缸编号如图1所示,点火顺序为1-2-3-4-5-6),累计行驶里程约为21万km。车主反映,该车起步加速时偶尔抖动,且行驶中加速无力。 图1 VQ23发动机的气缸编号 故障诊断接车后试车,发动机怠速运转平稳,但只要换挡起步,稍微踩下一点加速踏板,就能感觉到车身明显抖动。用故障检测仪检测,发动机控制模块(ECM)无故障代码存储,且无失火数据流。用虹科Pico汽车示波器测量气缸1点火信号(COP点火信号)和曲轴位置传感器信
    虹科Pico汽车示波器 2025-01-23 10:46 74浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 666浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 617浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 321浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 159浏览
  • 飞凌嵌入式基于瑞芯微RK3562系列处理器打造的FET3562J-C全国产核心板,是一款专为工业自动化及消费类电子设备设计的产品,凭借其强大的功能和灵活性,自上市以来得到了各行业客户的广泛关注。本文将详细介绍如何启动并测试RK3562J处理器的MCU,通过实际操作步骤,帮助各位工程师朋友更好地了解这款芯片。1、RK3562J处理器概述RK3562J处理器采用了4*Cortex-A53@1.8GHz+Cortex-M0@200MHz架构。其中,4个Cortex-A53核心作为主要核心,负责处理复杂
    飞凌嵌入式 2025-01-24 11:21 18浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 145浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦