位于:<KEIL path> \ARM\Device\Nordic\nrf51822\Board\pca10001\s110\ble_app_hrs
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:
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:
Also, a timer for generating battery measurements is started.
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.
Instructions on how to set up the nRFgo Motherboard: nRFgo Motherboard Setup (nRF6310).
LED assignments:
Buttons assignments:
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:
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。
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 }
注:
本篇讲了整个工程的大致结构[蓝牙] 2、蓝牙BLE协议及架构浅析&&基于广播超时待机说广播事件
@beautifulzzzz 2015-12-13 continue~