Heart Rate Monitor example for the BLE API using ST BlueNRG native drivers

Dependencies:   BLE_API X_NUCLEO_IDB0XA1 mbed

Getting started with X-NUCLEO-IDB05A1

This example demonstrates how to use the X-NUCLEO-IDB05A1 component with one of the STM32 Nucleo platforms tested with the to obtain heart rate information:

First, attach the X-NUCLEO-IDB05A1 to the STM32 Nucleo platform as shown here: /media/uploads/apalmieri/nucleoble.jpg

Next, connect the STM32 Nucleo platform to your PC with a USB-mini USB cable.

Now return to the BLE_HeartRate_IDB0XA1 project homepage and import the project into your mbed compiler:

/media/uploads/apalmieri/homepage.jpg

Click “Import” button on the pop up window shown below

/media/uploads/apalmieri/import.jpg

Compile and load the image onto the STM32 Nucleo platform

Upon a successful compilation, a binary image will be created and a dialog box will ask you where to save it.

/media/uploads/apalmieri/xsaveimage.jpg

Now you can load the compiled code onto your Nucleo platform by saving the newly created binary file to your STM32 Nucleo drive.

Open a terminal window to display the status of your Bluetooth stack. For this example, set the terminal BAUD rate to 9600

Note

Included within the USB interface of the STM32 Nucleo platform is a Virtual COM port that can be used to send back messages to your PC within your embedded code.
You need a terminal emulator installed on your PC to perform serial communications with your STM32 Nucleo platform. If you do not have a terminal emulation program on your PC we recommend you download and install one of the following terminal emulation programs:

Upon a successful serial connection, you should now see the various Bluetooth stack status displayed on your console output.

/media/uploads/apalmieri/xteraterm.png

Test your application with an Android or iOS device

/media/uploads/apalmieri/1.splashscreen_800x1280.png

  • On the STM32 BLE Profiles app select HeartRateSensor

/media/uploads/apalmieri/2.scanningdevice_800x1280.png

  • Select Heart Rate

/media/uploads/apalmieri/3.profileselection_800x1280.png /media/uploads/apalmieri/7.heartrate_800x1280.png

Committer:
apalmieri
Date:
Wed Oct 05 09:16:58 2016 +0000
Revision:
21:0e7c08f5386f
Parent:
14:f715c13eb84f
Child:
22:94afa3edefb3
Minor change (bps values range)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:eb7f02ad28a7 1 /* mbed Microcontroller Library
screamer 0:eb7f02ad28a7 2 * Copyright (c) 2006-2015 ARM Limited
screamer 0:eb7f02ad28a7 3 *
screamer 0:eb7f02ad28a7 4 * Licensed under the Apache License, Version 2.0 (the "License");
screamer 0:eb7f02ad28a7 5 * you may not use this file except in compliance with the License.
screamer 0:eb7f02ad28a7 6 * You may obtain a copy of the License at
screamer 0:eb7f02ad28a7 7 *
screamer 0:eb7f02ad28a7 8 * http://www.apache.org/licenses/LICENSE-2.0
screamer 0:eb7f02ad28a7 9 *
screamer 0:eb7f02ad28a7 10 * Unless required by applicable law or agreed to in writing, software
screamer 0:eb7f02ad28a7 11 * distributed under the License is distributed on an "AS IS" BASIS,
screamer 0:eb7f02ad28a7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
screamer 0:eb7f02ad28a7 13 * See the License for the specific language governing permissions and
screamer 0:eb7f02ad28a7 14 * limitations under the License.
screamer 0:eb7f02ad28a7 15 */
screamer 0:eb7f02ad28a7 16
screamer 0:eb7f02ad28a7 17 #include "mbed.h"
screamer 0:eb7f02ad28a7 18 #include "ble/BLE.h"
screamer 0:eb7f02ad28a7 19 #include "ble/services/HeartRateService.h"
screamer 0:eb7f02ad28a7 20
apalmieri 13:227a0149b677 21 DigitalOut led1(LED1, 1);
screamer 0:eb7f02ad28a7 22
screamer 0:eb7f02ad28a7 23 const static char DEVICE_NAME[] = "HRM1";
apalmieri 13:227a0149b677 24 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
apalmieri 13:227a0149b677 25
screamer 0:eb7f02ad28a7 26 static volatile bool triggerSensorPolling = false;
screamer 0:eb7f02ad28a7 27
apalmieri 2:bc0c0d442a24 28 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
screamer 0:eb7f02ad28a7 29 {
apalmieri 13:227a0149b677 30 (void)params;
apalmieri 13:227a0149b677 31 BLE::Instance().gap().startAdvertising(); // restart advertising
screamer 0:eb7f02ad28a7 32 }
screamer 0:eb7f02ad28a7 33
screamer 0:eb7f02ad28a7 34 void periodicCallback(void)
screamer 0:eb7f02ad28a7 35 {
screamer 0:eb7f02ad28a7 36 led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
screamer 0:eb7f02ad28a7 37 /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
screamer 0:eb7f02ad28a7 38 * heavy-weight sensor polling from the main thread. */
screamer 0:eb7f02ad28a7 39 triggerSensorPolling = true;
screamer 0:eb7f02ad28a7 40 }
screamer 0:eb7f02ad28a7 41
apalmieri 13:227a0149b677 42 void onBleInitError(BLE &ble, ble_error_t error)
apalmieri 13:227a0149b677 43 {
apalmieri 13:227a0149b677 44 (void)ble;
apalmieri 13:227a0149b677 45 (void)error;
apalmieri 13:227a0149b677 46 /* Initialization error handling should go here */
apalmieri 13:227a0149b677 47 }
apalmieri 13:227a0149b677 48
apalmieri 13:227a0149b677 49 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
screamer 0:eb7f02ad28a7 50 {
apalmieri 13:227a0149b677 51 BLE& ble = params->ble;
apalmieri 13:227a0149b677 52 ble_error_t error = params->error;
screamer 0:eb7f02ad28a7 53
apalmieri 13:227a0149b677 54 if (error != BLE_ERROR_NONE) {
apalmieri 13:227a0149b677 55 onBleInitError(ble, error);
apalmieri 13:227a0149b677 56 return;
apalmieri 13:227a0149b677 57 }
apalmieri 13:227a0149b677 58
apalmieri 13:227a0149b677 59 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
apalmieri 13:227a0149b677 60 return;
apalmieri 13:227a0149b677 61 }
apalmieri 13:227a0149b677 62
screamer 0:eb7f02ad28a7 63 ble.gap().onDisconnection(disconnectionCallback);
screamer 0:eb7f02ad28a7 64
screamer 0:eb7f02ad28a7 65 /* Setup primary service. */
apalmieri 21:0e7c08f5386f 66 uint8_t hrmCounter = 60; // init HRM to 60bps
screamer 0:eb7f02ad28a7 67 HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
screamer 0:eb7f02ad28a7 68
screamer 0:eb7f02ad28a7 69 /* Setup advertising. */
screamer 0:eb7f02ad28a7 70 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
screamer 0:eb7f02ad28a7 71 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
screamer 0:eb7f02ad28a7 72 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
screamer 0:eb7f02ad28a7 73 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
screamer 0:eb7f02ad28a7 74 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
screamer 0:eb7f02ad28a7 75 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
screamer 0:eb7f02ad28a7 76 ble.gap().startAdvertising();
screamer 0:eb7f02ad28a7 77
screamer 0:eb7f02ad28a7 78 // infinite loop
apalmieri 13:227a0149b677 79 while (true) {
screamer 0:eb7f02ad28a7 80 // check for trigger from periodicCallback()
screamer 0:eb7f02ad28a7 81 if (triggerSensorPolling && ble.getGapState().connected) {
screamer 0:eb7f02ad28a7 82 triggerSensorPolling = false;
screamer 0:eb7f02ad28a7 83
screamer 0:eb7f02ad28a7 84 // Do blocking calls or whatever is necessary for sensor polling.
screamer 0:eb7f02ad28a7 85 // In our case, we simply update the HRM measurement.
screamer 0:eb7f02ad28a7 86 hrmCounter++;
screamer 0:eb7f02ad28a7 87
apalmieri 21:0e7c08f5386f 88 // 60 <= HRM bps <= 100
apalmieri 21:0e7c08f5386f 89 if (hrmCounter == 100) {
apalmieri 21:0e7c08f5386f 90 hrmCounter = 60;
screamer 0:eb7f02ad28a7 91 }
screamer 0:eb7f02ad28a7 92
screamer 0:eb7f02ad28a7 93 // update bps
screamer 0:eb7f02ad28a7 94 hrService.updateHeartRate(hrmCounter);
screamer 0:eb7f02ad28a7 95 } else {
screamer 0:eb7f02ad28a7 96 ble.waitForEvent(); // low power wait for event
screamer 0:eb7f02ad28a7 97 }
screamer 0:eb7f02ad28a7 98 }
screamer 0:eb7f02ad28a7 99 }
apalmieri 13:227a0149b677 100
apalmieri 13:227a0149b677 101 int main(void)
apalmieri 13:227a0149b677 102 {
apalmieri 13:227a0149b677 103 Ticker ticker;
apalmieri 13:227a0149b677 104 ticker.attach(periodicCallback, 1); // blink LED every second
apalmieri 13:227a0149b677 105
apalmieri 13:227a0149b677 106 BLE::Instance().init(bleInitComplete);
apalmieri 13:227a0149b677 107 }
apalmieri 14:f715c13eb84f 108