[蓝牙] 3、<KEIL path> \ARM\Device\Nordic\nrf51822\Board\pca10001\s110\ble_app_hrs BLE心率检测工程

Heart Rate Example

The Heart Rate Application is a firmware example that implements the Heart Rate profile using the hardware delivered in the nRF51822 Development Kit.

The source code and project file can be found in the <InstallFolder>\Nordic\nrf51822\Board\nrf6310\s110\ble_app_hrs folder.

The application includes the two services in the Heart Rate profile:

  • Heart Rate Service
  • Device Information Service

In addition, use of the Battery Service is also demonstrated.

When the application starts, three timers are started which control generation of various parts of the Heart Rate Measurement characteristic value:

  • Heart Rate
  • RR Interval
  • Sensor Contact Detected

Also, a timer for generating battery measurements is started.

The sensor measurements are simulated the following way:

  • Heart Rate: See Sensor Data Simulator.
  • RR Interval: See Sensor Data Simulator.
  • Sensor Contact: The state is toggled each time the timer expires.
  • Battery Level: See Sensor Data Simulator.

When notification of Heart Rate Measurement characteristic is enabled, the Heart Rate Measurement, containing the current value for all the components of the Heart Rate Measurement characteristic, is notified each time the Heart Rate measurement timer expires. When notification of Battery Level characteristic is enabled, the Battery Level is notified each time the Battery Level measurement timer expires.

Note
This application is not power optimised!
The application will stop advertising after 3 minutes and go to system-off mode. Push the button 0 restart advertising.

Setup

Instructions on how to set up the nRFgo Motherboard: nRFgo Motherboard Setup (nRF6310).

LED assignments:

  • LED 0: Advertising
  • LED 1: Connected
  • LED 7: Asserted (i.e. an assert check in the application has failed)

Buttons assignments:

  • Button 0: Wake-up from system-off and restart advertising.
  • Button 1: Wake-up erase all bonds and restart advertising.

Testing

The Heart Rate Application can be tested using the nRF Utility app for iOS and Android. The app will be listed as "nRFready Utility" on Apple Store and as "nRF Utility" on Google Play.

It can also be tested using the Master Control Panel as follows:

  1. Compile and program the application. Observe that the Advertising LED is lit.
  2. Connect to the device from Master Control Panel (the device will be advertising as ‘Nordic_HRM‘), then perform service discovery. Observe that the Connected LED is lit, and the Advertising LED is off.
  3. Click the ‘Enable services‘ button on the Master Control Panel. Observe that Heart Rate notifications are received every second, and Battery Level notifications are received every two seconds.


main函数

 1 int main(void)
 2 {
 3     uint32_t err_code;
 4
 5     timers_init();//@details Initializes the timer module. This creates and starts application timers.
 6     gpiote_init();
 7     buttons_init();
 8     ble_stack_init();
 9     bond_manager_init();
10
11     // Initialize Bluetooth Stack parameters
12     gap_params_init();
13     advertising_init();
14     services_init();
15     conn_params_init();
16     sec_params_init();
17
18     // Start advertising
19     advertising_start();
20
21     // Enter main loop
22     for (;;)
23     {
24         // Switch to a low power state until an event is available for the application
25         err_code = sd_app_evt_wait();
26         APP_ERROR_CHECK(err_code);
27     }
28 }

初始化->start ad->for loop



Timer初始化

 1 /**@brief Function for the Timer initialization.
 2  *
 3 * @details Initializes the timer module. This creates and starts application timers.
 4 */
 5 static void timers_init(void)
 6 {
 7     uint32_t err_code;
 8
 9     // Initialize timer module
10     APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);
11
12     // Create timers
13     err_code = app_timer_create(&m_battery_timer_id,
14                                 APP_TIMER_MODE_REPEATED,
15                                 battery_level_meas_timeout_handler);
16     APP_ERROR_CHECK(err_code);
17
18     err_code = app_timer_create(&m_heart_rate_timer_id,
19                                 APP_TIMER_MODE_REPEATED,
20                                 heart_rate_meas_timeout_handler);
21     APP_ERROR_CHECK(err_code);
22 }

使用app_timer_create创建了两个时钟,处理函数分别是battery_level_meas_timeout_handler和heart_rate_meas_timeout_handler。

// Initialize timer module

    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);

1、参数宏APP_TIMER_INIT()

这个宏用于初始化app_timer模块,这是一个参数宏,接口定义如下:

APP_TIMER_INIT(PRESCALER, MAX_TIMERS, OP_QUEUES_SIZE, USE_SCHEDULER)

其中PRESCALE     分频比例,填入0的话,每秒就产生32768次tick,定时最大长度为0xFFFFFF次tick,也就是说500多秒定时。

PS3:与ucos提供的时基tick不同,本SDK的主要在定时到达的时候进入RTC中断,而不是每个TICK都进入。因此就算每秒就产生32768次tick,也不会拖慢系统性能。

MAX_TIMERS       必须大于等于工程中创建的timer数量。

OP_QUEUES_SIZE   操作队列的大小,具体意思看第三节。如果不作死,选择等于MAX_TIMERS就行了。

USE_SCHEDULER    是否使用任务调度器,当前不使用

#define APP_TIMER_PRESCALER                  0                                         /**< Value of the RTC1 PRESCALER register. */

#define APP_TIMER_MAX_TIMERS                 4                                         /**< Maximum number of simultaneously created timers. */

#define APP_TIMER_OP_QUEUE_SIZE              5                                         /**< Size of timer operation queues. */

// Create timers

    err_code = app_timer_create(&m_battery_timer_id,

                                APP_TIMER_MODE_REPEATED,

                                battery_level_meas_timeout_handler);

2、函数app_timer_create()

用于创建一个timer,并获取生成timer的控制句柄。接口定义如下:

uint32_t app_timer_create(app_timer_id_t *            p_timer_id,

app_timer_mode_t            mode,

app_timer_timeout_handler_t timeout_handler)

p_timer_id         读取到创建的timer的句柄

mode             timer的类型,其中

APP_TIMER_MODE_SINGLE_SHOT是单次执行

APP_TIMER_MODE_REPEATED是循环执行

timeout_handler    被注册到内核的回调函数,当timer超时后就会执行。

static app_timer_id_t                        m_battery_timer_id;                       /**< Battery timer. */

在处理函数中分别测电量和心率。这些函数被周期性执行~

 1 /**@brief Function for handling the Battery measurement timer timeout.
 2  *
 3  * @details This function will be called each time the battery level measurement timer expires.
 4  *          This function will start the ADC.
 5  *
 6  * @param[in]   p_context   Pointer used for passing some arbitrary information (context) from the
 7  *                          app_start_timer() call to the timeout handler.
 8  */
 9 static void battery_level_meas_timeout_handler(void * p_context)
10 {
11     UNUSED_PARAMETER(p_context);
12     battery_start();
13 }
14
15
16 /**@brief Function for handling the Heart rate measurement timer timeout.
17  *
18  * @details This function will be called each time the heart rate measurement timer expires.
19  *          It will exclude RR Interval data from every third measurement.
20  *
21  * @param[in]   p_context   Pointer used for passing some arbitrary information (context) from the
22  *                          app_start_timer() call to the timeout handler.
23  */
24 static void heart_rate_meas_timeout_handler(void * p_context)
25 {
26     uint32_t err_code;
27
28     UNUSED_PARAMETER(p_context);
29
30     err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, m_cur_heart_rate);
31
32     if (
33         (err_code != NRF_SUCCESS)
34         &&
35         (err_code != NRF_ERROR_INVALID_STATE)
36         &&
37         (err_code != BLE_ERROR_NO_TX_BUFFERS)
38         &&
39         (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
40     )
41     {
42         APP_ERROR_HANDLER(err_code);
43     }
44 }

时钟创建后并不会自动运行,当调用application_timers_start后时钟开始运行:

 1 /**@brief Function for starting the application timers.
 2  */
 3 static void application_timers_start(void)
 4 {
 5     uint32_t err_code;
 6
 7     // Start application timers
 8     err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
 9     APP_ERROR_CHECK(err_code);
10
11     err_code = app_timer_start(m_heart_rate_timer_id, HEART_RATE_MEAS_INTERVAL, NULL);
12     APP_ERROR_CHECK(err_code);
13 } 


services_init()初始化程序中的三个服务:ble_dis.c, ble_bas.c, ble_hrs.c

 1 /**@brief Function for initializing the services that will be used by the application.
 2  *
 3  * @details Initialize the Heart Rate, Battery and Device Information services.
 4  */
 5 static void services_init(void)
 6 {
 7     uint32_t       err_code;
 8     ble_hrs_init_t hrs_init;
 9     ble_bas_init_t bas_init;
10     ble_dis_init_t dis_init;
11     uint8_t        body_sensor_location;
12
13     // Initialize Heart Rate Service
14     body_sensor_location = BLE_HRS_BODY_SENSOR_LOCATION_FINGER;
15
16     memset(&hrs_init, 0, sizeof(hrs_init));
17
18     hrs_init.evt_handler = hrs_event_handler;
19     hrs_init.is_sensor_contact_supported = false;
20     hrs_init.p_body_sensor_location      = &body_sensor_location;
21
22     // Here the sec level for the Heart Rate Service can be changed/increased.
23     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_hrm_attr_md.cccd_write_perm);
24     BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.read_perm);
25     BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_hrm_attr_md.write_perm);
26
27     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&hrs_init.hrs_bsl_attr_md.read_perm);
28     BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hrs_init.hrs_bsl_attr_md.write_perm);
29
30     err_code = ble_hrs_init(&m_hrs, &hrs_init);
31     APP_ERROR_CHECK(err_code);
32
33     // Initialize Battery Service
34     memset(&bas_init, 0, sizeof(bas_init));
35
36     // Here the sec level for the Battery Service can be changed/increased.
37     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.cccd_write_perm);
38     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_char_attr_md.read_perm);
39     BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&bas_init.battery_level_char_attr_md.write_perm);
40
41     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&bas_init.battery_level_report_read_perm);
42
43     bas_init.evt_handler          = NULL;
44     bas_init.support_notification = true;
45     bas_init.p_report_ref         = NULL;
46     bas_init.initial_batt_level   = 100;
47
48     err_code = ble_bas_init(&bas, &bas_init);
49     APP_ERROR_CHECK(err_code);
50
51     // Initialize Device Information Service
52     memset(&dis_init, 0, sizeof(dis_init));
53
54     ble_srv_ascii_to_utf8(&dis_init.manufact_name_str, MANUFACTURER_NAME);
55
56     BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dis_init.dis_attr_md.read_perm);
57     BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&dis_init.dis_attr_md.write_perm);
58
59     err_code = ble_dis_init(&dis_init);
60     APP_ERROR_CHECK(err_code);
61 }

static ble_hrs_t的结构定义:

 1 /**@brief Heart Rate Service structure. This contains various status information for the service. */
 2 typedef struct ble_hrs_s
 3 {
 4     ble_hrs_evt_handler_t        evt_handler;                                          /**< Event handler to be called for handling events in the Heart Rate Service. */
 5     bool                         is_expended_energy_supported;                         /**< TRUE if Expended Energy measurement is supported. */
 6     bool                         is_sensor_contact_supported;                          /**< TRUE if sensor contact detection is supported. */
 7     uint16_t                     service_handle;                                       /**< Handle of Heart Rate Service (as provided by the BLE stack). */
 8     ble_gatts_char_handles_t     hrm_handles;                                          /**< Handles related to the Heart Rate Measurement characteristic. */
 9     ble_gatts_char_handles_t     bsl_handles;                                          /**< Handles related to the Body Sensor Location characteristic. */
10     ble_gatts_char_handles_t     hrcp_handles;                                         /**< Handles related to the Heart Rate Control Point characteristic. */
11     uint16_t                     conn_handle;                                          /**< Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
12     bool                         is_sensor_contact_detected;                           /**< TRUE if sensor contact has been detected. */
13     uint16_t                     rr_interval[BLE_HRS_MAX_BUFFERED_RR_INTERVALS];       /**< Set of RR Interval measurements since the last Heart Rate Measurement transmission. */
14     uint16_t                     rr_interval_count;                                    /**< Number of RR Interval measurements since the last Heart Rate Measurement transmission. */
15 } ble_hrs_t; 

ble_hrs.h/ble_hrs.c是心率计程序服务的代码。

 1 /** @file
 2  *
 3  * @defgroup ble_sdk_srv_hrs Heart Rate Service
 4  * @{
 5  * @ingroup ble_sdk_srv
 6  * @brief Heart Rate Service module.
 7  *
 8  * @details This module implements执行 the Heart Rate Service with the Heart Rate Measurement,
 9  *          Body Sensor Location and Heart Rate Control Point characteristics.
10  *          During initialization it adds the Heart Rate Service and Heart Rate Measurement
11  *          characteristic to the BLE stack database. Optionally it also adds the
12  *          Body Sensor Location and Heart Rate Control Point characteristics.
13  *
14  *          If enabled, notification of the Heart Rate Measurement characteristic is performed
15  *          when the application calls ble_hrs_heart_rate_measurement_send().
16  *
17  *          The Heart Rate Service also provides a set of functions for manipulating the
18  *          various fields in the Heart Rate Measurement characteristic, as well as setting
19  *          the Body Sensor Location characteristic value.
20  *
21  *          If an event handler is supplied by the application, the Heart Rate Service will
22  *          generate Heart Rate Service events to the application.
23  *
24  * @note The application must propagate BLE stack events to the Heart Rate Service module by calling
25  *       ble_hrs_on_ble_evt() from the from the @ref ble_stack_handler callback.
26  *
27  * @note Attention!
28  *  To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
29  *  qualification listings, this section of source code must not be modified.
30  */

buttons_init(void)初始化两个按钮:HR_INC_BUTTON_PIN_NO和HR_DEC_BUTTON_PIN_NO,分别模拟心率计的加减。

 1 /**@brief Function for initializing the button module.
 2  */
 3 static void buttons_init(void)
 4 {
 5     // Configure HR_INC_BUTTON_PIN_NO and HR_DEC_BUTTON_PIN_NO as wake up buttons and also configure
 6     // for ‘pull up‘ because the eval board does not have external pull up resistors connected to
 7     // the buttons.
 8     static app_button_cfg_t buttons[] =
 9     {
10         {HR_INC_BUTTON_PIN_NO, false, BUTTON_PULL, button_event_handler},
11         {HR_DEC_BUTTON_PIN_NO, false, BUTTON_PULL, button_event_handler}  // Note: This pin is also BONDMNGR_DELETE_BUTTON_PIN_NO
12     };
13
14     APP_BUTTON_INIT(buttons, sizeof(buttons) / sizeof(buttons[0]), BUTTON_DETECTION_DELAY, false);
15 }  

当按下按钮时,处理程序是button_event_handler(),它处理心率计的加减模拟:

 1 /**@brief Function for handling button events.
 2  *
 3  * @param[in]   pin_no   The pin number of the button pressed.
 4  */
 5 static void button_event_handler(uint8_t pin_no)
 6 {
 7     switch (pin_no)
 8     {
 9         case HR_INC_BUTTON_PIN_NO:
10             // Increase Heart Rate measurement
11             m_cur_heart_rate += HEART_RATE_CHANGE;
12             if (m_cur_heart_rate > MAX_HEART_RATE)
13             {
14                 m_cur_heart_rate = MIN_HEART_RATE; // Loop back
15             }
16             break;
17
18         case HR_DEC_BUTTON_PIN_NO:
19             // Decrease Heart Rate measurement
20             m_cur_heart_rate -= HEART_RATE_CHANGE;
21             if (m_cur_heart_rate < MIN_HEART_RATE)
22             {
23                 m_cur_heart_rate = MAX_HEART_RATE; // Loop back
24             }
25             break;
26
27         default:
28             APP_ERROR_HANDLER(pin_no);
29             break;
30     }
31 }

注:

本篇讲了整个工程的大致结构

下一篇具体分析几个服务

More:

[蓝牙] 1、蓝牙核心技术了解(蓝牙协议、架构、硬件和软件笔记)

[蓝牙] 2、蓝牙BLE协议及架构浅析&&基于广播超时待机说广播事件

@beautifulzzzz 2015-12-13 continue~

时间: 2024-12-05 09:26:31

[蓝牙] 3、<KEIL path> \ARM\Device\Nordic\nrf51822\Board\pca10001\s110\ble_app_hrs BLE心率检测工程的相关文章

&lt;转&gt;主流蓝牙BLE控制芯片详解(4):Nordic nRF51822

导读] nRF51822 是功能强大.高灵活性的多协议 SoC,非常适用于 Bluetooth® 低功耗和 2.4GHz 超低功耗无线应用. 同系列芯片资料推荐:    主流蓝牙BLE控制芯片详解(1):TI CC2540    主流蓝牙BLE控制芯片详解(2):CSR BC6130    主流蓝牙BLE控制芯片详解(3):创杰 IS1685S Nordic nRF51822简介 nRF51822 是功能强大.高灵活性的多协议 SoC,非常适用于 Bluetooth® 低功耗和 2.4GHz 超

Keil for ARM与C++

1. 如果你的程序中使用了C++全局变量,那么*不要*使用MicroLIB,否则Keil会说某某Symbol找不到 2. 不使用MicroLIB带来的一个问题是KEIL会使用semihosting SWI完成sys_io(例如printf的时候),我们需要一个retarget.c来禁止semihosting.KEIL提供该文件的模版(包括最小版和完全版,见下文),改改就是了 3. retarget.c也有最小版和完全版:最小版除实现fputc及辅助函数用于printf外,只实现了sys_io中的

由MTK平台 mtkfb 设备注册疑问引发的知识延伸--ARM Device Tree

问题: 在kernel-3.10\drivers\misc\mediatek\videox\mt6735\mtkfb.c里面int __init mtkfb_init(void) 有看到 platform_driver_register(&mtkfb_driver)注册, 但在kerne l整体代码目录搜索,没有搜到 mtkfb_driver 对应的设备名为“mtkfb”设备注册, ,唯一搜到:kernel-3.10\drivers\misc\mediatek\mach\mt6735\mt_de

关于linux ARM device tree设备树

关于linux ARM device tree设备树 关于linux device tree .dtb文件是如何加载到内核并解析的.见下图: 关于arm device tree的phandle的处理原理,见下图: 详细情况,见下面我的ARM device tree原理视频课程:https://edu.51cto.com/course/17175.html 具体请参考我的免费的linux各种驱动开发课程如下:https://edu.51cto.com/course/17138.html 另外我的相

NORDIC内核ARM蓝牙芯片NRF51802/NRF51822

Nordic  nRF51 系列的IC 和协议堆栈对内存大小.封装类型.接口.周边产品及无线连接提供更多选择. 关于 nRF51 系列 多协议 2.4GHz 射频收发器拥有高性能.超低功耗以及灵活性等好处.它的主要功能包括: 在蓝牙低功耗模式下灵敏度为-92.5dB RX, 高达 +4dBm 的输出功率: 与 Nordic 上一代射频收发器相比,链接预算增强高达 9.5dBm: 低于10mA 的峰值电流适合3V 纽扣电池: 符合蓝牙低功耗(蓝牙 4.0 )标准: 与 Nordic 现有的 nRF

Linux 3.10 ARM Device Tree 的初始化

转载:http://blog.chinaunix.net/uid-20522771-id-3785808.html 本文代码均来自标准 linux kernel 3.10,可以到这里下载 https://www.kernel.org/     以 arch/arm/mach-msm/board-dt-8960.c 为例,在该文件中的 msm_dt_init 函数的作用就是利用 dt(device tree)结构初始化 platform device. static void __init msm

使用nRF51822创建一个简单的BLE应用 ---入门实例手册(中文)之三

3 最小BLE应用简介 这个章节简单介绍了在nRF51822芯片上使用S110 SoftDevice协议栈构建一个最小的BLE应用的过程. 3.1初始化介绍 有一些初始化函数通常在执行一个BLE应用之前调用,下面的表格中列出了这些初始化调用函数,在后面将对它们进行详细的介绍. 大部分采用数据结构的形式作为输入参数,这些数据结构包含一系列的配置和选项信息,阅读代码中的注释能更好地理解它们. 在广播开始之后,你就进入了main函数中的for循环. 3.2 协议栈S110 SoftDevice 为了使

1、第一个程序控制LED(包括如何烧写程序)

C:\Keil-ARM\ARM\Device\Nordic\nrf51822\Board\pca10001 第一个程序控制LED C:\Keil-ARM\ARM\Device\Nordic\nrf51822\Board\pca10001\blinky_example 32页介绍如何烧写程序 只要连接一个mini USB就可以进行烧写(要使用: 操作步骤:1. 如6.1.1节所述 “选择要进行操作的目标板”然后选择“Program Application“ .2. 单击“Browse “定位应用程

[编译] 4、在Linux下搭建nRF51822的开发烧写环境(makefile版)

星期日, 09. 九月 2018 07:51下午 - beautifulzzzz 1.安装步骤 1) 从GNU Arm Embedded Toolchain官网下载最新的gcc-arm工具链,写文章时下载的是: gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2 2) 从NORDIC官网下载相应版本的SDK,我这里选择的是12.3.0版本: Code Name Version nRF5-SDK-v12-zip nRF5 SDK Zip File