0% found this document useful (0 votes)
44 views

B. Arduino Mega Program

This document provides the code for an Arduino program that monitors pulse rate using a pulse sensor and sends SMS alerts if the pulse rate is abnormal. It includes code to read pulse sensor data using interrupts, calculate BPM, check for abnormal readings, read GPS data, and assemble and send SMS messages using a GSM module. Global variables and functions are defined for pulse monitoring, GPS reading, sensor checking, SMS assembly and sending.
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
44 views

B. Arduino Mega Program

This document provides the code for an Arduino program that monitors pulse rate using a pulse sensor and sends SMS alerts if the pulse rate is abnormal. It includes code to read pulse sensor data using interrupts, calculate BPM, check for abnormal readings, read GPS data, and assemble and send SMS messages using a GSM module. Global variables and functions are defined for pulse monitoring, GPS reading, sensor checking, SMS assembly and sending.
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 23

Appendices 41

B. Arduino Mega Program

#include <LayadCircuits_SalengGSM.h>

#include <TinyGPS++.h>

#include <SoftwareSerial.h>

#include <LiquidCrystal_I2C.h>

TinyGPSPlus gps;

LiquidCrystal_I2C lcd(0x3F,16,2);

//SoftwareSerial gsmSerial(2,3);

#define gsmSerial Serial1

LayadCircuits_SalengGSM salengGSM =
LayadCircuits_SalengGSM(&gsmSerial);

TinyGPSPlus tinygps;

char PHONE[12] = "09164428565";

const int MAX_NORMAL_BPM = 100;

const int MIN_NORMAL_BPM = 50;

bool DEBUG = true;

//Pulse Variables

const byte PULSEPIN = A0;

// Pulse Sensor purple wire connected to analog pin 0

const byte SMS_DISABLE = A1;

// Volatile Variables, used in the interrupt service


routine!
Appendices 42

volatile int BPM;

// int that holds raw Analog in 0. updated every 2mS

volatile int Signal;

// holds the incoming raw data

volatile int IBI = 600;

// int that holds the time interval between beats! Must be


seeded!

volatile boolean Pulse = false;

// "True" when User's live heartbeat is detected. "False"


when not a "live beat".

volatile boolean QS = false;

// becomes true when Arduoino finds a beat.

// interrupt for Pulse Sensor

volatile int rate[10];

// array to hold last ten IBI values

volatile unsigned long sampleCounter = 0;

// used to determine pulse timing

volatile unsigned long lastBeatTime = 0;

// used to find IBI

volatile int P =512;

// used to find peak in pulse wave, seeded

volatile int T = 512;

// used to find trough in pulse wave, seeded

volatile int thresh = 515;

// used to find instant moment of heart beat, seeded


Appendices 43

volatile int amp = 100;

// used to hold amplitude of pulse waveform, seeded

volatile boolean firstBeat = true;

// used to seed rate array so we startup with reasonable


BPM

volatile boolean secondBeat = false;

// used to seed rate array so we startup with reasonable


BPM

float latitude;

float longitude;

char sms_buff[160]="";

char buf[17]="";

bool flag_abnormal_bpm;

bool flag_gps; // true when gps signal is seen

void gps_routine()

unsigned long tim;

if(Serial2.available())

tim = millis();

while(millis() - tim < 100)


Appendices 44

if(Serial2.available())

char c;

c = Serial2.read();

tinygps.encode(c);

if (!tinygps.location.isValid()) Serial.write(c); //
test only

static unsigned long t;

if(millis() - t < 1000) return;

t=millis();

if (tinygps.location.isValid())

digitalWrite(LED_BUILTIN,HIGH);

latitude = tinygps.location.lat();

longitude = tinygps.location.lng();

Serial.print(F("-----------------latitude="));
Serial.println(latitude);

Serial.print(F("-----------------longitude="));
Serial.println(longitude);
Appendices 45

else digitalWrite(LED_BUILTIN,LOW);

void interruptSetup()

// Initializes Timer2 to throw an interrupt every 2mS.

TCCR2A = 0x02;

// DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC


MODE

TCCR2B = 0x06;

// DON'T FORCE COMPARE, 256 PRESCALER

OCR2A = 0X7C;

// SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE

TIMSK2 = 0x02;

// ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A

sei();

// MAKE SURE GLOBAL INTERRUPTS ARE ENABLED

// THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE.


Appendices 46

// Timer 2 makes sure that we take a reading every 2


miliseconds

ISR(TIMER2_COMPA_vect)

// triggered when Timer2 counts to 124

cli();

// disable interrupts while we do this

Signal = analogRead(PULSEPIN);

// read the Pulse Sensor

sampleCounter += 2;

// keep track of the time in mS with this variable

int N = sampleCounter - lastBeatTime;

// monitor the time since the last beat to avoid noise

// find the peak and trough of the pulse wave

if(Signal < thresh && N > (IBI/5)*3){

// avoid dichrotic noise by waiting 3/5 of last IBI

if (Signal < T){

// T is the trough

T = Signal;

// keep track of lowest point in pulse wave

if(Signal > thresh && Signal > P){

// thresh condition helps avoid noise


Appendices 47

P = Signal;

// P is the peak

// keep track of highest point in pulse wave

// NOW IT'S TIME TO LOOK FOR THE HEART BEAT

// signal surges up in value every time there is a pulse

if (N > 250){

// avoid high frequency noise

if ( (Signal > thresh) && (Pulse == false) && (N >


(IBI/5)*3) ){

Pulse = true;

// set the Pulse flag when we think there is a pulse

IBI = sampleCounter - lastBeatTime;

// measure time between beats in mS

lastBeatTime = sampleCounter;

// keep track of time for next pulse

if(secondBeat){

// if this is the second beat, if secondBeat == TRUE

secondBeat = false;

// clear secondBeat flag

for(int i=0; i<=9; i++){

// seed the running total to get a realisitic BPM at


startup

rate[i] = IBI;
Appendices 48

if(firstBeat){

// if it's the first time we found a beat, if firstBeat ==


TRUE

firstBeat = false;

// clear firstBeat flag

secondBeat = true;

// set the second beat flag

sei();

// enable interrupts again

return;

// IBI value is unreliable so discard it

// keep a running total of the last 10 IBI values

word runningTotal = 0;

// clear the runningTotal variable

for(int i=0; i<=8; i++){

// shift data in the rate array

rate[i] = rate[i+1];

// and drop the oldest IBI value

runningTotal += rate[i];

// add up the 9 oldest IBI values


Appendices 49

rate[9] = IBI;

// add the latest IBI to the rate array

runningTotal += rate[9];

// add the latest IBI to runningTotal

runningTotal /= 10;

// average the last 10 IBI values

BPM = 60000/runningTotal;

// how many beats can fit into a minute? that's BPM!

QS = true;

// set Quantified Self flag

// QS FLAG IS NOT CLEARED INSIDE THIS ISR

if (Signal < thresh && Pulse == true){

// when the values are going down, the beat is over

Pulse = false;

// reset the Pulse flag so we can do it again

amp = P - T;

// get amplitude of the pulse wave

thresh = amp/2 + T;

// set thresh at 50% of the amplitude

P = thresh;
Appendices 50

// reset these for next time

T = thresh;

if (N > 2500){

// if 2.5 seconds go by without a beat

thresh = 512;

// set thresh default

P = 512;

// set P default

T = 512;

// set T default

lastBeatTime = sampleCounter;

// bring the lastBeatTime up to date

firstBeat = true;

// set these to avoid noise

secondBeat = false;

// when we get the heartbeat back

sei();

// enable interrupts when youre done!

void pulse_sensor()
Appendices 51

static unsigned long actual_temp;

if (millis() - actual_temp < 20) return;

actual_temp = millis();

if (QS == true)// A Heartbeat Was Found

QS = false; // reset the Quantified


Self flag for next time

void sensor_check()

static bool flagp; // tells us when the transition from


normal to abnormal occurs

static byte ctrp; // counts how many times we detected an


abnormal sensor value

static unsigned long timer;

if(millis() - timer < 100) return; // we only check every


1 second. prevent rapid checking

timer = millis();
Appendices 52

if(BPM > MAX_NORMAL_BPM || BPM < MIN_NORMAL_BPM && BPM !=


0 )

if(flagp == false)

ctrp++;

if(ctrp >= 10)

flag_abnormal_bpm = true; // flag for second phone


number

flagp = true;

else

flagp = false;

ctrp = 0;

Serial.print(F("BPM="));

Serial.println(BPM);

void sms_manager()
Appendices 53

if(digitalRead(SMS_DISABLE) == LOW)

flag_abnormal_bpm = false;

return;

if(salengGSM.isFreeToSend() == false) return; // if we are


not yet free to send then exit immediately.

static unsigned long t;

if(millis() - t < 1000) return;

t=millis();

if(flag_abnormal_bpm == true) // check if we detected an


abnormal sensor value

flag_abnormal_bpm = false;

assemble_sms(sms_buff);

salengGSM.sendSMS(PHONE,sms_buff); // intiiate the


SMS.

Serial.print(F("Sending to:"));

Serial.println(PHONE);

Serial.println(sms_buff);
Appendices 54

// if(DEBUG)Serial.println(F("ABNORMAL PULSERATE"));

void assemble_sms(char * pmsg)

char temp[32];

byte p;

p=0;

memset(pmsg,' ',160);

pmsg[159] = 0;

sprintf(pmsg,"BPM=%03d",BPM); p = 7;

memcpy(&pmsg[p],"\nLOCATION\nLATITUDE:",19); p = p +
19

memset(temp,0,32);

// dtostrf(latitude,3,6,temp);

// strncpy(&pmsg[p], temp,9);

// p = p + 9;

dtostrf(latitude,3,6,temp);

strncpy(&pmsg[p], temp,8);

p = p + 8;
Appendices 55

pmsg[p] = '\n';

p++;

memcpy(&pmsg[p],"LONGITUDE:",10); p = p + 10;

memset(temp,0,32);

dtostrf(longitude,3,6,temp);

strncpy(&pmsg[p], temp,9);

p = p + 9;

pmsg[p] = '\n';

p++;

strncpy(&pmsg[p],"\r\n",2); p = p + 2;

if(latitude!=0)

// http://maps.google.com/?q=lll.llllll,ooo.oooooo

// p=0;

strncpy(&pmsg[p], "http://maps.google.com/?q=",26);

p = p+ 26;

memset(temp,0,32);

dtostrf(latitude,3,6,temp);

// strncpy(&pmsg[p], temp,9);
Appendices 56

// p = p + 9;

strncpy(&pmsg[p], temp,8);

p = p + 8;

pmsg[p] = ',';

p++;

memset(temp,0,32);

dtostrf(longitude,3,6,temp);

strncpy(&pmsg[p], temp,9);

p = p + 9;

else

sprintf(pmsg,"BPM=
%03d\nLOCATION\nLATITUDE:0\nLONGITUDE:0\n\r\nNo GPS
Signal",BPM);

memcpy(&pmsg[p], "\r\n",2);

p = p+2;

pmsg[p] = 0;
Appendices 57

void lcd_refresh()

static unsigned long t;

if(millis() - t < 500) return;

t=millis();

char g,s;

if (tinygps.location.isValid()) g='G';

else g=' ';

if(digitalRead(SMS_DISABLE) == LOW) s=' ';

else s = 'S';

if(salengGSM.isFreeToSend() == false)

lcd.setCursor(0,0); lcd.print(F("SENDING SMS... "));

lcd.setCursor(0,1);

sprintf(buf,"%03d bpm %c %c",BPM,g,s);

lcd.print(buf);

else
Appendices 58

lcd.setCursor(0,0); lcd.print(F(" HEART RATE "));

lcd.setCursor(0,1);

sprintf(buf,"%03d bpm %c %c",BPM,g,s);

lcd.print(buf);

void setup() {

pinMode(LED_BUILTIN,OUTPUT);

pinMode(SMS_DISABLE,INPUT_PULLUP);

salengGSM.begin(9600);

// this is the default baud rate

Serial.begin(9600);

Serial2.begin(9600);

Serial.println(F("AT"));

lcd.init();

lcd.backlight();

lcd.setCursor(0,0); lcd.print(F(" PLEASE "));

lcd.setCursor(0,1); lcd.print(F(" WAIT "));

//Pulse Sensor

interruptSetup();

Serial.print(F("Preparing Saleng GSM Shield.Pls wait for


10 seconds..."));
Appendices 59

unsigned long t;

// delay(10000); // allow 10 seconds for modem to boot up


and register

salengGSM.initSalengGSM();

Serial.println(F("Start"));

//salengGSM.sendSMS("09164428565","Hi, this is a test SMS


from the Layad Circuits' Saleng GSM Shield. Have a nice
day!");

void loop() {

salengGSM.smsMachine();

pulse_sensor()a;

sms_manager();

sensor_check();

gps_routine();

lcd_refresh();

}
Appendices 60

C. Documentation

Figure 3: Connecting components to Arduino Mega

Figure 4: Assembly of prototype to be placed in the chassis


Appendices 61

Figure 5: Attaching power source to the chassis

Figure 6: Components are being secured and taped on the chassis


Appendices 62

Figure 7: Fixing wires to avoid soldering of components

Figure 8: Activating and testing the prototype


Appendices 63

Figure 9: Final Prototype

You might also like