[藍牙] 三、 剖析BLE心率檢測工程

 

 

位於:<KEIL path> \ARM\Device\Nordic\nrf51822\Board\pca10001\s110\ble_app_hrs html

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.app

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

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:oop

  • Heart Rate
  • RR Interval
  • Sensor Contact Detected

Also, a timer for generating battery measurements is started.post

The sensor measurements are simulated the following way:性能

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.ui

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).this

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);
一、參數宏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);
二、函數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:
相關文章
相關標籤/搜索