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:
nikapov
Date:
Thu Aug 09 14:07:14 2018 +0000
Revision:
22:94afa3edefb3
Parent:
21:0e7c08f5386f
Update mbed lib.

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
nikapov 22:94afa3edefb3 21 #if !defined(IDB0XA1_D13_PATCH)
nikapov 22:94afa3edefb3 22 DigitalOut led1(LED1, 1); // LED conflicts SPI_CLK in case of D13 patch
nikapov 22:94afa3edefb3 23 #endif
screamer 0:eb7f02ad28a7 24
screamer 0:eb7f02ad28a7 25 const static char DEVICE_NAME[] = "HRM1";
apalmieri 13:227a0149b677 26 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
apalmieri 13:227a0149b677 27
screamer 0:eb7f02ad28a7 28 static volatile bool triggerSensorPolling = false;
screamer 0:eb7f02ad28a7 29
apalmieri 2:bc0c0d442a24 30 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
screamer 0:eb7f02ad28a7 31 {
apalmieri 13:227a0149b677 32 (void)params;
apalmieri 13:227a0149b677 33 BLE::Instance().gap().startAdvertising(); // restart advertising
screamer 0:eb7f02ad28a7 34 }
screamer 0:eb7f02ad28a7 35
screamer 0:eb7f02ad28a7 36 void periodicCallback(void)
screamer 0:eb7f02ad28a7 37 {
nikapov 22:94afa3edefb3 38 #if !defined(IDB0XA1_D13_PATCH)
screamer 0:eb7f02ad28a7 39 led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
nikapov 22:94afa3edefb3 40 #endif
nikapov 22:94afa3edefb3 41
screamer 0:eb7f02ad28a7 42 /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
screamer 0:eb7f02ad28a7 43 * heavy-weight sensor polling from the main thread. */
screamer 0:eb7f02ad28a7 44 triggerSensorPolling = true;
screamer 0:eb7f02ad28a7 45 }
screamer 0:eb7f02ad28a7 46
apalmieri 13:227a0149b677 47 void onBleInitError(BLE &ble, ble_error_t error)
apalmieri 13:227a0149b677 48 {
apalmieri 13:227a0149b677 49 (void)ble;
apalmieri 13:227a0149b677 50 (void)error;
apalmieri 13:227a0149b677 51 /* Initialization error handling should go here */
apalmieri 13:227a0149b677 52 }
apalmieri 13:227a0149b677 53
apalmieri 13:227a0149b677 54 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
screamer 0:eb7f02ad28a7 55 {
apalmieri 13:227a0149b677 56 BLE& ble = params->ble;
apalmieri 13:227a0149b677 57 ble_error_t error = params->error;
screamer 0:eb7f02ad28a7 58
apalmieri 13:227a0149b677 59 if (error != BLE_ERROR_NONE) {
apalmieri 13:227a0149b677 60 onBleInitError(ble, error);
apalmieri 13:227a0149b677 61 return;
apalmieri 13:227a0149b677 62 }
apalmieri 13:227a0149b677 63
apalmieri 13:227a0149b677 64 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
apalmieri 13:227a0149b677 65 return;
apalmieri 13:227a0149b677 66 }
apalmieri 13:227a0149b677 67
screamer 0:eb7f02ad28a7 68 ble.gap().onDisconnection(disconnectionCallback);
screamer 0:eb7f02ad28a7 69
screamer 0:eb7f02ad28a7 70 /* Setup primary service. */
apalmieri 21:0e7c08f5386f 71 uint8_t hrmCounter = 60; // init HRM to 60bps
screamer 0:eb7f02ad28a7 72 HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
screamer 0:eb7f02ad28a7 73
screamer 0:eb7f02ad28a7 74 /* Setup advertising. */
screamer 0:eb7f02ad28a7 75 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
screamer 0:eb7f02ad28a7 76 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
screamer 0:eb7f02ad28a7 77 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
screamer 0:eb7f02ad28a7 78 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
screamer 0:eb7f02ad28a7 79 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
screamer 0:eb7f02ad28a7 80 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
screamer 0:eb7f02ad28a7 81 ble.gap().startAdvertising();
screamer 0:eb7f02ad28a7 82
screamer 0:eb7f02ad28a7 83 // infinite loop
apalmieri 13:227a0149b677 84 while (true) {
screamer 0:eb7f02ad28a7 85 // check for trigger from periodicCallback()
screamer 0:eb7f02ad28a7 86 if (triggerSensorPolling && ble.getGapState().connected) {
screamer 0:eb7f02ad28a7 87 triggerSensorPolling = false;
screamer 0:eb7f02ad28a7 88
screamer 0:eb7f02ad28a7 89 // Do blocking calls or whatever is necessary for sensor polling.
screamer 0:eb7f02ad28a7 90 // In our case, we simply update the HRM measurement.
screamer 0:eb7f02ad28a7 91 hrmCounter++;
screamer 0:eb7f02ad28a7 92
apalmieri 21:0e7c08f5386f 93 // 60 <= HRM bps <= 100
apalmieri 21:0e7c08f5386f 94 if (hrmCounter == 100) {
apalmieri 21:0e7c08f5386f 95 hrmCounter = 60;
screamer 0:eb7f02ad28a7 96 }
screamer 0:eb7f02ad28a7 97
screamer 0:eb7f02ad28a7 98 // update bps
screamer 0:eb7f02ad28a7 99 hrService.updateHeartRate(hrmCounter);
screamer 0:eb7f02ad28a7 100 } else {
screamer 0:eb7f02ad28a7 101 ble.waitForEvent(); // low power wait for event
screamer 0:eb7f02ad28a7 102 }
screamer 0:eb7f02ad28a7 103 }
screamer 0:eb7f02ad28a7 104 }
apalmieri 13:227a0149b677 105
apalmieri 13:227a0149b677 106 int main(void)
apalmieri 13:227a0149b677 107 {
apalmieri 13:227a0149b677 108 Ticker ticker;
apalmieri 13:227a0149b677 109 ticker.attach(periodicCallback, 1); // blink LED every second
apalmieri 13:227a0149b677 110
apalmieri 13:227a0149b677 111 BLE::Instance().init(bleInitComplete);
apalmieri 13:227a0149b677 112 }
apalmieri 14:f715c13eb84f 113