Delaying without stalling loop

Hey everyone,

I have a void loop that is constantly checking the input of some light sensors, When a sensor hits a certain value I want to set an output pin to HIGH, hold it there for half a second, then set it back to LOW.

The problem I'm having is the part where I wait half a second before returning the pin to LOW. If I use delay(500); it will stop everything until the delay is over.

How do I delay setting the output pin to LOW without halting everything else?

thanks for the help

-joe

Try looking at one of the example sketches that comes with the IDE - I think it’s called “BlinkWithoutDelay” or something like that. The basic idea is your code makes a note of the current time (using millis), carries on looping round doing whatever it wants but each time through the loop you check what the current time is now. If a sufficient interval has passed compared with your first time then you do something. In pseudo code:

interval = 500; // 500 milliseconds = 0.5 seconds
threshold = 300;
boolean triggered = false;

void loop {
  // Do your thing here
  lightVal = readSensor();

  if (lightVal > threshold) {
    triggered = true;
    startTime = millis();
    setPinToHigh();
  }

  if (triggered) {
    // Check how much time has passed
    if ((millis() - startTime) > interval) {
      // Time to turn off
      triggered = false;
      setPinToLow();
    }
  }
}

The way I’ve written it above it will keep on triggering and resetting the 0.5s timer if the light level stays above the threshold value. If you want it to trigger once, then not trigger again until the interval has passed then you’ll need to change it like this:

...
  if ((lightVal > threshold) && !triggered) {
...

This is off the top of my head, but I think the algorithm is what you want.

Andrew

Thanks, that did it! I played around with it and was able to get an led to light up for a quarter of a second and go out.

I have a new challenge that is really difficult for me. I would think this is an easy one but Im not a good programmer, so its difficult for me.

I have my light sensor, when I shine a light on it my led turns on, holds, turns off nicely. I need the part where it turns on and off itself to be delayed, but at the same time I don’t want to stop receiving input from the sensors.

So if I wave a flashlight at the sensor 4 times, you will see the leds flashing 4 times, each a second after the flashlight.

I’ve been trying to figure out how to buffer the input, but I don’t know how to approach it. I’m assuming I have to load several variables up with the sensor value and put individual delays on them (like the delay shown in the previous post) I get confused when I think of how to regulate the rate at which each variable is given its value…

thanks again for the help

-joe

You'll need to be able to store multiple start times and also have a time interval after the trigger time before you set your pin high, followed by the interval before you set it low again. Arrays will definitely be useful.

Try looking at the code in this post: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1225593807/6#6 . Once you understand how it works you should be able to combine the concepts with the code you've already got.

Andrew

Hello again

I’m having a terrible time getting my head around this. I understand how the arrays work, and I understand how I can use them if I’m going to use multiple sensor inputs (which I will eventually)
Right now I have the code working fine if I wave a light over a sensor, it will blink the led with the delay I need without interrupting the loop that is constantly checking the sensor data for a change. I have a function right now that is making the data from the sensor absolute, either 1 or 0.

The problem I’m having is queuing up the sensor input. I’ve spent all day thinking about it, and all night trying to get it to work, but I couldn’t come up with the code to do the job.

I don’t know how to read the sensor input, store that information, then repeat the process, while at the same time having a light blink for each input half a second later.

Is there an official term for this process? I’ve been searching the internet for examples, but I haven’t come up with much, but on the brighter side I learned a whole lot about arrays, and multidimensional arrays :slight_smile:

Here is my code that currently works as a delayed blink without interrupting the loop.

int outputpin = 13;
int buffer; //variable to store input data
boolean ontrigger = false;
boolean offtrigger = false;
long onstartTime;
long offstartTime;
long interval = 500;


void setup() 
{ 
  Serial.begin(9600);           // sets the serial port to 9600 
  pinMode(outputpin , OUTPUT);
} 
 
void loop() 
{ 

//////Input from light sensors  
  
  
    buffer = sensorInput(1); //get value from sensorInput function           
    Serial.print(buffer, DEC);
    Serial.println();
    
       if ((buffer == 1) && !ontrigger)
       {  
          ontrigger = true;
          onstartTime = millis();     
       }

///Output to leds  
  
       if (ontrigger) 
       {  
          if ((millis() - onstartTime) > interval)     // Check how much time has passed
          {
            ontrigger = false;
            offtrigger = true;
            offstartTime = millis();
            digitalWrite(outputpin, HIGH);
          }
       }  

///turn off leds 
  if (offtrigger) 
       {  
          if ((millis() - offstartTime) > interval)     // Check how much time has passed
          {
            offtrigger = false;
            digitalWrite(outputpin, LOW);
          }
       }  
  
  
  
  
 

  

}


//function for reading light sensor data and making it 1 or 0
int sensorInput(int sensorPin)
{  
  int input[51];  //Raw input value of light sensor
  int average;    //Average of sensor data
  int digital;    //The value of sensor input, 1 or 0
  int i;
  int sum;
  int inputx = 50;     //Amount of samples to take from the input pin

  i=0;
  sum=0;


  for(i=0; i<inputx; i++)
  {
    input[i] = analogRead(sensorPin); //load input into array
    sum = (input[i] + sum); //add up all the input
  }

  average = (sum/inputx); //average the senor data


//Make the sensor data absolute
  if (average > 40)
    {
      digital = 1;
    }
  if (average < 40)
    {
      digital = 0;
    } 
  
   return digital;
}

Once again I am very grateful for the help received.

Here is one way to do it, using a function called blink that should be called over and over. It knows about three states:

  • blinking disabled (the led does not blink)
  • blinking with the led not illuminated
  • blinking with the led lit

If the state is set to anything other than disabled, the led will blink

// blink example using function to service state changes
// LED on pin 13 blinks when sensor input on pin 1 equals 1
int outputpin = 13;
int buffer; //variable to store input data

int  blinkState;     //the following constants define the blink states:
const int BLINK_DISABLED = 0;
const int BLINK_LOW       = 1;
const int BLINK_HIGH     = 2;

long blinkStartTime; // the time the current blinking state started
long interval = 500;

void blink()
{
  if(blinkState > BLINK_DISABLED)
  {  // here if blinking
    if ((millis() - blinkStartTime) > interval)     // Check if blink interval has elapsed
    {
      blinkStartTime = millis(); // reset the time
      if( blinkState == BLINK_LOW) // toggle the blink state
        blinkState = BLINK_HIGH;
      else 
        blinkState = BLINK_LOW;
    }
  }  
  if(  blinkState == BLINK_HIGH)
    digitalWrite(outputpin, HIGH);   // only illuminate LED if the blink state is BLINK_HIGH
  else
    digitalWrite(outputpin, LOW);  
}

void setup()
{
  Serial.begin(9600);           // sets the serial port to 9600
  pinMode(outputpin , OUTPUT); 
}

void loop()
{
  //////Input from light sensors

  buffer = sensorInput(1); //get value from sensorInput function
  Serial.print(buffer, DEC);
  Serial.println();

  if (buffer == 1)   //start blinking (if not already blinking) if buffer equals 1
  {
    if( blinkState == BLINK_DISABLED)
        blinkState = BLINK_LOW; //start blinking   
  }
  else
     blinkState = BLINK_DISABLED; //stop blinking  
     
  blink(); // calls blink over and over
}


//function for reading light sensor
// returns true if sensor reading greater than 40;0
int sensorInput(int sensorPin)
{
  int input[51];  //Raw input value of light sensor
  int average;    //Average of sensor data
  int digital;    //The value of sensor input, 1 or 0
  int i;
  int sum;
  int inputx = 50;     //Amount of samples to take from the input pin

  i=0;
  sum=0;


  for(i=0; i<inputx; i++)
  {
    input[i] = analogRead(sensorPin); //load input into array
    sum = (input[i] + sum); //add up all the input
  }

  average = (sum/inputx); //average the senor data


  //Make the sensor data absolute
  if (average > 40)
  {
    digital = 1;
  }
  if (average < 40)
  {
    digital = 0;
  }

  return digital;
}

I actually made a library the will provide some of this functionality :slight_smile:

/*
||
|| @file DelayedSignal.pde
|| @version 1.0
|| @author Alexander Brevig
|| @contact alexanderbrevig@gmail.com
||
|| @description
|| | Display a way to delay a led signal on serial recieve.
|| #
||
|| @license
|| | Copyright (c) 2009 Alexander Brevig. All rights reserved.
|| | This code is subject to AlphaLicence.txt
|| | alphabeta.alexanderbrevig.com/AlphaLicense.txt
|| #
||
*/

#include <Scheduler.h> // Scheduler.zip

Scheduler scheduler = Scheduler(); //create a scheduler

const byte ledPin = 13; //LED on pin 13

void setup(){
Serial.begin(9600); //Iitialize the UART
pinMode(ledPin,OUTPUT); //set pin 13 to OUTPUT
}

void loop(){
scheduler.update(); //update the scheduler, maybe it is time to execute a function?

if (Serial.available()){ //if we have recieved anything on the Serial
scheduler.schedule(setHigh,500); //schedule a setHigh call in 500 milliseconds
Serial.flush(); //flush Serial so we do not schedule multiple setHigh calls
}
}

void setHigh(){
digitalWrite(ledPin,HIGH); //set ledPin HIGH
scheduler.schedule(setLow,500); //schedule setLow to execute in 500 milliseconds
}

void setLow(){
digitalWrite(ledPin,LOW); //set ledPin LOW
}

It makes scheduling functioncalls simpler. Or at least, it should.

By default it can store up to 10 function calls, but this can be modified in the .h

Hi AlphaBeta, Its not clear from that example how you 'unschedule' something. It may help the OP if you could show how to start and stop the blinking based on the return from his sensorInput function.

I first thought not calling update would do it but that would leave the LED in an indeterminate state. It would also stop any other scheduled function.

Hmm. Why schedule something, unly to ‘unschedule’ it?

To be honest, the library does not provide a way to unshedule a scheduled call.

[edit]
Code related to OP:
[this should do what you want, if you want a delayed blink every time the sensorInput is true]

#include <Scheduler.h> // Scheduler.zip

Scheduler scheduler = Scheduler();      //create a scheduler

const byte ledPin = 13;               //LED on pin 13

void setup(){
 pinMode(ledPin,OUTPUT);             //set pin 13 to OUTPUT
}

void loop(){
 scheduler.update();                 //update the scheduler, maybe it is time to execute a function?
 
 if (sensorInput(1)){            //if we have recieved anything on the Serial
   scheduler.schedule(setHigh,500);  //schedule a setHigh call in 500 milliseconds
 }
}

void setHigh(){
 digitalWrite(ledPin,HIGH);          //set ledPin HIGH
 scheduler.schedule(setLow,500);     //schedule setLow to execute in 500 milliseconds
}

void setLow(){
 digitalWrite(ledPin,LOW);           //set ledPin LOW
}

//function for reading light sensor
// returns true if sensor reading greater than 40;0
bool sensorInput(int sensorPin)
{
      int input[51];  //Raw input value of light sensor
      int average;    //Average of sensor data
      int digital;    //The value of sensor input, 1 or 0
      int i;
      int sum;
      int inputx = 50;     //Amount of samples to take from the input pin

      i=0;
      sum=0;


      for(i=0; i<inputx; i++)
      {
            input[i] = analogRead(sensorPin); //load input into array
            sum = (input[i] + sum); //add up all the input
      }

      average = (sum/inputx); //average the senor data


      //Make the sensor data absolute
      if (average > 40)
      {
            digital = 1;
      }
      if (average < 40)
      {
            digital = 0;
      }

      return digital;
}

[/edit]

Hmm. Why schedule something, unly to 'unschedule' it?

to stop it blinking when the condition that started it blinking is no longer true.

But perhaps the OP doesn't need that functionality

to stop it blinking when the condition that started it blinking is no longer true.

I have a void loop that is constantly checking the input of some light sensors, When a sensor hits a certain value I want to set an output pin to HIGH, hold it there for half a second, then set it back to LOW.

But perhaps the OP doesn’t need that functionality

I do not think so. :slight_smile:

But… It might be handy to implement this functionality.

I have a void loop that is constantly checking the input of some light sensors, When a sensor hits a certain value I want to set an output pin to HIGH, hold it there for half a second, then set it back to LOW.

actually implies that it gets unscheduled after a single cycle. Lets see what the OP says he wants.

anyway, I do think that stopping a scheduled object would be a useful addition to your library.

I do not want to seem cantankerous, but you’ll have to agree that even though the state becomes false, it will not change the fact that it at some point was true? And, while true scheduling, a blink as supposed to.

But, yes. I will add the ability to unschedule. And yes, I guess we’ll have to wait for the OP :slight_smile:

Sorry if this post was unclear, the initial post was for delaying the led turning off. I was able to get that working, now I'm trying to have the led react to the light sensor with half a second of lag. So if the light sensor receives input for 2 seconds, it will wait half a second then turn the led on for two seconds, then turn off.

But, I need this to happen so that no input from the sensor is ever lost. So if I blink a flashlight at my light sensor 10 times, the led will wait half a second, then start flashing 10 times. The input from the sensor needs to be buffered, queued up and outputted even after the led has started blinking.

The part that I don't know if how to start a queue for the input, and have it wait in line to be outputted (at the same rate it was inputted)

Hope that clears things up. thanks :) -joe

I am able to do call/repeat with this sketch:

#include <Scheduler.h> // Scheduler.zip

Scheduler scheduler = Scheduler();  //create a scheduler

const byte ledPin = 13;       //LED on pin 13
bool stateChange = true;

void setup(){
 pinMode(ledPin,OUTPUT);     //set pin 13 to OUTPUT
}

void loop(){
  scheduler.update();         //update the scheduler, maybe it is time to execute a function?

  if (sensorInput(1)){    //if we have recieved anything on the Serial
    if (stateChange){
      scheduler.schedule(setHigh,500);  //schedule a setHigh call in 500 milliseconds
      stateChange=false;
    }
  }else{
    scheduler.schedule(setLow,500);  //schedule a setHigh call in 500 milliseconds
    stateChange=true;
  }
}

void setHigh(){ digitalWrite(ledPin,HIGH); }

void setLow(){ digitalWrite(ledPin,LOW);}

//function for reading light sensor
// returns true if sensor reading greater than 40;0
bool sensorInput(int sensorPin)
{
  int input[51];  //Raw input value of light sensor
  int average;    //Average of sensor data
  int digital;    //The value of sensor input, 1 or 0
  int i;
  int sum;
  int inputx = 50;     //Amount of samples to take from the input pin

  i=0;
  sum=0;


  for(i=0; i<inputx; i++)
  {
  input[i] = analogRead(sensorPin); //load input into array
  sum = (input[i] + sum); //add up all the input
  }

  average = (sum/inputx); //average the senor data


  //Make the sensor data absolute
  if (average > 40)
  {
  digital = 1;
  }
  if (average < 40)
  {
  digital = 0;
  }

  return digital;
}

start a queue for the input, and have it wait in line to be outputted (at the same rate it was inputted)

Joe, when you say rate , do you mean the same number of times as the input was flashed, or do you mean that the flash duration will be the same as the input duration.

start a queue for the input, and have it wait in line to be outputted (at the same rate it was inputted)

Joe, when you say rate , do you mean the same number of times as the input was flashed, or do you mean that the flash duration will be the same as the input duration.

I was thinking both?

Here I am, interfering again :-/ Sorry mem.