Go Down

Topic: timed duration for output without affecting the loop (Read 378 times) previous topic - next topic

fame3096

Hi guys,
I am doing a project in which I am collecting data from a sensor. I need to set a threshold and run a vibrator if the data is below it. The thing is that the vibrator should turn on for 2 seconds and turn off for 5 mins even if the data is below threshold. I cannot use delay because I want the data to be displayed in serial monitor at all times.

omersiar

Do you have a working code?

I think vibration for 2 seconds for every 5 min is like a heartbeat and can be accomplished via millis().

Below example can be used for that purpose tweak it for your needs. Blink rate should be 300000 for 5 minutes intervals.

Please take time and learn Blink Without Delay concept

Several Things at Same Time

Code: [Select]

// Define these at the top of your sketch.
#define LEDBLINK_PIN    13    // I/O pin connected to the LED.
#define LEDBLINK_MS     1000  // Blink rate (in milliseconds).

void setup()
{
  // For ledBlink(), set LEDBLINK_PIN to output.
  pinMode(LEDBLINK_PIN, OUTPUT);
}

void loop()
{
  // Blink the LED to let the user know we are still alive.
  ledBlink();

  // Do something.
}

//
// LED Heartbeat routine by Allen C. Huffman (www.appleause.com)
//
void ledBlink()
{
  static unsigned int  ledStatus = LOW;  // Last set LED mode.
  static unsigned long ledBlinkTime = 0; // LED blink time.

  // LED blinking heartbeat. Yes, we are alive.
  // For explanation, see:
  // http://playground.arduino.cc/Code/TimingRollover
  if ( (long)(millis()-ledBlinkTime) >= 0 )
  {
    // Toggle LED.
    ledStatus = (ledStatus==HIGH ? LOW : HIGH);

    // Set LED pin status.
    digitalWrite(LEDBLINK_PIN, ledStatus);

    // Reset "next time to toggle" time.
    ledBlinkTime = millis()+LEDBLINK_MS;
  }
} // End of ledBlink()

Pure SPI Library for 1602 LCD using Shift Register
https://github.com/omersiar/ShiftedLCD

RFID Access Control Project
https://github.com/omersiar/RFID522-Door-Unlock

Robin2

Have a look at how millis() is used to manage timing without blocking in several things at a time

...R
@omersiar, got there just before me :)
Two or three hours spent thinking and reading documentation solves most programming problems.

fame3096

I have checked out the millis() tutorial. I dont think you got me.
My code's serial output is heartrate values which come out every second. I need to code so that a vibrator goes off for 2 seconds if the heart rate is below 90 and turn it off for 5 minutes even if the incoming heart rates are below 90.
My code to display heart rate is:
<code>
#include <SoftwareSerial.h>
SoftwareSerial nss(8,5); // Put your TX and RX pins here, in the correct order, nss represent heartRate

byte vals[3];
const int numReadings = 10;
int heartRate, oxyLevel;
int readings[numReadings];
int readIndex = 0;              // the index of the current reading
float total = 0;                  // the running total
float average = 0;                // the average



void setup()
{
 
 nss.begin(9600); // Or whatever is appropriate
  Serial.begin(9600);
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }

}

void loop()
{
  if(nss.available() >= 3)
  {     
    vals[0] = nss.read(); //represent byte 1
    vals[1] = nss.read(); //represent byte 2
    vals[2] = nss.read(); //represent byte 3
   
    heartRate = 0; // Sets all 8 bits to 0
    oxyLevel = 0; // Sets all 8 bits to 0

    bitWrite(heartRate, 0, bitRead(vals[1], 0)); // Set bit 0
    bitWrite(heartRate, 1, bitRead(vals[1], 1)); // Set bit 1
    bitWrite(heartRate, 2, bitRead(vals[1], 2)); // Set bit 2
    bitWrite(heartRate, 3, bitRead(vals[1], 3)); // Set bit 3
    bitWrite(heartRate, 4, bitRead(vals[1], 4)); // Set bit 4
    bitWrite(heartRate, 5, bitRead(vals[1], 5)); // Set bit 5
    bitWrite(heartRate, 6, bitRead(vals[1], 6)); // Set bit 6
    bitWrite(heartRate, 7, bitRead(vals[0], 0)); // Set bit 7
    bitWrite(heartRate, 8, bitRead(vals[0], 1)); // Set bit 8
     
    oxyLevel = vals[2];

  }

  // subtract the last reading:
  total = total - readings[readIndex];
  // read from the sensor:
readings[readIndex] = heartRate;
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  // send it to the computer as ASCII digits
 
  Serial.print("Heart rate: ");
Serial.println(heartRate);
 
  Serial.print("avg: ");
  Serial.println(average);
  delay(1);        // delay in between reads for stability
}


</code>

sterretje

If you now edit your post and use square brackets instead of < and > for the code tags you will have it right ;)
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

Robin2

I have checked out the millis() tutorial. I dont think you got me.
My code's serial output is heartrate values which come out every second. I need to code so that a vibrator goes off for 2 seconds if the heart rate is below 90 and turn it off for 5 minutes even if the incoming heart rates are below 90.
I think it is you who have not understood the relevance of using millis() as in the example. Try again.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

fame3096

hey guys, Sorry for asking too much. I did take time to study millis(). I wrote up a code and the led turns on for 2 seconds when the average HR is < 95 and then turns off for 5 seconds but then the data is not displayed in the serial monitor during this 2 seconds on time and 5 seconds off time.
Code: [Select]

#include <SoftwareSerial.h>
SoftwareSerial nss(8,5); // Put your TX and RX pins here, in the correct order, nss represent heartRate

byte vals[3];
const int numReadings = 10;
int heartRate, oxyLevel;
int readings[numReadings];
int readIndex = 0;              // the index of the current reading
float total = 0;                  // the running total
float average = 0;                // the average

unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long ontime = 2000; // interval at which to blink (milliseconds)
const long offtime = 5000;


void setup()
{
 
 nss.begin(9600); // Or whatever is appropriate
  Serial.begin(9600);
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
pinMode(13,OUTPUT);
}

void loop()
{
  if(nss.available() >= 3)
  {     
    vals[0] = nss.read(); //represent byte 1
    vals[1] = nss.read(); //represent byte 2
    vals[2] = nss.read(); //represent byte 3
   
    heartRate = 0; // Sets all 8 bits to 0
    oxyLevel = 0; // Sets all 8 bits to 0

    bitWrite(heartRate, 0, bitRead(vals[1], 0)); // Set bit 0
    bitWrite(heartRate, 1, bitRead(vals[1], 1)); // Set bit 1
    bitWrite(heartRate, 2, bitRead(vals[1], 2)); // Set bit 2
    bitWrite(heartRate, 3, bitRead(vals[1], 3)); // Set bit 3
    bitWrite(heartRate, 4, bitRead(vals[1], 4)); // Set bit 4
    bitWrite(heartRate, 5, bitRead(vals[1], 5)); // Set bit 5
    bitWrite(heartRate, 6, bitRead(vals[1], 6)); // Set bit 6
    bitWrite(heartRate, 7, bitRead(vals[0], 0)); // Set bit 7
    bitWrite(heartRate, 8, bitRead(vals[0], 1)); // Set bit 8
     
    oxyLevel = vals[2];

  }

  // subtract the last reading:
  total = total - readings[readIndex];
  // read from the sensor:
readings[readIndex] = heartRate;
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  // send it to the computer as ASCII digits
 
  Serial.print("Heart rate: ");
Serial.println(heartRate);
 
  Serial.print("avg: ");
  Serial.println(average);
  delay(1);        // delay in between reads for stability

  unsigned long onTime = millis();
  if(average>95){
while(millis() - onTime < 2000){
  digitalWrite(13,HIGH);
}
  while(millis() - onTime < 5000){
   digitalWrite(13,LOW);
 
  }
  }
else{
  digitalWrite(13,LOW);

}
}




Now, this works just like a delay. If I copy paste the first 2/3rd of the code(data output) right after the 2 second on time and 5 second off time, It works like I need it to.
Code: [Select]

if(nss.available() >= 3)
  {     
    vals[0] = nss.read(); //represent byte 1
    vals[1] = nss.read(); //represent byte 2
    vals[2] = nss.read(); //represent byte 3
   
    heartRate = 0; // Sets all 8 bits to 0
    oxyLevel = 0; // Sets all 8 bits to 0

    bitWrite(heartRate, 0, bitRead(vals[1], 0)); // Set bit 0
    bitWrite(heartRate, 1, bitRead(vals[1], 1)); // Set bit 1
    bitWrite(heartRate, 2, bitRead(vals[1], 2)); // Set bit 2
    bitWrite(heartRate, 3, bitRead(vals[1], 3)); // Set bit 3
    bitWrite(heartRate, 4, bitRead(vals[1], 4)); // Set bit 4
    bitWrite(heartRate, 5, bitRead(vals[1], 5)); // Set bit 5
    bitWrite(heartRate, 6, bitRead(vals[1], 6)); // Set bit 6
    bitWrite(heartRate, 7, bitRead(vals[0], 0)); // Set bit 7
    bitWrite(heartRate, 8, bitRead(vals[0], 1)); // Set bit 8
     
    oxyLevel = vals[2];

  }

  // subtract the last reading:
  total = total - readings[readIndex];
  // read from the sensor:
readings[readIndex] = heartRate;
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }
  // calculate the average:
  average = total / numReadings;
  // send it to the computer as ASCII digits
 
  Serial.print("Heart rate: ");
Serial.println(heartRate);
 
  Serial.print("avg: ");
  Serial.println(average);
  delay(1);        // delay in between reads for stability


 But the set of code appears 3 times in the loop and it looks like an inefficient way to do it. How to reduce that? or Am I using millis() wrong?

Robin2

Now, this works just like a delay.
That is because you are using WHILE. If you look at my demo you will see that it uses IF.

Getting your head around the use of millis() can take a little effort, but it is a very fundamental concept for Arduino programming.

Think of the way that you use the clock on the wall in your kitchen. When something starts you save the value of millis() (make a note of the time on the clock) and at regular intervals you compare the latest value of millis() (the current time on your clock) with the value you saved. If the right amount of time has passed you know to take the chicken from the oven.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

fame3096

@Robin2

Thanks for the reply. I still haven't figured it out.

What I am trying to do is that "if" the heartrate goes up, I want a PWM LED to be on for a 5 seconds and then off for 10 seconds even if the heart rate is above the threshold. All this needs to happen while the data is streaming on the serial monitor. To be honest, I am a novice at arduino. My code doesn't seem to do this. Can you please help me out?

<code>
unsigned long currentMillis = millis();
unsigned long previousMillis = 0;

void loop()
{
dataread();//function to display serial data
currentMillis = millis();
if(average>60){
  if(currentMillis - previousMillis >= 5000) {
    analogWrite(11,200);
 // setup clock for next tick
    previousMillis = currentMillis;
  }
  dataread();
 if(currentMillis - previousMillis >=10000){
    analogWrite(11,0);
    previousMillis = currentMillis;
  }
   dataread();
 
  }
else{
  analogWrite(11,0);

}
}
</code>
thank you!

Go Up