This application transmits a heart rate value using the Bluetooth SIG Heart Rate Profile. The heart rate value is provided by the application itself, not by a sensor, so that you don't have to get a sensor just to run the example. The canonical source for this example lives at https://github.com/ARMmbed/mbed-os-example-ble/tree/master/BLE_HeartRate

BLE Heart Rate Monitor

This application transmits a heart rate value using the Bluetooth SIG Heart Rate Profile. The heart rate value is provided by the application itself, not by a sensor, so that you don't have to get a sensor just to run the example.

Technical details are better presented in the mbed Classic equivalent of this example.

Running the application

Requirements

To see the heart rate information on your phone, download Panobike for iOS or Android.

You could also use a generic BLE scanners:

- nRF Master Control Panel for Android.

- LightBlue for iPhone.

Hardware requirements are in the main readme.

Building instructions

Building with mbed-cli

If you'd like to use mbed-cli to build this, then you should refer to the main readme. The instructions here relate to using the developer.mbed.org Online Compiler

In order to build this example in the mbed Online Compiler, first import the example using the ‘Import’ button on the right hand side.

Next, select a platform to build for. This must either be a platform that supports BLE, for example the NRF51-DK, or one of the following:

List of platforms supporting Bluetooth Low Energy

Or you must also add a piece of hardware and the supporting library that includes a Bluetooth Low Energy driver for that hardware, for example the K64F or NUCLEO_F401RE with the X-NUCLEO-IDB05A1

List of components supporting Bluetooth Low Energy.

Once you have selected your platform, compile the example and drag and drop the resulting binary onto your board.

For general instructions on using the mbed Online Compiler, please see the mbed Handbook

Checking for success

Note: Screens captures depicted below show what is expected from this example if the scanner used is nRF Master Control Panel version 4.0.5. If you encounter any difficulties consider trying another scanner or another version of nRF Master Control Panel. Alternative scanners may require reference to their manuals.

  • Build the application and install it on your board as explained in the building instructions.
  • Open the BLE scanner on your phone.
  • Start a scan.

/media/uploads/vcoubard/start_scan.png

figure 1 How to start scan using nRF Master Control Panel 4.0.5

  • Find your device; it should be named `HRM`.

/media/uploads/vcoubard/scan_result.png

figure 2 Scan results using nRF Master Control Panel 4.0.5

  • Establish a connection with your device.

/media/uploads/vcoubard/connection.png

figure 3 How to establish a connection using Master Control Panel 4.0.5

  • Discover the services and the characteristics on the device. The *Heart Rate* service has the UUID `0x180D` and includes the *Heart Rate Measurement* characteristic which has the UUID `0x2A37`.

/media/uploads/vcoubard/discovery.png

figure 4 Representation of the Heart Rate service using Master Control Panel 4.0.5

  • Register for the notifications sent by the Heart Rate Measurement characteristic.

/media/uploads/vcoubard/register_to_notifications.png

figure 5 How to register to notifications using Master Control Panel 4.0.5

  • You should see the heart rate value change every half second. It begins at 100, goes up to 175 (in steps of 1), resets to 100 and so on.

/media/uploads/vcoubard/notifications.png

figure 6 Notifications view using Master Control Panel 4.0.5

Committer:
mbed_official
Date:
Mon Jan 14 10:45:44 2019 +0000
Revision:
73:633b44bce5fc
Parent:
43:fb2855f7754b
Merge pull request #208 from ARMmbed/mbed-os-5.11.0-oob

Mbed OS 5.11.0
.
Commit copied from https://github.com/ARMmbed/mbed-os-example-ble

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 1:72c60abef7e7 1 /* mbed Microcontroller Library
mbed_official 1:72c60abef7e7 2 * Copyright (c) 2006-2015 ARM Limited
mbed_official 1:72c60abef7e7 3 *
mbed_official 1:72c60abef7e7 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 1:72c60abef7e7 5 * you may not use this file except in compliance with the License.
mbed_official 1:72c60abef7e7 6 * You may obtain a copy of the License at
mbed_official 1:72c60abef7e7 7 *
mbed_official 1:72c60abef7e7 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 1:72c60abef7e7 9 *
mbed_official 1:72c60abef7e7 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 1:72c60abef7e7 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 1:72c60abef7e7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 1:72c60abef7e7 13 * See the License for the specific language governing permissions and
mbed_official 1:72c60abef7e7 14 * limitations under the License.
mbed_official 1:72c60abef7e7 15 */
mbed_official 1:72c60abef7e7 16
mbed_official 10:ac3615194d04 17 #include <events/mbed_events.h>
mbed_official 1:72c60abef7e7 18 #include <mbed.h>
mbed_official 1:72c60abef7e7 19 #include "ble/BLE.h"
mbed_official 73:633b44bce5fc 20 #include "ble/gap/Gap.h"
mbed_official 1:72c60abef7e7 21 #include "ble/services/HeartRateService.h"
mbed_official 73:633b44bce5fc 22 #include "pretty_printer.h"
mbed_official 1:72c60abef7e7 23
mbed_official 73:633b44bce5fc 24 const static char DEVICE_NAME[] = "Heartrate";
mbed_official 73:633b44bce5fc 25
mbed_official 73:633b44bce5fc 26 static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE);
mbed_official 1:72c60abef7e7 27
mbed_official 73:633b44bce5fc 28 class HeartrateDemo : ble::Gap::EventHandler {
mbed_official 73:633b44bce5fc 29 public:
mbed_official 73:633b44bce5fc 30 HeartrateDemo(BLE &ble, events::EventQueue &event_queue) :
mbed_official 73:633b44bce5fc 31 _ble(ble),
mbed_official 73:633b44bce5fc 32 _event_queue(event_queue),
mbed_official 73:633b44bce5fc 33 _led1(LED1, 1),
mbed_official 73:633b44bce5fc 34 _connected(false),
mbed_official 73:633b44bce5fc 35 _hr_uuid(GattService::UUID_HEART_RATE_SERVICE),
mbed_official 73:633b44bce5fc 36 _hr_counter(100),
mbed_official 73:633b44bce5fc 37 _hr_service(ble, _hr_counter, HeartRateService::LOCATION_FINGER),
mbed_official 73:633b44bce5fc 38 _adv_data_builder(_adv_buffer) { }
mbed_official 1:72c60abef7e7 39
mbed_official 73:633b44bce5fc 40 void start() {
mbed_official 73:633b44bce5fc 41 _ble.gap().setEventHandler(this);
mbed_official 73:633b44bce5fc 42
mbed_official 73:633b44bce5fc 43 _ble.init(this, &HeartrateDemo::on_init_complete);
mbed_official 73:633b44bce5fc 44
mbed_official 73:633b44bce5fc 45 _event_queue.call_every(500, this, &HeartrateDemo::blink);
mbed_official 73:633b44bce5fc 46 _event_queue.call_every(1000, this, &HeartrateDemo::update_sensor_value);
mbed_official 73:633b44bce5fc 47
mbed_official 73:633b44bce5fc 48 _event_queue.dispatch_forever();
mbed_official 73:633b44bce5fc 49 }
mbed_official 1:72c60abef7e7 50
mbed_official 73:633b44bce5fc 51 private:
mbed_official 73:633b44bce5fc 52 /** Callback triggered when the ble initialization process has finished */
mbed_official 73:633b44bce5fc 53 void on_init_complete(BLE::InitializationCompleteCallbackContext *params) {
mbed_official 73:633b44bce5fc 54 if (params->error != BLE_ERROR_NONE) {
mbed_official 73:633b44bce5fc 55 printf("Ble initialization failed.");
mbed_official 73:633b44bce5fc 56 return;
mbed_official 73:633b44bce5fc 57 }
mbed_official 1:72c60abef7e7 58
mbed_official 73:633b44bce5fc 59 print_mac_address();
mbed_official 73:633b44bce5fc 60
mbed_official 73:633b44bce5fc 61 start_advertising();
mbed_official 1:72c60abef7e7 62 }
mbed_official 1:72c60abef7e7 63
mbed_official 73:633b44bce5fc 64 void start_advertising() {
mbed_official 73:633b44bce5fc 65 /* Create advertising parameters and payload */
mbed_official 1:72c60abef7e7 66
mbed_official 73:633b44bce5fc 67 ble::AdvertisingParameters adv_parameters(
mbed_official 73:633b44bce5fc 68 ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
mbed_official 73:633b44bce5fc 69 ble::adv_interval_t(ble::millisecond_t(1000))
mbed_official 73:633b44bce5fc 70 );
mbed_official 1:72c60abef7e7 71
mbed_official 73:633b44bce5fc 72 _adv_data_builder.setFlags();
mbed_official 73:633b44bce5fc 73 _adv_data_builder.setAppearance(ble::adv_data_appearance_t::GENERIC_HEART_RATE_SENSOR);
mbed_official 73:633b44bce5fc 74 _adv_data_builder.setLocalServiceList(mbed::make_Span(&_hr_uuid, 1));
mbed_official 73:633b44bce5fc 75 _adv_data_builder.setName(DEVICE_NAME);
mbed_official 1:72c60abef7e7 76
mbed_official 73:633b44bce5fc 77 /* Setup advertising */
mbed_official 73:633b44bce5fc 78
mbed_official 73:633b44bce5fc 79 ble_error_t error = _ble.gap().setAdvertisingParameters(
mbed_official 73:633b44bce5fc 80 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 73:633b44bce5fc 81 adv_parameters
mbed_official 73:633b44bce5fc 82 );
mbed_official 1:72c60abef7e7 83
mbed_official 73:633b44bce5fc 84 if (error) {
mbed_official 73:633b44bce5fc 85 printf("_ble.gap().setAdvertisingParameters() failed\r\n");
mbed_official 73:633b44bce5fc 86 return;
mbed_official 73:633b44bce5fc 87 }
mbed_official 73:633b44bce5fc 88
mbed_official 73:633b44bce5fc 89 error = _ble.gap().setAdvertisingPayload(
mbed_official 73:633b44bce5fc 90 ble::LEGACY_ADVERTISING_HANDLE,
mbed_official 73:633b44bce5fc 91 _adv_data_builder.getAdvertisingData()
mbed_official 73:633b44bce5fc 92 );
mbed_official 43:fb2855f7754b 93
mbed_official 73:633b44bce5fc 94 if (error) {
mbed_official 73:633b44bce5fc 95 printf("_ble.gap().setAdvertisingPayload() failed\r\n");
mbed_official 73:633b44bce5fc 96 return;
mbed_official 73:633b44bce5fc 97 }
mbed_official 73:633b44bce5fc 98
mbed_official 73:633b44bce5fc 99 /* Start advertising */
mbed_official 1:72c60abef7e7 100
mbed_official 73:633b44bce5fc 101 error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 73:633b44bce5fc 102
mbed_official 73:633b44bce5fc 103 if (error) {
mbed_official 73:633b44bce5fc 104 printf("_ble.gap().startAdvertising() failed\r\n");
mbed_official 73:633b44bce5fc 105 return;
mbed_official 73:633b44bce5fc 106 }
mbed_official 1:72c60abef7e7 107 }
mbed_official 1:72c60abef7e7 108
mbed_official 73:633b44bce5fc 109 void update_sensor_value() {
mbed_official 73:633b44bce5fc 110 if (_connected) {
mbed_official 73:633b44bce5fc 111 // Do blocking calls or whatever is necessary for sensor polling.
mbed_official 73:633b44bce5fc 112 // In our case, we simply update the HRM measurement.
mbed_official 73:633b44bce5fc 113 _hr_counter++;
mbed_official 73:633b44bce5fc 114
mbed_official 73:633b44bce5fc 115 // 100 <= HRM bps <=175
mbed_official 73:633b44bce5fc 116 if (_hr_counter == 175) {
mbed_official 73:633b44bce5fc 117 _hr_counter = 100;
mbed_official 73:633b44bce5fc 118 }
mbed_official 73:633b44bce5fc 119
mbed_official 73:633b44bce5fc 120 _hr_service.updateHeartRate(_hr_counter);
mbed_official 73:633b44bce5fc 121 }
mbed_official 73:633b44bce5fc 122 }
mbed_official 73:633b44bce5fc 123
mbed_official 73:633b44bce5fc 124 void blink(void) {
mbed_official 73:633b44bce5fc 125 _led1 = !_led1;
mbed_official 1:72c60abef7e7 126 }
mbed_official 1:72c60abef7e7 127
mbed_official 73:633b44bce5fc 128 private:
mbed_official 73:633b44bce5fc 129 /* Event handler */
mbed_official 1:72c60abef7e7 130
mbed_official 73:633b44bce5fc 131 void onDisconnectionComplete(const ble::DisconnectionCompleteEvent&) {
mbed_official 73:633b44bce5fc 132 _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
mbed_official 73:633b44bce5fc 133 _connected = false;
mbed_official 73:633b44bce5fc 134 }
mbed_official 73:633b44bce5fc 135
mbed_official 73:633b44bce5fc 136 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) {
mbed_official 73:633b44bce5fc 137 if (event.getStatus() == BLE_ERROR_NONE) {
mbed_official 73:633b44bce5fc 138 _connected = true;
mbed_official 73:633b44bce5fc 139 }
mbed_official 73:633b44bce5fc 140 }
mbed_official 1:72c60abef7e7 141
mbed_official 73:633b44bce5fc 142 private:
mbed_official 73:633b44bce5fc 143 BLE &_ble;
mbed_official 73:633b44bce5fc 144 events::EventQueue &_event_queue;
mbed_official 73:633b44bce5fc 145 DigitalOut _led1;
mbed_official 73:633b44bce5fc 146
mbed_official 73:633b44bce5fc 147 bool _connected;
mbed_official 73:633b44bce5fc 148
mbed_official 73:633b44bce5fc 149 UUID _hr_uuid;
mbed_official 43:fb2855f7754b 150
mbed_official 73:633b44bce5fc 151 uint8_t _hr_counter;
mbed_official 73:633b44bce5fc 152 HeartRateService _hr_service;
mbed_official 1:72c60abef7e7 153
mbed_official 73:633b44bce5fc 154 uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
mbed_official 73:633b44bce5fc 155 ble::AdvertisingDataBuilder _adv_data_builder;
mbed_official 73:633b44bce5fc 156 };
mbed_official 73:633b44bce5fc 157
mbed_official 73:633b44bce5fc 158 /** Schedule processing of events from the BLE middleware in the event queue. */
mbed_official 73:633b44bce5fc 159 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context) {
mbed_official 73:633b44bce5fc 160 event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
mbed_official 1:72c60abef7e7 161 }
mbed_official 1:72c60abef7e7 162
mbed_official 1:72c60abef7e7 163 int main()
mbed_official 1:72c60abef7e7 164 {
mbed_official 73:633b44bce5fc 165 BLE &ble = BLE::Instance();
mbed_official 73:633b44bce5fc 166 ble.onEventsToProcess(schedule_ble_events);
mbed_official 1:72c60abef7e7 167
mbed_official 73:633b44bce5fc 168 HeartrateDemo demo(ble, event_queue);
mbed_official 73:633b44bce5fc 169 demo.start();
mbed_official 1:72c60abef7e7 170
mbed_official 1:72c60abef7e7 171 return 0;
mbed_official 1:72c60abef7e7 172 }
mbed_official 73:633b44bce5fc 173