当前位置:   article > 正文

蓝牙5.0简介、nRF52832 BLE样例工程框架及main函数初始化流程简析_蓝牙5.0协议栈

蓝牙5.0协议栈

蓝牙5.0基本概念

蓝牙5.0

蓝牙5.0是由蓝牙技术联盟2016年6月16日发布的最新一代蓝牙标准,蓝牙5.0针在蓝牙4.2的基础上进化而来,除了具备蓝牙4.2低功耗的特性,在性能上相对于蓝牙4.2而言:

  • 4X 距离
    通过降低带宽,保持原来的功率要求的情况下,可以使传输距离提高至原来的4倍,有效传输距离可达300米。

  • 2X 数据吞吐量
    蓝牙4.2标准最大突发速率为1Mb/s,而蓝牙5.0标准将速率提高到2Mb/s。可以让蓝牙设备响应更快、性能更高。

  • 8X 广播数据
    蓝牙5.0标准将广播数据从传统的三个广播信道扩展到全部数据信道。广播信道增加,提高了广播传输容量,可以把更多的信息传送到其他兼容设备,而不会形成实际连接,从而加快互动速度。

不仅如此,蓝牙5.0标准针对物联网进行了很多底层优化,力求以更低的功耗和更高的性能为智能家居服务。同时蓝牙5.0标准添加了导航功能,结合wifi可以实现精度小于1米的室内定位,有利于实现室内导航功能。

在更新的蓝牙5.1协议上,加入了AoA(到达角)和 AoD(出发角)的概念,实现了测向和厘米级的定位服务。

蓝牙Mesh

蓝牙Mesh技术是一种组网方式。

2017年7月19日,蓝牙技术联盟正式宣布蓝牙技术开始全面支持Mesh网络。至此,蓝牙拥有了进军智能家居、智慧城市、楼宇自动化等物联网的资本。和zigbee实现Mesh网络的方式不同,zigbee采用路由技术,而蓝牙采用管理型网络泛洪方式,也就是广播方式。大家听到广播方式,第一感觉就是网络会非常的繁忙、效率低下、耗电,但是蓝牙Mesh采用的广播方式是可控的,设备对于信息的转发需要满足多种限定条件,提高传输效率。

蓝牙协议栈结构

蓝牙的协议栈核心规范可以在蓝牙 SIG 官方网站上下载:https://www.bluetooth.com/specifications

下面内容有部分参考博文:蓝牙5.0基础知识

蓝牙5 核心规范包含低功耗蓝牙(BLE) 和经典蓝牙(BR/EDR) 两种设备类型

蓝牙5 核心主要包含以下功能:

2MSym/s PLY层设计(2M Symbol Rate 物理层)

LE 信道选择算法

LE 安全连接

LE 数据长度扩展

LE 隐私

LE LCAP 面向连接的信道支持

LE 链路层拓扑结构

LE Ping

从机功能扩展

连接参数请求
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

以上功能均在蓝牙5 协议栈实现,并且可以选择编译。

对于目前学习的52832来说,我们针对的应用都是低功耗的应用,所以下面以BLE协议框架来说明:

BLE协议栈是实现低功耗蓝牙协议的代码,下面是BLE协议栈的整体框架:
在这里插入图片描述

控制层(Controller)

PHY(Physical layer 物理层)

指定BLE所用的无线-频段,调制解调方式和方法,传输数据的速度,整个BLE芯片功耗、灵敏度以及selectivity 等视频指标

LL(Link Layer 链路层)

核心,具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据完整性,ACK接收,重传,对链路的管理和控制等。
负责把数据发出去或者接收回来,对数据的解析是GAP或者ATT。

HCI(Host controller interface)

主要用于两个MCU实现BLE协议栈的场合,规范两者之间的通讯协议和命令。
HCI是可选的。

主协议层(Host)

L2CAP(logic link control and adaptation )

L2CAP 对 LL 进行了一次简单封装,L2CAP 要区分是加密通道还是普通通道,同时还要对连接间隔进行管理。

SMP(Secure manager protocol )

管理BLE连接的加密和安全。

ATT(Attribute protocol)

开发者接触最多的 ATT。 用来定义用户命令及命令操作的数据,比如读取某个数据,写某个数据。BLE引入了 attribute 概念,用来描述一条一条的数据。Attribute 除了定义数据,同时定义该数据可以使用的 ATT 命令。

GAP(Generic access profile)

主要用来进行广播,扫描和发起连接等。
GAP是对 LL 层 payload(有效数据包)如何进行解析的两种方式中的一种,最简单的那种。GAP简单的对 LL payload进行一些规范和定义。

GATT(Generic attribute profile)

GATT用来规范 attribute 中的数据内容,并运用 group(分组)的概念对 attribute 进行分类管理。为主从设备交互数据提供 Profile、Service、Characteristic 等概念的抽象、管理。没有GATT,BLE也能跑,但是互联互通会出问题,兼容性差。

应用层(Profiles)

包含公共任务和私有任务。
公共任务时 SIG 蓝牙协议小组定义的蓝牙任务,
私有任务时用户自定义的蓝牙任务。
开发应用者所有的任务应用就是在这个层。

蓝牙的连接

主机与从机的通讯步骤可以简单归纳为下面的步骤:
从机广播 —> 主机扫描 —> 主机发起连接 —> 连接建立 —> 数据交换

nRF52832 BLE工程结构

上面我们大概介绍了蓝牙5.0的一些基础知识,我们使用的芯片是nRF52832,最终我们的应用开发是需要在这个芯片上面,但是对于初次接触工程的朋友来说,这个工程结构还是有点复杂的,我们可以在官网下载官方的SDK,先认识一下官方 BLE 的样例工程结构,把下载好的SDK包解压,然后找到BLE的工程:

在这里插入图片描述

结构框架

整体的框架结构图:
在这里插入图片描述

1、Device

这里面是 startup.s 和system.c(Cortex-M内核,和STM32类似),一个是芯片启动文件,一个是芯片系统文件,配置处理器时钟,寄存器等参数。

文件路径如下图:
在这里插入图片描述

2、Application

应用程序部分,一个是main.c函数,一个是sdk_config.h配置文件,宏定义使能各种外设或者驱动,都需要在这个文件进行配置设置。

文件路径如下图:
在这里插入图片描述在这里插入图片描述

3、Board Definition

板载的 按键和LED 定义相关, Board Definition 部分和下面的 Board Support 是可选的,可以自己编写或者直接根据自己的硬件进行修改。

文件路径如下图:
在这里插入图片描述

4、Board Support

板载的 按键和LED 功能设置,比如协议栈下按键唤醒,按键休眠,长按与短按等配置功能。

文件路径如下图:
在这里插入图片描述

5、nRF_BLE

在这里插入图片描述
提供一些蓝牙服务代码,比如广播的配置代码,连接参数的配置代码,GATT的配置代码,还有 peer 设备匹配管理的代码,安全参数设置等。

文件路径如下图:
在这里插入图片描述

6、nRF_Drivers

在这里插入图片描述
外设驱动,新版本的外设驱动文件,带有nrfx的表示新版驱动。

文件路径如下图:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

7、nRF_Libraries

在这里插入图片描述
外设驱动函数代码,类似于二级驱动。
包含一些内存处理,打印,缓冲,能量管理等内容。

文件路径如下图:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

8、nRF_Log

uart串口的打印输出接口

文件路径如下图:
在这里插入图片描述

9、nRF_Segger_RTT

jlink仿真器的打印输出接口

文件路径如下图:
在这里插入图片描述

10、nRF_SoftDevice

配置协议栈初始化的时候协议栈的参数设定,协议栈是不开源的,只留下了配置接口,用户可以通过这些配置接口来设置协议栈的运行状态。

文件路径如下图:
在这里插入图片描述

主函数简析

先上一段官方样例中的主函数部分代码:

/**@brief Function for application main entry.
 */
int main(void)
{
    bool erase_bonds;

    // Initialize.
    log_init();
    timers_init();
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    gap_params_init();
    gatt_init();
    advertising_init();
    services_init();
    conn_params_init();
    peer_manager_init();

    // Start execution.
    NRF_LOG_INFO("Template example started.");
    application_timers_start();

    advertising_start(erase_bonds);

    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
}
/**
 * @}
 */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

log_init()

log打印初始化

/*
#define NRF_LOG_DEFAULT_BACKENDS_INIT() nrf_log_default_backends_init()
*/
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

timers_init()

软件定时器初始化,用户可以任意设置自己需要的软件定时器 id,对于每一个新的计时器需要,可以设置不同的定时器超时溢出时间。
软甲定时器是基于RTC来实现的。

/**@brief Function for the Timer initialization.
 *
 * @details Initializes the timer module. This creates and starts application timers.
 */
static void timers_init(void)
{
    // Initialize timer module.
    ret_code_t err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    // Create timers.

    /* YOUR_JOB: Create any timers to be used by the application.
                 Below is an example of how to create a timer.
                 For every new timer needed, increase the value of the macro APP_TIMER_MAX_TIMERS by
                 one.
       ret_code_t err_code;
       err_code = app_timer_create(&m_app_timer_id, APP_TIMER_MODE_REPEATED, timer_timeout_handler);
       APP_ERROR_CHECK(err_code); */
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

buttons_leds_init(&erase_bonds)

初始化LED和按键,因为在SDK中有相关的LED和按键库,库中提供了板载初始化bsp_init()函数,利用该函数进行LED和按键的初始化,并且声明了一个按键触发事件中断bsp_event_handler
bsp_event_handler()函数需要在主函数main.c文件中编写,可以使用按键来进行休眠,启动蓝牙广播,删除白名单等处理。

/**@brief Function for initializing buttons and leds.
 *
 * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
 */
static void buttons_leds_init(bool * p_erase_bonds)
{
    ret_code_t err_code;
    bsp_event_t startup_event;

    err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
    APP_ERROR_CHECK(err_code);

    err_code = bsp_btn_ble_init(NULL, &startup_event);
    APP_ERROR_CHECK(err_code);

    *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

bsp_event_handler()

/**@brief Function for handling events from the BSP module.
 *
 * @param[in]   event   Event generated when button is pressed.
 */
static void bsp_event_handler(bsp_event_t event)
{
    ret_code_t err_code;

    switch (event)
    {
        case BSP_EVENT_SLEEP: //进入睡眠
            sleep_mode_enter();
            break; // BSP_EVENT_SLEEP

        case BSP_EVENT_DISCONNECT:  //蓝牙断开
            err_code = sd_ble_gap_disconnect(m_conn_handle,
                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
            if (err_code != NRF_ERROR_INVALID_STATE)
            {
                APP_ERROR_CHECK(err_code);
            }
            break; // BSP_EVENT_DISCONNECT

        case BSP_EVENT_WHITELIST_OFF:   //没有白名单
            if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
            {
                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }
            }
            break; // BSP_EVENT_KEY_0

        default:
            break;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

power_management_init()

能源管理,实现m4内核SCB内核里低功耗管理设置的初始化。

/**@brief Function for initializing power management.
 */
static void power_management_init(void)
{
    ret_code_t err_code;
    err_code = nrf_pwr_mgmt_init();
    APP_ERROR_CHECK(err_code);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

ble_stack_init()

协议栈初始化,主要做下面几点工作:

1、协议栈回复使能应答(时钟初始化等);
2、相关参数设置,初始化协议栈,完成使能;
3、注册蓝牙处理调度事件。	
  • 1
  • 2
  • 3
/**@brief Function for initializing the BLE stack.
 *
 * @details Initializes the SoftDevice and the BLE event interrupt.
 */
static void ble_stack_init(void)
{
    ret_code_t err_code;
		//协议栈回复使能应答,主要配置协议栈时钟
    err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);

    /*
    Configure the BLE stack using the default settings.
    配置协议栈使用默认地址
    Fetch the start address of the application RAM.
    获取RAM的开始地址
    相关参数设置,初始化协议
    */
    uint32_t ram_start = 0;
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);

    // Enable BLE stack. 使能协议栈
    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);

    // Register a handler for BLE events. 注册蓝牙处理事件
    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

gap_params_init()

GAP(通用访问配置文件 Generic Access Profile)初始化,该配置文件保证不同的 Bluetooth 产品可以互相发现对方并建立连接。
GAP规定的是一些一般性的运行任务,它具有强制性,并作为所有其他蓝牙应用规范的基础。
GAP是多有其他配置文件的基础,它定义了再蓝牙设备间建立基带链路的通用方法。
在初始化代码中,GAP实际上只做了两件事,一是配置设配名称,二就是配置GAP的链接参数。

/**@brief Function for the GAP initialization.
 *
 * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
 *          device including the device name, appearance, and the preferred connection parameters.
 */
static void gap_params_init(void)
{
    ret_code_t              err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
	//设定设备名称
    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *)DEVICE_NAME,
                                          strlen(DEVICE_NAME));
    APP_ERROR_CHECK(err_code);

    /* YOUR_JOB: Use an appearance value matching the application's use case.
    		添加服务的图标
       err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_);
       APP_ERROR_CHECK(err_code); */
	err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_);
	APP_ERROR_CHECK(err_code);

    memset(&gap_conn_params, 0, sizeof(gap_conn_params));
	//初始化 gap 链接间隔,从机延迟,超时时间
    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    gap_conn_params.slave_latency     = SLAVE_LATENCY;
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(err_code);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

gatt_init()

GATT 通用属性规范(Generic Attribute profile),GATT层 是传输真正数据所在的层,包括了一个数据传输和存储框架以及基本操作。
其大部分设置是在服务中进行的,在主函数中只需要初始化数据长度这个参数。

/**@brief Function for initializing the GATT module.
ret_code_t nrf_ble_gatt_init(nrf_ble_gatt_t * p_gatt, nrf_ble_gatt_evt_handler_t evt_handler)
 */
static void gatt_init(void)
{
	//nrf_ble_gatt_init定义了gatt主机,从机的最大MTU长度,以及协商数据的长度
    ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
    APP_ERROR_CHECK(err_code);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

advertising_init

广播初始化,其中有2个结构体,一个是 广播数据参数,一个是广播配置参数。

一个广播数据实际上最多可以携带31字节数据,它通常包含用户可读的名字、关于设备发送数据包的有关信息、用于表示此设备是否可被发现的标志等标志,下面的结构体的定义。
当主机接收到广播包后,它可能发送请求更多数据包的请求,即扫描回应,如果它被设置成主动扫描,从机设备将会发送一个扫描回应作为对主机请求的回应,扫描回应最多也可以携带31字节数据。广播扫描回应包的数据结构类型和广播包一致。

/**@brief Function for initializing the Advertising functionality.
 */
static void advertising_init(void)
{
    ret_code_t             err_code;
    ble_advertising_init_t init;

    memset(&init, 0, sizeof(init));

    init.advdata.name_type               = BLE_ADVDATA_FULL_NAME;//广播名称
    init.advdata.include_appearance      = true; //是否需要图标
    init.advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;//广播模式
    init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);//蓝牙设备模式
    init.advdata.uuids_complete.p_uuids  = m_adv_uuids;//UUID

    init.config.ble_adv_fast_enabled  = true; //广播类型
    init.config.ble_adv_fast_interval = APP_ADV_INTERVAL; //广播间隔
    init.config.ble_adv_fast_timeout  = APP_ADV_DURATION; //广播超时

    init.evt_handler = on_adv_evt;

    err_code = ble_advertising_init(&m_advertising, &init);
    APP_ERROR_CHECK(err_code);

	//设置广播识别号
    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

services_init

建立一个服务声明,在工程中添加自己需要的蓝牙服务。
该函数给 RAM 一个空间,专门对服务进行初始化和声明。官方Demo中只是给出了一个框架,没有实例,这是用户需要自己添加的服务。

/**@brief Function for initializing services that will be used by the application.
 */
static void services_init(void)
{
    ret_code_t         err_code;
    nrf_ble_qwr_init_t qwr_init = {0};

    // Initialize Queued Write Module.
    qwr_init.error_handler = nrf_qwr_error_handler;

    err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
    APP_ERROR_CHECK(err_code);

    /* YOUR_JOB: Add code to initialize the services used by the application.
       ble_xxs_init_t                     xxs_init;
       ble_yys_init_t                     yys_init;

       // Initialize XXX Service.
       memset(&xxs_init, 0, sizeof(xxs_init));

       xxs_init.evt_handler                = NULL;
       xxs_init.is_xxx_notify_supported    = true;
       xxs_init.ble_xx_initial_value.level = 100;

       err_code = ble_bas_init(&m_xxs, &xxs_init);
       APP_ERROR_CHECK(err_code);

       // Initialize YYY Service.
       memset(&yys_init, 0, sizeof(yys_init));
       yys_init.evt_handler                  = on_yys_evt;
       yys_init.ble_yy_initial_value.counter = 0;

       err_code = ble_yy_service_init(&yys_init, &yy_init);
       APP_ERROR_CHECK(err_code);
     */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

conn_params_init

连接参数初始化,使用ble_conn_params_init初始化ble_conn_params()模块,在SDK中ble_conn_params()模块用于管理连接参数更新,它通过SoftDevice API (不开源的函数)进行处理,包括请求的时间和第一次请求被拒绝再发送一个新的请求。

/**@brief Function for initializing the Connection Parameters module.
 */
static void conn_params_init(void)
{
    ret_code_t             err_code;
    ble_conn_params_init_t cp_init;

    memset(&cp_init, 0, sizeof(cp_init));

    cp_init.p_conn_params                  = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
    cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
    cp_init.disconnect_on_fail             = false;
    cp_init.evt_handler                    = on_conn_params_evt;
    cp_init.error_handler                  = conn_params_error_handler;

    err_code = ble_conn_params_init(&cp_init);
    APP_ERROR_CHECK(err_code);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

peer_manager_init

配对管理初始化,主要就是配置配对绑定过程中使用的安全参数。
配对是蓝牙主从设备加密特性的可交换,并创建临时密钥。
绑定测试在配对之后交换和保存长期密钥,用于以后的连接。
为了保证低功耗蓝牙的绝大多数安全特性,蓝牙设备必须完成两件事:
1、互相配对;
2、连接一旦加密,设备必须分配用于加密并对消息进行验证的密钥。只要密钥被保存,设备就处于绑定态。

/**@brief Function for the Peer Manager initialization.
 */
static void peer_manager_init(void)
{
    ble_gap_sec_params_t sec_param;
    ret_code_t           err_code;

    err_code = pm_init();
    APP_ERROR_CHECK(err_code);

    memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));

    // Security parameters to be used for all security procedures.安全参数
    sec_param.bond           = SEC_PARAM_BOND;
    sec_param.mitm           = SEC_PARAM_MITM;
    sec_param.lesc           = SEC_PARAM_LESC;
    sec_param.keypress       = SEC_PARAM_KEYPRESS;
    sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
    sec_param.oob            = SEC_PARAM_OOB;
    sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
    sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
    sec_param.kdist_own.enc  = 1;
    sec_param.kdist_own.id   = 1;
    sec_param.kdist_peer.enc = 1;
    sec_param.kdist_peer.id  = 1;

    err_code = pm_sec_params_set(&sec_param);
    APP_ERROR_CHECK(err_code);

    err_code = pm_register(pm_evt_handler);
    APP_ERROR_CHECK(err_code);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

advertising_start(erase_bonds)

开始广播。首先剔除绑定设备,保证设备能够被重新连接。然后启动广播为快速广播。

/**@brief Function for starting advertising.
 */
static void advertising_start(bool erase_bonds)
{
    if (erase_bonds == true)
    {
        delete_bonds();
        // Advertising is started by PM_EVT_PEERS_DELETED_SUCEEDED event 去除绑定
    }
    else
    {
        ret_code_t err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);

        APP_ERROR_CHECK(err_code);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

idle_state_handle()

在循环中调用了idle_state_handle(),可以使设备处于待机(system on) 状态。
该函数调用了nrf_pwr_mgmt_run()函数,这个函数中又使用了SDK提供的一个协议栈函数sd_app_evt_wait()模块,用于管理电源。

/**@brief Function for handling the idle state (main loop).
 *
 * @details If there is no pending log operation, then sleep until next the next event occurs.
 */
static void idle_state_handle(void)
{
    if (NRF_LOG_PROCESS() == false)
    {
        nrf_pwr_mgmt_run();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

工程烧录

nRF系列烧录协议栈和应用程序部分需要分开烧录,应用程序烧录和裸机一样使用 keilC 直接烧录,协议栈烧录使用Nordic官方提供的 nrfgostudio 工具:官方下载地址
在这里插入图片描述
根据自己的系统安装对应的版本,安装过程这里就不多介绍了,傻瓜式安装。

但是注意,软件安装完以后会自动安装Jlink驱动,即便你电脑上本来有Jlink驱动,也还是让软件继续安装,不要去掉,要不然容易出问题,识别不了设备

1、协议栈烧录

协议栈官方给我们提供好了hex,nRF52832使用的协议栈路径如下:
在这里插入图片描述
打开安装好的nrfgostudio 工具,按照下图所示进行操作:
在这里插入图片描述

2、应用程序烧录

应用程序直接通过Keil 打开官方Demo,路径在上面我们讲解工程结构的最开始有截图,直接下载。

在此期间我遇到过一个问题,就是 Jlink提示错误信息read:@0x02000004

我也是在网上查找到解决办法,这里给出原文地址:解决方法:调试NRF52832工程时JLink提示错误信息read:@0x02000004

最后连接测试结果:
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/194322
推荐阅读
相关标签
  

闽ICP备14008679号