Now the LED flashes correctly - with the heartbeat, but there is nothing printed. I've also tried going back, but still nothing is printed. Here's the code now:
int LED = 13; //LED to blink when pulsing
int din = 2; // digital pin 2 to read 0V or 5V
int check; // checks current status of digital pin 2
int prevcheck;// previous check status
int pulsecount = 0; //number of pulses (highs) seen on the digital pin
int BPM = 0; //beats perminute = counter value * 10
unsigned long firstpulse =0; //time of first pulse
unsigned long timecount = 0;//cumulative time of total pulses
unsigned long latestpulse=0;
unsigned long interval = 6000; //setting 6 seconds as max read time
void setup()
{
pinMode(LED, OUTPUT);
pinMode(din,INPUT);
Serial.begin(9600);
}
void loop()
{
check = digitalRead(din);
//if (check != prevcheck ) // comparing current state to previous state
{
if (check == LOW)
{
digitalWrite(LED, LOW);
//prevcheck == LOW;
}
if (check == HIGH)
{
digitalWrite(LED, HIGH);
//prevcheck == HIGH; //storing current state of input pin
check == LOW; //reset the check
if (pulsecount == 0 ) // if this is the first count
{
firstpulse = millis(); // recording time of first pulse
pulsecount = pulsecount +1; //increment the counter
}
if (pulsecount >=1 )
{
pulsecount = pulsecount + 1; // increment pulse counter when detected
//timecount = millis() + firstpulse + timecount; //sumation of all pulse periods
latestpulse = millis(); // recording latest pulse time
}
}
}
if (latestpulse - firstpulse > interval) //checking if 6 seconds has elapsed
{
BPM = pulsecount;
Serial.println(BPM); //display the number of counts over 6 seconds
pulsecount = 0; // counter restarted
firstpulse = 0; // restart for time of new first-pulse read
latestpulse = 0; // restart for new time readings
//delay(100);
}
prevcheck = check;
}
void loop()
{
check = digitalRead(din);
if(check != prevcheck)
{
if (check == LOW)
{
digitalWrite(LED, LOW);
}
if (check == HIGH)
{
digitalWrite(LED, HIGH);
if (pulsecount == 0 ) // if this is the first count
{
firstpulse = millis(); // recording time of first pulse
pulsecount = pulsecount +1; //increment the counter
}
if (pulsecount >=1 )
{
pulsecount = pulsecount + 1; // increment pulse counter when detected
latestpulse = millis(); // recording latest pulse time
}
}
}
if (latestpulse - firstpulse > interval) //checking if 6 seconds has elapsed
{
BPM = pulsecount;
Serial.println(BPM); //display the number of counts over 6 seconds
pulsecount = 0; // counter restarted
firstpulse = 0; // restart for time of new first-pulse read
latestpulse = 0; // restart for new time readings
}
prevcheck = check;
}
@ Wildbill, sorry i mean't with the arduino. Is this the best way to determine pulse counts? Could arrays / for loops be used? I'm considering using case statements. The BPM is not always consistent so far.
The code looks fine to me - I don't see any advantage to using different constructs. The area I'd look at is how well your sensor is working - there seems to be quite wide variation in what it reads - or perhaps you got excited to see it finally working You might be able to mask that with a longer sensing period, but it looks like you need to compare what you're getting with a manual check of your pulse.
Hi, Yes i've been very excited but up to 300 BPM readings would be concerning XD
I was able to take some scope measurements - setup:
2V per box, 1 second per box, graph width of 10s - with this i was measuring a square wave (5V peak) and on average 7 pulses.
But the arduino kept displaying values from 100 upwards on an attached LCD - i increased the time interval to 10s. Here's the current code:
int LED = 13; //LED to blink when pulsing
int din = 2; // digital pin 2 to read 0V or 5V
int check; // checks current status of digital pin 2
int prevcheck;// previous check status
int pulsecount = 0; //number of pulses (highs) seen on the digital pin
int BPM = 0; //beats perminute = counter value * 10
unsigned long firstpulse =0; //time of first pulse
unsigned long timecount = 0;//cumulative time of total pulses
unsigned long latestpulse=0;
unsigned long interval = 10000; //setting 6 seconds as max read time
#include <LiquidCrystal.h> //include LCD
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);
void setup()
{
pinMode(LED, OUTPUT);
pinMode(din,INPUT);
lcd.begin(16, 2);// set up the LCD's number of columns and rows:
lcd.print("AV. HEART RATE:");// Print a message to the LCD.
Serial.begin(9600);
}
void loop()
{
check = digitalRead(din);
delay(100);
if(check != prevcheck)
{
if (check == LOW)
{
digitalWrite(LED, LOW);
}
if (check == HIGH)
{
digitalWrite(LED, HIGH);
if (pulsecount == 0 ) // if this is the first count
{
firstpulse = millis(); // recording time of first pulse
pulsecount = pulsecount +1; //increment the counter
}
if (pulsecount >=1 )
{
pulsecount = pulsecount + 1; // increment pulse counter when detected
latestpulse = millis(); // recording latest pulse time
}
}
}
//-----DISPLAY------///
if (latestpulse - firstpulse > interval) //checking if 6 seconds has elapsed
{
BPM = pulsecount*10;
Serial.println(BPM); //display the number of counts over 6 seconds
pulsecount = 0; // counter restarted
firstpulse = 0; // restart for time of new first-pulse read
latestpulse = 0; // restart for new time readings
lcd.setCursor(0, 1); //setting LCD cursor to 1st column, second row
lcd.print(BPM); // print the HR on the LCD as well
lcd.setCursor(5,1); // setting cursor in 5th column, row 2
lcd.print("BPM"); // printing text next to BPM
}
prevcheck = check;
}
The LCD code is dodgy. You may be leaving digits on the screen from prior readings. Either clear the LCD or print spaces after the number. Frankly, I'd concentrate on the results from the serial port for now until you're convinced that the sensing is working.
I think you're trying to take too many steps at the same time.
Start by writing your sketch so that it detects each pulse, using the logic demonstrated in the state change example.
Then add some code that detects when the elapsed time reaches six seconds. I suggest this timeout should be independent of the pulse detection/timing logic since you presumably don't want it to hang if no pulse is detected.
Once that is working, leave that logic alone and just focus on the code that is run each time a pulse is detected. It needs to determine whether this is the first pulse or not and either save the first pulse time, or save the last pulse time and increment the pulse count. You could use the non-zero first pulse time to determine whether this is the first pulse or not.
Once that's working, add some code that executes after the six second timeout has elapsed that does your arithmetic to calculate the bps.
At each step, make sure the code you're adding / changing does what you want before you move on to add the next bit of functionality. You're only looking at about a dozen lines of code and none of it is complicated, but you need to develop it methodically or you will just end up going round in circles.
Thank you!! The code seems to work now. Will test again in a few hours. - the LCD display matches the values on the serial monitor.
My next step is to use bluetooth to send and receive the signal - using the rn-42 modules. Will a new post be needed or continue with this?
Current code:
int LED = 13; //LED to blink when pulsing
int din = 2; // digital pin 2 to read 0V or 5V
int check; // checks current status of digital pin 2
int prevcheck;// previous check status
int pulsecount = 0; //number of pulses (highs) seen on the digital pin
int BPM = 0; //beats perminute = counter value * 10
unsigned long firstpulse =0; //time of first pulse
unsigned long timecount = 0;//cumulative time of total pulses
unsigned long latestpulse=0;
unsigned long interval = 10000; //setting 10 seconds as max read time
#include <LiquidCrystal.h> //include LCD
LiquidCrystal lcd(12, 11, 6, 5, 4, 3);
void setup()
{
pinMode(LED, OUTPUT);
pinMode(din,INPUT);
lcd.begin(16, 2);// set up the LCD's number of columns and rows:
lcd.print("AV. HEART RATE:");// Print a message to the LCD.
Serial.begin(9600);
}
void loop()
{
check = digitalRead(din);
delay(100);
if(check != prevcheck)
{
if (check == LOW)
{
digitalWrite(LED, LOW);
}
if (check == HIGH)
{
digitalWrite(LED, HIGH);
if (pulsecount == 0 ) // if this is the first count
{
firstpulse = millis(); // recording time of first pulse
pulsecount = pulsecount +1; //increment the counter
}
if (pulsecount >=1 )
{
pulsecount = pulsecount + 1; // increment pulse counter when detected
latestpulse = millis(); // recording latest pulse time
}
}
}
//-----DISPLAY------///
if (latestpulse - firstpulse > interval) //checking if 6 seconds has elapsed
{
BPM = pulsecount*6;
Serial.println(BPM); //display the number of counts over 6 seconds
pulsecount = 0; // counter restarted
firstpulse = 0; // restart for time of new first-pulse read
latestpulse = 0; // restart for new time readings
lcd.setCursor(0, 1); //setting LCD cursor to 1st column, second row
lcd.print(BPM); // print the HR on the LCD as well
lcd.setCursor(5,1); // setting cursor in 5th column, row 2
lcd.print("BPM"); // printing text next to BPM
}
prevcheck = check;
}
I suggest that rather than just printing BPM directly with 'lcd.print(BPM)', you format it to a string and then print the string. This gives you control over padding and alignment of the number.
char buff[5]; // make it long enough for your longest string, plus a space for the null terminator
snprintf(buff, sizeof(buff), "%3d", BPM);
lcd.print(buff);
Thanks for the reply PeterH - it seems to have fixed that issue.
I plugged in the Arduiono today - same setup as yesterday - and the LED is now out of sync with the heratbeat, giving sporadic pulses.
Here are some of my readings from the serial monitor:
102
156
162
162
138
132
108
72
78
90
162
162
Going back to yesterdays code has't changed anything. Is there a timing issue in the loop? I don't understand why it should suddenly stop working after a few hours
Yes. I don't know what sort of sensor you're using but I guess it will need to be very sensitive and could be upset by tiny electrical issues.
Do you still have that delay() call at the top of your loop() function? I can't see the point of that, and it would reduce the accuracy of your timing quite substantially since you only get to poll the input ten times a second. Depending on the nature of the sensor that might even cause you to miss beats.
The delay in the loop slows the execution a bit, without it the read is too large and the LED flickers at times. - But it does seem like i'm missing // adding pulses
With regards to the wiring - i moved each wire connecting the arduino and the LCD and it measures more realistic values. my current setup:
Sensor circuit:
IR LED next to OPT101 - transimpedance amp with photodiode. Signal passes through (LP filter + Active HP filter)*2. Fed into arduino
Display:
Standard Hitachi LCD
The sensor circuit is on a veroboard, the LCD on a breadboard. All of this is powered by the arduino's 5 Volts.