Projet_BMC
/
HeartPulseModify
heart rate mesuarement
main.cpp@2:515e6791dfe2, 2020-01-24 (annotated)
- Committer:
- zmoutaou
- Date:
- Fri Jan 24 11:16:30 2020 +0000
- Revision:
- 2:515e6791dfe2
- Parent:
- 0:a78b08608d76
Pulse sensor
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
asagin | 0:a78b08608d76 | 1 | #include "mbed.h" |
zmoutaou | 2:515e6791dfe2 | 2 | #include "USBSerial.h" |
zmoutaou | 2:515e6791dfe2 | 3 | #include "Adafruit_SSD1306.h" |
zmoutaou | 2:515e6791dfe2 | 4 | #include <string> |
zmoutaou | 2:515e6791dfe2 | 5 | #include <sstream> |
zmoutaou | 2:515e6791dfe2 | 6 | #include <map> |
asagin | 0:a78b08608d76 | 7 | |
zmoutaou | 2:515e6791dfe2 | 8 | AnalogIn pulseIn(A0); |
zmoutaou | 2:515e6791dfe2 | 9 | using namespace std; |
zmoutaou | 2:515e6791dfe2 | 10 | USBSerial pc; |
zmoutaou | 2:515e6791dfe2 | 11 | I2C i2c(PB_9, PB_8); |
zmoutaou | 2:515e6791dfe2 | 12 | Adafruit_SSD1306_I2c oled(i2c,PC_13); |
zmoutaou | 2:515e6791dfe2 | 13 | |
zmoutaou | 2:515e6791dfe2 | 14 | |
zmoutaou | 2:515e6791dfe2 | 15 | AnalogIn pulsePin(A0); //This is signal input |
asagin | 0:a78b08608d76 | 16 | |
zmoutaou | 2:515e6791dfe2 | 17 | // these variables are because they are used during the interrupt service routine! |
zmoutaou | 2:515e6791dfe2 | 18 | int BPM; // used to hold the pulse rate |
zmoutaou | 2:515e6791dfe2 | 19 | int Signal; // holds the incoming raw data |
zmoutaou | 2:515e6791dfe2 | 20 | int IBI = 600; // holds the time between beats, the Inter-Beat Interval |
zmoutaou | 2:515e6791dfe2 | 21 | bool Pulse = false; // true when pulse wave is high, false when it's low |
zmoutaou | 2:515e6791dfe2 | 22 | bool QS = false; // becomes true when Arduoino finds a beat. |
asagin | 0:a78b08608d76 | 23 | |
zmoutaou | 2:515e6791dfe2 | 24 | void heart_rate_test(void); |
zmoutaou | 2:515e6791dfe2 | 25 | int rate[10]; // used to hold last ten IBI values |
zmoutaou | 2:515e6791dfe2 | 26 | unsigned long sampleCounter = 0; // used to determine pulse timing |
zmoutaou | 2:515e6791dfe2 | 27 | unsigned long lastBeatTime = 0; // used to find the inter beat interval |
zmoutaou | 2:515e6791dfe2 | 28 | int P =512; // used to find peak in pulse wave |
zmoutaou | 2:515e6791dfe2 | 29 | int T = 512; // used to find trough in pulse wave |
zmoutaou | 2:515e6791dfe2 | 30 | int thresh = 512; // used to find instant moment of heart beat |
zmoutaou | 2:515e6791dfe2 | 31 | int amp = 100; // used to hold amplitude of pulse waveform |
zmoutaou | 2:515e6791dfe2 | 32 | bool firstBeat = true; // used to seed rate array so we startup with reasonable BPM |
zmoutaou | 2:515e6791dfe2 | 33 | bool secondBeat = true; // used to seed rate array so we startup with reasonable BPM |
asagin | 0:a78b08608d76 | 34 | |
zmoutaou | 2:515e6791dfe2 | 35 | Ticker time_up; |
zmoutaou | 2:515e6791dfe2 | 36 | // Escreve o texto passado como parâmetro no display |
zmoutaou | 2:515e6791dfe2 | 37 | void OLED_writeString(string str, int x, int y) { |
zmoutaou | 2:515e6791dfe2 | 38 | oled.clearDisplay(); |
zmoutaou | 2:515e6791dfe2 | 39 | oled.setTextCursor(x, y); |
zmoutaou | 2:515e6791dfe2 | 40 | oled.fillRect(x, y, 128, 8, 0); |
zmoutaou | 2:515e6791dfe2 | 41 | } |
zmoutaou | 2:515e6791dfe2 | 42 | |
asagin | 0:a78b08608d76 | 43 | |
zmoutaou | 2:515e6791dfe2 | 44 | void heart_rate_test() |
zmoutaou | 2:515e6791dfe2 | 45 | { |
zmoutaou | 2:515e6791dfe2 | 46 | Signal = pulsePin.read()*1024; // read the Pulse Sensor |
zmoutaou | 2:515e6791dfe2 | 47 | sampleCounter += 2; // keep track of the time in mS with this variable |
zmoutaou | 2:515e6791dfe2 | 48 | int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid nois // find the peak and trough of the pulse wave |
zmoutaou | 2:515e6791dfe2 | 49 | if(Signal < thresh && N > (IBI/5)*3) { // avoid dichrotic noise by waiting 3/5 of last IBI |
zmoutaou | 2:515e6791dfe2 | 50 | if (Signal < T) { // T is the trough |
zmoutaou | 2:515e6791dfe2 | 51 | T = Signal; // keep track of lowest point in pulse wave |
zmoutaou | 2:515e6791dfe2 | 52 | } |
zmoutaou | 2:515e6791dfe2 | 53 | } |
zmoutaou | 2:515e6791dfe2 | 54 | |
zmoutaou | 2:515e6791dfe2 | 55 | if(Signal > thresh && Signal > P) { // thresh condition helps avoid noise |
zmoutaou | 2:515e6791dfe2 | 56 | P = Signal; // P is the peak |
zmoutaou | 2:515e6791dfe2 | 57 | } // keep track of highest point in pulse wave |
zmoutaou | 2:515e6791dfe2 | 58 | |
zmoutaou | 2:515e6791dfe2 | 59 | // NOW IT'S TIME TO LOOK FOR THE HEART BEAT |
zmoutaou | 2:515e6791dfe2 | 60 | // signal surges up in value every time there is a pulse |
zmoutaou | 2:515e6791dfe2 | 61 | if (N > 250) { // avoid high frequency noise |
zmoutaou | 2:515e6791dfe2 | 62 | if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ) { |
zmoutaou | 2:515e6791dfe2 | 63 | Pulse = true; // set the Pulse flag when we think there is a pulse |
zmoutaou | 2:515e6791dfe2 | 64 | //digitalWrite(blinkPin,HIGH); // turn on pin 13 LED |
zmoutaou | 2:515e6791dfe2 | 65 | IBI = sampleCounter - lastBeatTime; // measure time between beats in mS |
zmoutaou | 2:515e6791dfe2 | 66 | lastBeatTime = sampleCounter; // keep track of time for next pulse |
zmoutaou | 2:515e6791dfe2 | 67 | |
zmoutaou | 2:515e6791dfe2 | 68 | if(firstBeat) { // if it's the first time we found a beat, if firstBeat == TRUE |
zmoutaou | 2:515e6791dfe2 | 69 | firstBeat = false; // clear firstBeat flag |
zmoutaou | 2:515e6791dfe2 | 70 | return; // IBI value is unreliable so discard it |
zmoutaou | 2:515e6791dfe2 | 71 | } |
zmoutaou | 2:515e6791dfe2 | 72 | if(secondBeat) { // if this is the second beat, if secondBeat == TRUE |
zmoutaou | 2:515e6791dfe2 | 73 | secondBeat = false; // clear secondBeat flag |
zmoutaou | 2:515e6791dfe2 | 74 | for(int i=0; i<=9; i++) { // seed the running total to get a realisitic BPM at startup |
zmoutaou | 2:515e6791dfe2 | 75 | rate[i] = IBI; |
zmoutaou | 2:515e6791dfe2 | 76 | } |
zmoutaou | 2:515e6791dfe2 | 77 | } |
zmoutaou | 2:515e6791dfe2 | 78 | |
zmoutaou | 2:515e6791dfe2 | 79 | // keep a running total of the last 10 IBI values |
zmoutaou | 2:515e6791dfe2 | 80 | long runningTotal = 0; // clear the runningTotal variable |
zmoutaou | 2:515e6791dfe2 | 81 | |
zmoutaou | 2:515e6791dfe2 | 82 | for(int i=0; i<=8; i++) { // shift data in the rate array |
zmoutaou | 2:515e6791dfe2 | 83 | rate[i] = rate[i+1]; // and drop the oldest IBI value |
zmoutaou | 2:515e6791dfe2 | 84 | runningTotal += rate[i]; // add up the 9 oldest IBI values |
zmoutaou | 2:515e6791dfe2 | 85 | } |
zmoutaou | 2:515e6791dfe2 | 86 | |
zmoutaou | 2:515e6791dfe2 | 87 | rate[9] = IBI; // add the latest IBI to the rate array |
zmoutaou | 2:515e6791dfe2 | 88 | runningTotal += rate[9]; // add the latest IBI to runningTotal |
zmoutaou | 2:515e6791dfe2 | 89 | runningTotal /= 10; // average the last 10 IBI values |
zmoutaou | 2:515e6791dfe2 | 90 | BPM = 60000/runningTotal; // how many beats can fit into a minute? that's BPM! |
zmoutaou | 2:515e6791dfe2 | 91 | QS = true; |
zmoutaou | 2:515e6791dfe2 | 92 | string BPM_s= static_cast<ostringstream*>( &(ostringstream() << BPM) )->str(); |
zmoutaou | 2:515e6791dfe2 | 93 | OLED_writeString(BPM_s, 1, 1); |
zmoutaou | 2:515e6791dfe2 | 94 | // QS FLAG IS NOT CLEARED INSIDE THIS ISR |
zmoutaou | 2:515e6791dfe2 | 95 | } |
zmoutaou | 2:515e6791dfe2 | 96 | } |
zmoutaou | 2:515e6791dfe2 | 97 | |
zmoutaou | 2:515e6791dfe2 | 98 | if (Signal < thresh && Pulse == true) { // when the values are going down, the beat is over |
zmoutaou | 2:515e6791dfe2 | 99 | Pulse = false; // reset the Pulse flag so we can do it again |
zmoutaou | 2:515e6791dfe2 | 100 | amp = P - T; // get amplitude of the pulse wave |
zmoutaou | 2:515e6791dfe2 | 101 | thresh = amp/2 + T; // set thresh at 50% of the amplitude |
zmoutaou | 2:515e6791dfe2 | 102 | P = thresh; // reset these for next time |
zmoutaou | 2:515e6791dfe2 | 103 | T = thresh; |
zmoutaou | 2:515e6791dfe2 | 104 | } |
zmoutaou | 2:515e6791dfe2 | 105 | |
zmoutaou | 2:515e6791dfe2 | 106 | if (N > 2500) { // if 2.5 seconds go by without a beat |
zmoutaou | 2:515e6791dfe2 | 107 | thresh = 512; // set thresh default |
zmoutaou | 2:515e6791dfe2 | 108 | P = 512; // set P default |
zmoutaou | 2:515e6791dfe2 | 109 | T = 512; // set T default |
zmoutaou | 2:515e6791dfe2 | 110 | lastBeatTime = sampleCounter; // bring the lastBeatTime up to date |
zmoutaou | 2:515e6791dfe2 | 111 | firstBeat = true; // set these to avoid noise |
zmoutaou | 2:515e6791dfe2 | 112 | secondBeat = true; // when we get the heartbeat back |
zmoutaou | 2:515e6791dfe2 | 113 | } |
asagin | 0:a78b08608d76 | 114 | |
zmoutaou | 2:515e6791dfe2 | 115 | |
asagin | 0:a78b08608d76 | 116 | } |
asagin | 0:a78b08608d76 | 117 | |
asagin | 0:a78b08608d76 | 118 | |
zmoutaou | 2:515e6791dfe2 | 119 | int main() |
zmoutaou | 2:515e6791dfe2 | 120 | { |
zmoutaou | 2:515e6791dfe2 | 121 | time_up.attach(&heart_rate_test, 0.002); |
zmoutaou | 2:515e6791dfe2 | 122 | oled.clearDisplay(); |
zmoutaou | 2:515e6791dfe2 | 123 | OLED_writeString("hello world", 1, 1); |
zmoutaou | 2:515e6791dfe2 | 124 | while(true) |
zmoutaou | 2:515e6791dfe2 | 125 | { |
zmoutaou | 2:515e6791dfe2 | 126 | if (QS == true) |
zmoutaou | 2:515e6791dfe2 | 127 | { |
zmoutaou | 2:515e6791dfe2 | 128 | |
zmoutaou | 2:515e6791dfe2 | 129 | QS = false; |
zmoutaou | 2:515e6791dfe2 | 130 | //pc.printf("%d \n ",BPM); // reset the Quantified Self flag for next time |
zmoutaou | 2:515e6791dfe2 | 131 | } |
zmoutaou | 2:515e6791dfe2 | 132 | wait_ms(20); |
zmoutaou | 2:515e6791dfe2 | 133 | } |
zmoutaou | 2:515e6791dfe2 | 134 | } |
asagin | 0:a78b08608d76 | 135 | |
asagin | 0:a78b08608d76 | 136 | |
zmoutaou | 2:515e6791dfe2 | 137 | |
zmoutaou | 2:515e6791dfe2 | 138 |