BLE Heart Rate Sample Program for HRM1017 which is using Nordic nRF51822 confirmed the connection of nRFToolbox on Android.
Dependencies: BLE_API mbed nRF51822 color_pixels
Fork of BLE_HTM_HRM1017 by
PulseSensor.cpp@11:d32f4f43161d, 2016-10-16 (annotated)
- Committer:
- YoshinoTaro
- Date:
- Sun Oct 16 14:25:59 2016 +0000
- Revision:
- 11:d32f4f43161d
Enable Heart Rate Sensor and PixelLeds;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
YoshinoTaro | 11:d32f4f43161d | 1 | #include "mbed.h" |
YoshinoTaro | 11:d32f4f43161d | 2 | #include <limits.h> |
YoshinoTaro | 11:d32f4f43161d | 3 | |
YoshinoTaro | 11:d32f4f43161d | 4 | #ifdef __cplusplus |
YoshinoTaro | 11:d32f4f43161d | 5 | extern "C" { |
YoshinoTaro | 11:d32f4f43161d | 6 | #endif // __cplusplus |
YoshinoTaro | 11:d32f4f43161d | 7 | |
YoshinoTaro | 11:d32f4f43161d | 8 | #define NEED_DEBUG |
YoshinoTaro | 11:d32f4f43161d | 9 | #ifdef NEED_DEBUG |
YoshinoTaro | 11:d32f4f43161d | 10 | #define DEBUG(...) { printf(__VA_ARGS__); } |
YoshinoTaro | 11:d32f4f43161d | 11 | #else |
YoshinoTaro | 11:d32f4f43161d | 12 | #define DEBUG(...) /* nothing */ |
YoshinoTaro | 11:d32f4f43161d | 13 | #endif |
YoshinoTaro | 11:d32f4f43161d | 14 | |
YoshinoTaro | 11:d32f4f43161d | 15 | #define N 10 |
YoshinoTaro | 11:d32f4f43161d | 16 | #define DEFAULT_THRESHOLD 500 |
YoshinoTaro | 11:d32f4f43161d | 17 | #define DEFAULT_AMP 100 |
YoshinoTaro | 11:d32f4f43161d | 18 | |
YoshinoTaro | 11:d32f4f43161d | 19 | |
YoshinoTaro | 11:d32f4f43161d | 20 | volatile int BPM = 60; |
YoshinoTaro | 11:d32f4f43161d | 21 | volatile int IBI = 600; |
YoshinoTaro | 11:d32f4f43161d | 22 | |
YoshinoTaro | 11:d32f4f43161d | 23 | volatile bool Pulse = false; |
YoshinoTaro | 11:d32f4f43161d | 24 | volatile bool QS = false; |
YoshinoTaro | 11:d32f4f43161d | 25 | |
YoshinoTaro | 11:d32f4f43161d | 26 | volatile int Rate[N]; |
YoshinoTaro | 11:d32f4f43161d | 27 | volatile int CurrentBeatTime = 0; |
YoshinoTaro | 11:d32f4f43161d | 28 | volatile int LastBeatTime = 0; |
YoshinoTaro | 11:d32f4f43161d | 29 | |
YoshinoTaro | 11:d32f4f43161d | 30 | volatile uint16_t Signal; |
YoshinoTaro | 11:d32f4f43161d | 31 | volatile uint16_t P = DEFAULT_THRESHOLD; |
YoshinoTaro | 11:d32f4f43161d | 32 | volatile uint16_t T = DEFAULT_THRESHOLD; |
YoshinoTaro | 11:d32f4f43161d | 33 | volatile uint16_t Threshold = DEFAULT_THRESHOLD; |
YoshinoTaro | 11:d32f4f43161d | 34 | |
YoshinoTaro | 11:d32f4f43161d | 35 | volatile int Amplifier = DEFAULT_AMP; |
YoshinoTaro | 11:d32f4f43161d | 36 | |
YoshinoTaro | 11:d32f4f43161d | 37 | Timer timer; |
YoshinoTaro | 11:d32f4f43161d | 38 | AnalogIn ain(p5); |
YoshinoTaro | 11:d32f4f43161d | 39 | |
YoshinoTaro | 11:d32f4f43161d | 40 | void initPulseSensor(void) { |
YoshinoTaro | 11:d32f4f43161d | 41 | for (int i = 0; i < N; ++i) { |
YoshinoTaro | 11:d32f4f43161d | 42 | Rate[i] = 0; |
YoshinoTaro | 11:d32f4f43161d | 43 | } |
YoshinoTaro | 11:d32f4f43161d | 44 | timer.start(); |
YoshinoTaro | 11:d32f4f43161d | 45 | LastBeatTime = timer.read_ms(); |
YoshinoTaro | 11:d32f4f43161d | 46 | } |
YoshinoTaro | 11:d32f4f43161d | 47 | |
YoshinoTaro | 11:d32f4f43161d | 48 | int getBPM(void) { |
YoshinoTaro | 11:d32f4f43161d | 49 | return BPM; |
YoshinoTaro | 11:d32f4f43161d | 50 | } |
YoshinoTaro | 11:d32f4f43161d | 51 | |
YoshinoTaro | 11:d32f4f43161d | 52 | bool isQS(void) { |
YoshinoTaro | 11:d32f4f43161d | 53 | bool qs = QS; |
YoshinoTaro | 11:d32f4f43161d | 54 | QS = false; |
YoshinoTaro | 11:d32f4f43161d | 55 | return qs; |
YoshinoTaro | 11:d32f4f43161d | 56 | } |
YoshinoTaro | 11:d32f4f43161d | 57 | |
YoshinoTaro | 11:d32f4f43161d | 58 | |
YoshinoTaro | 11:d32f4f43161d | 59 | void reset() { |
YoshinoTaro | 11:d32f4f43161d | 60 | Threshold = DEFAULT_THRESHOLD; |
YoshinoTaro | 11:d32f4f43161d | 61 | Amplifier = DEFAULT_AMP; |
YoshinoTaro | 11:d32f4f43161d | 62 | P = T = DEFAULT_THRESHOLD; |
YoshinoTaro | 11:d32f4f43161d | 63 | } |
YoshinoTaro | 11:d32f4f43161d | 64 | |
YoshinoTaro | 11:d32f4f43161d | 65 | void calcHeartRate(void) { |
YoshinoTaro | 11:d32f4f43161d | 66 | |
YoshinoTaro | 11:d32f4f43161d | 67 | Signal = ain.read_u16(); |
YoshinoTaro | 11:d32f4f43161d | 68 | CurrentBeatTime = timer.read_ms(); |
YoshinoTaro | 11:d32f4f43161d | 69 | // DEBUG("%d\t%d\r\n", CurrentBeatTime, Signal); |
YoshinoTaro | 11:d32f4f43161d | 70 | |
YoshinoTaro | 11:d32f4f43161d | 71 | int interval = 0; |
YoshinoTaro | 11:d32f4f43161d | 72 | if (CurrentBeatTime < LastBeatTime) { |
YoshinoTaro | 11:d32f4f43161d | 73 | interval = INT_MAX - CurrentBeatTime + LastBeatTime; |
YoshinoTaro | 11:d32f4f43161d | 74 | } else { |
YoshinoTaro | 11:d32f4f43161d | 75 | interval = CurrentBeatTime - LastBeatTime; |
YoshinoTaro | 11:d32f4f43161d | 76 | } |
YoshinoTaro | 11:d32f4f43161d | 77 | |
YoshinoTaro | 11:d32f4f43161d | 78 | if ((Signal < Threshold) && (interval > IBI * 3/5)) { |
YoshinoTaro | 11:d32f4f43161d | 79 | if (Signal < T) { // hold bottom |
YoshinoTaro | 11:d32f4f43161d | 80 | T = Signal; |
YoshinoTaro | 11:d32f4f43161d | 81 | // DEBUG("T:%d\r\n", T); |
YoshinoTaro | 11:d32f4f43161d | 82 | } |
YoshinoTaro | 11:d32f4f43161d | 83 | } else if ((Signal > Threshold) && (Signal > P)) { |
YoshinoTaro | 11:d32f4f43161d | 84 | P = Signal; // hold peak |
YoshinoTaro | 11:d32f4f43161d | 85 | // DEBUG("P:%d\r\n", P); |
YoshinoTaro | 11:d32f4f43161d | 86 | } |
YoshinoTaro | 11:d32f4f43161d | 87 | |
YoshinoTaro | 11:d32f4f43161d | 88 | if (interval > 250 && interval < 2500) { // msec |
YoshinoTaro | 11:d32f4f43161d | 89 | |
YoshinoTaro | 11:d32f4f43161d | 90 | if ((Signal > Threshold) && !Pulse && (interval > IBI * 3/5)) { |
YoshinoTaro | 11:d32f4f43161d | 91 | Pulse = true; |
YoshinoTaro | 11:d32f4f43161d | 92 | IBI = interval; |
YoshinoTaro | 11:d32f4f43161d | 93 | |
YoshinoTaro | 11:d32f4f43161d | 94 | if (Rate[0] < 0) { // first time |
YoshinoTaro | 11:d32f4f43161d | 95 | Rate[0] = 0; |
YoshinoTaro | 11:d32f4f43161d | 96 | LastBeatTime = timer.read_ms(); |
YoshinoTaro | 11:d32f4f43161d | 97 | return; |
YoshinoTaro | 11:d32f4f43161d | 98 | } else if (Rate[0] == 0) { // second time |
YoshinoTaro | 11:d32f4f43161d | 99 | for (int i = 0; i < N; ++i) { |
YoshinoTaro | 11:d32f4f43161d | 100 | Rate[i] = IBI; |
YoshinoTaro | 11:d32f4f43161d | 101 | } |
YoshinoTaro | 11:d32f4f43161d | 102 | } |
YoshinoTaro | 11:d32f4f43161d | 103 | |
YoshinoTaro | 11:d32f4f43161d | 104 | int running_total = 0; |
YoshinoTaro | 11:d32f4f43161d | 105 | for (int i = 0; i < N-1; ++i) { |
YoshinoTaro | 11:d32f4f43161d | 106 | Rate[i] = Rate[i+1]; |
YoshinoTaro | 11:d32f4f43161d | 107 | running_total += Rate[i]; |
YoshinoTaro | 11:d32f4f43161d | 108 | } |
YoshinoTaro | 11:d32f4f43161d | 109 | |
YoshinoTaro | 11:d32f4f43161d | 110 | Rate[N-1] = IBI; |
YoshinoTaro | 11:d32f4f43161d | 111 | running_total += IBI; |
YoshinoTaro | 11:d32f4f43161d | 112 | running_total /= N; |
YoshinoTaro | 11:d32f4f43161d | 113 | BPM = 60000 / running_total; |
YoshinoTaro | 11:d32f4f43161d | 114 | QS = true; |
YoshinoTaro | 11:d32f4f43161d | 115 | LastBeatTime = timer.read_ms(); |
YoshinoTaro | 11:d32f4f43161d | 116 | // DEBUG("P:%d T:%d AMP:%d THR:%d BPM:%d\r\n" |
YoshinoTaro | 11:d32f4f43161d | 117 | // ,P ,T ,Amplifier ,Threshold ,BPM); |
YoshinoTaro | 11:d32f4f43161d | 118 | } |
YoshinoTaro | 11:d32f4f43161d | 119 | } |
YoshinoTaro | 11:d32f4f43161d | 120 | |
YoshinoTaro | 11:d32f4f43161d | 121 | // check if Signal is under Threshold |
YoshinoTaro | 11:d32f4f43161d | 122 | // if (Pulse) { |
YoshinoTaro | 11:d32f4f43161d | 123 | if ((Signal < Threshold) && Pulse) { |
YoshinoTaro | 11:d32f4f43161d | 124 | Pulse = false; |
YoshinoTaro | 11:d32f4f43161d | 125 | if (P >= T) { |
YoshinoTaro | 11:d32f4f43161d | 126 | Amplifier = P - T; |
YoshinoTaro | 11:d32f4f43161d | 127 | Threshold = Amplifier/2 + T; // update Threshold |
YoshinoTaro | 11:d32f4f43161d | 128 | P = T = Threshold; |
YoshinoTaro | 11:d32f4f43161d | 129 | // DEBUG("Update Threshold:%d\r\n", Threshold); |
YoshinoTaro | 11:d32f4f43161d | 130 | } else { |
YoshinoTaro | 11:d32f4f43161d | 131 | // DEBUG("Error: T(%d) over P(%d)\r\n", T, P); |
YoshinoTaro | 11:d32f4f43161d | 132 | reset(); |
YoshinoTaro | 11:d32f4f43161d | 133 | } |
YoshinoTaro | 11:d32f4f43161d | 134 | } |
YoshinoTaro | 11:d32f4f43161d | 135 | |
YoshinoTaro | 11:d32f4f43161d | 136 | // check if no Signal is over 2.5 sec |
YoshinoTaro | 11:d32f4f43161d | 137 | if (interval >= 2500) { |
YoshinoTaro | 11:d32f4f43161d | 138 | DEBUG("No Signal over 2.5sec\r\n"); |
YoshinoTaro | 11:d32f4f43161d | 139 | reset(); |
YoshinoTaro | 11:d32f4f43161d | 140 | LastBeatTime = timer.read_ms(); |
YoshinoTaro | 11:d32f4f43161d | 141 | for (int i = 0; i < N; ++i) { |
YoshinoTaro | 11:d32f4f43161d | 142 | Rate[i] = -1; |
YoshinoTaro | 11:d32f4f43161d | 143 | } |
YoshinoTaro | 11:d32f4f43161d | 144 | } |
YoshinoTaro | 11:d32f4f43161d | 145 | } |
YoshinoTaro | 11:d32f4f43161d | 146 | |
YoshinoTaro | 11:d32f4f43161d | 147 | #ifdef __cplusplus |
YoshinoTaro | 11:d32f4f43161d | 148 | } |
YoshinoTaro | 11:d32f4f43161d | 149 | #endif |