Blinking without stoping the code.

by duffkindt on Sun Feb 27, 2011 7:55 pm

I have tried several ways to get this to happen but to no avail. I am a newbe and was pleased to get my basic sketch to work fine but adding the blink in several different ways didn't work. i have spent two weeks trying to find a solution. It must be right under my nose. I'm 62 yo and this is my first programming effort my brain must be atrophying. Code follows.

/*Sequence 7-10 lights from bottom to top of driveway
or top to bottom from PIR input at top or bottom.
If top sequences is initiated first the top most
and bottom most light will light first,
then top to bottom sequence will continue
until complete then remain on for one minute
then all will go off. The same if the bottom
sequence is initiated first only in reverse. */
/*Added whistle blink the led at the oppisite end of
the driveway to indicate if soomeone is coming up,
or down as the case may be*/
// Initialize pins as input and output

int topPir = 2; //digital input for top pir
int bottomPir = 3; //digital input for bottom pir

int outPin4 = 4; //output for bottom light or relay
int outPin5 = 5;
int outPin6 = 6;
int outPin7 = 7;
int outPin8 = 8;
int outPin9 = 9;
int outPin10 = 10;
int outPin11 = 11;
int outPin12 = 12; //output for top light or relay

void setup()
{
pinMode(topPir, INPUT); //declare topPir as input
pinMode(bottomPir, INPUT); //declare bottomPir as input
pinMode(outPin4, OUTPUT); // declare outPin4 as output
pinMode(outPin5, OUTPUT); // declare outPin5 as output
pinMode(outPin6, OUTPUT); // declare outPin6 as output
pinMode(outPin7, OUTPUT); // declare outPin7 as output
pinMode(outPin8, OUTPUT); // declare outPin8 as output
pinMode(outPin9, OUTPUT); // declare outPin9 as output
pinMode(outPin10, OUTPUT); // declare outPin10 as output
pinMode(outPin11, OUTPUT); // declare outPin11 as output
pinMode(outPin12, OUTPUT); // declare outPin12 as outputq
}

void loop ()
{
if (digitalRead(topPir) == HIGH)//checks topPir condition
{
digitalWrite(outPin4, HIGH); //turns output outPin4 on
digitalWrite(outPin12, HIGH); //I want to blink this one
delay(1000); //delays for one second
digitalWrite(outPin5, HIGH); //turn on output outPin5
delay(1000); //delay
digitalWrite(outPin6, HIGH); //same as above until end of
delay(1000); //loop
digitalWrite(outPin7, HIGH);
delay(1000);
digitalWrite(outPin8, HIGH);
delay(1000);
digitalWrite(outPin9, HIGH);
delay(1000);
digitalWrite(outPin10, HIGH);
delay(1000);
digitalWrite(outPin11, HIGH);
delay(1000);
digitalWrite(outPin12, HIGH);
delay(60000); //all outputs on for one minute
digitalWrite(outPin4, LOW); //turns all outPins off
digitalWrite(outPin5, LOW);
digitalWrite(outPin6, LOW);
digitalWrite(outPin7, LOW);
digitalWrite(outPin8, LOW);
digitalWrite(outPin9, LOW);
digitalWrite(outPin10, LOW);
digitalWrite(outPin11, LOW);
digitalWrite(outPin12, LOW);
}
if (digitalRead(bottomPir) == HIGH)//checks bottomPir condition
{
digitalWrite(outPin12, HIGH); //turns output outPin12 on
digitalWrite(outPin4, HIGH); // blink this while rest of code runs
delay(1000); //delays for one second
digitalWrite(outPin11, HIGH); //turn on output outPin12
delay(1000); //delay
digitalWrite(outPin10, HIGH); //same as above until end of
delay(1000); //loop
digitalWrite(outPin9, HIGH);
delay(1000);
digitalWrite(outPin8, HIGH);
delay(1000);
digitalWrite(outPin7, HIGH);
delay(1000);
digitalWrite(outPin6, HIGH);
delay(1000);
digitalWrite(outPin5, HIGH);
delay(1000);
digitalWrite(outPin4, HIGH);
delay(60000); //all outputs on for one minute
digitalWrite(outPin4, LOW); //turns all outPins off
digitalWrite(outPin5, LOW);
digitalWrite(outPin6, LOW);
digitalWrite(outPin7, LOW);
digitalWrite(outPin8, LOW);
digitalWrite(outPin9, LOW);
digitalWrite(outPin10, LOW);
digitalWrite(outPin11, LOW);
digitalWrite(outPin12, LOW);
}

}

Thanks Duff
duffkindt
 
Posts: 3
Joined: Thu Feb 10, 2011 1:37 pm

Re: Blinking without stoping the code.

by westfw on Sun Feb 27, 2011 8:36 pm

There is the "blink without delay" example sketch...

Many of the examples are missing a description of the thought process that leads to the code they contain. The basic strategy for blinking is essentially
Code: Select all | TOGGLE FULL SIZE
if (time_to_change_ledstate(which_led) {
   change_led_state(which_led);
   set_new_time_to_change(which_led);
}


BlinkWithoutDelay is an example of a way to implement this.
User avatar
westfw
 
Posts: 1373
Joined: Fri Apr 27, 2007 12:01 pm
Location: SF Bay area

Re: Blinking without stoping the code.

by duffkindt on Mon Feb 28, 2011 12:25 pm

I'm sorry. I don't understand.
Would I place this statement below my initial if statement or inside of it?

if (time_to_change_ledstate(which_led) {
change_led_state(which_led);
set_new_time_to_change(which_led);
}


Does "time_to_change_ledstate" refer to a number of milliseconds or a point at which I want the blinking to start? i.e. topPir==HIGH?
I would think (which_led) in my case would be outPin12.
Is change_led_state some sort of command that I need to declare as a variable and give an initial value?
Lastly (I hope) set_new_time_to_change would be the rate of change i.e. 300milliseconds?

I really feel dumb but I am trying.
Thanks, Duff
duffkindt
 
Posts: 3
Joined: Thu Feb 10, 2011 1:37 pm

Re: Blinking without stoping the code.

by adafruit_support_bill on Mon Feb 28, 2011 12:31 pm

The "BlinkWithoutDelay" example sketch in the IDE is a good place to start. This uses a system timer (millis) to figure out when it is time to change the state of the LED. Once you understand how it works for one LED, you should be able scale it up to sequence multiple LEDs.

Code: Select all | TOGGLE FULL SIZE
/* Blink without Delay
 
 Turns on and off a light emitting diode(LED) connected to a digital 
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.
 
 The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.
 
 
 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen
 
 This example code is in the public domain.

 
 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);     
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}
User avatar
adafruit_support_bill
 
Posts: 28161
Joined: Sat Feb 07, 2009 9:11 am

Re: Blinking without stoping the code.

by floresta on Mon Feb 28, 2011 1:22 pm

I'm sorry. I don't understand.
Would I place this statement below my initial if statement or inside of it?

if (time_to_change_ledstate(which_led) {
change_led_state(which_led);
set_new_time_to_change(which_led);
}

Don't feel bad, it's what is called pseudo code and it is supposed to make things easier to understand. You can't just paste it into your program but you can use it as a model to construct your own code.

Don
floresta
 
Posts: 221
Joined: Thu Jul 31, 2008 9:27 am
Location: Western New York, USA

Re: Blinking without stoping the code.

by devans on Mon Feb 28, 2011 1:51 pm

Hi Duffkindt,

I like the sound of your project. Are you controlling relays linked to proper drive way lights?

With all those delays in there your not going to be able to get anything blink so I'm afraid to say you'll need to modify your code a fair bit. For starters I will describe the changes that you'll need to do.

First, Rather than declaring all your pins for your lights as separate variables declare it as a single array variable. (the topPir and bottomPir are fine as is). Having an array will make it a lot easier to set the state of the pins and reduces the size of your code. To declare an array you simply state the type, the variable name followed by square brackets. you can then set the contents of your array in braced brackets. in you case it would be:
Code: Select all | TOGGLE FULL SIZE
int lightPins[] = {4,5,6,7,8,9,10,11,12};


with your pins for your lights in an array you can now simplify the code in your setup (keeping the topPir and bottomPir as is)
Code: Select all | TOGGLE FULL SIZE
for (i = 0; i < 9; i = i + 1) {
   pinMode(lightPins[i], OUTPUT)
}


the code above will loop 9 times incrementing i each time. the value of each element in the array will be used to set the pin as output.

now the main loop. What you want to do in here is ensure the loop is free to execute as frequently as possible (Don't use delay as this is in effect pausing the code)

Because it is our aim to have the loop run freely, you will need to firstly add a check if the Arduino is already running a light sequence. to do this add a new boolean variable to keep track of this and then setup your if block. You'll need both an if else (if it is running you need to check if the next light of the sequence is due else you will be checking the state of the PIR's)

in the header:
Code: Select all | TOGGLE FULL SIZE
boolean seqRunning = false;


in the loop:
Code: Select all | TOGGLE FULL SIZE
if (seqRunning == TRUE)
{
  // check if sequence need to be moved on
}
else
{
  // check state of PIR's
}


in the else part of your code you will need to add the checks you already have. if either are HIGH then you will enable the sequence and setup the variables used to control it.

Code: Select all | TOGGLE FULL SIZE
 
// check state of PIR's
if (digitalRead(topPir) == HIGH)//checks topPir condition
{
    seqRunning = TRUE;
    seqDirection = -1;
    seqPosition = 8;
    seqTime = millis();
    seqDelayNextAction = 0;
}
if (digitalRead(bottomPir) == HIGH)//checks bottomPir condition
{
    seqRunning = TRUE;
    seqDirection = +1;
    seqPosition = 0;
    seqTime = millis();
    seqDelayNextAction = 0;
}


a point to note in the above code. If both PIR's are HIGH when the arduino checks this code it will be the code in the bottomPir if statement that will set the variables as it is the last to execute. if you want it to be the other way around then re-arrange the if blocks.

There were also new variables defined:
seqDirection is an int that describes the direction the lights will be lite (positive or negative)
seqPosition is an int which is the pin position in our array of lights that is next to be actioned. it's worth pointing out that we are setting this to either one less or one more than the size of our array. as you will read later we first increment or decrement this position when progressing the sequence. it is also worth noting that because the array structure is 0 based (the first element is accessed as position 0) our seqPosition is set to either 0 (the beginning) or 8 (the end).
seqTime is an unsigned long that captures the current time in ms from when the arduino was last reset
seqDelayNextAction is an int that is used to determine when the next action should occur (in Ms). by setting it to the 0 we are wanting the light sequence to start straight away. if you want the start with a delay then you would add it here.

if for example a sequence is not running and the bottomPir is HIGH then the loop will fall in to the else block and then the setup for the bottomPir. the code will then get to the end of the loop and start again at the top. because the sequence is now running the first condition is true. The next step is to build out the code here to progress the sequence.

first thing to do is to check if an action needs to occur. we have 2 variables that were setup seqTime and seqDelayNextAction to help us determine this.The code to do this is as follows. The code to blink the light would be outside of the if block.

Code: Select all | TOGGLE FULL SIZE
  //Blink lights goes here...
  //---

  timeNow = millis();
  if (seqTime + seqDelayNextAction <= timeNow)
  {
     // record the current time as the sequence time for future checks.
     seqTime = timeNow;

      // Progress Sequence
      //..
  }





To progress the sequence we first add the seqDirection to seqPosition. This gives us the new position in our array of lights that will be triggered in the sequence.

After incrementing the seqPosition we need to check that we are still in bounds and haven't got to the end of the sequence.

If still in bound then set the pin to high and setup the delay

Code: Select all | TOGGLE FULL SIZE
  // Progress Sequence
  seqPosition += seqDirection;
  if (seqPosition>=0 & seqPosition<=8)
  {
       //set the next light in sequence
       digitalWrite(lightPins[seqPosition],HIGH);

       //set the delay until the next sequence cycle
       if (seqPosition = 0 | seqPosition = 8) //Last lights lite
       {
          seqDelayNextAction = 60000; //All the lights have been lite. wait a minute before turning off
       }
       else
       {
          seqDelayNextAction = 1000; //delay 1 second until next sequence cycle.
       }
  }
  else //cycle out of bounds. shutdown
  {
    for (i = 0; i < 9; i = i + 1) {
      digitalWrite(lightPins[i],LOW);
    }
  }




The last item of code to tackle is the blinking lights that you would insert where it says //Blink lights goes here...
the logic for this is simple. if the seqDirection is -1 then the topPir intiated the cycle so we want to flash pin 12 else we will flash pin 4. in our array pin 12 is array position 8 and pin 4 is array position 0 , so:

Code: Select all | TOGGLE FULL SIZE
   //Blink lights goes here...
   Blink=!Blink
   if (seqDirection=-1)
   {
      digitalWrite(lightPins[8],Blink);
   }
   else
   {
      digitalWrite(lightPins[0],Blink);
   }


Blink is a state variable that is declared as a boolean and set to FALSE.
What you will find in the above code is that the state will change quickly..
You will need to create a seperate time control for the blink effect in order to slow it down.

Please bare in mind that whilst this code should work it hasn't been tested as it was written adhoc straight in to forum editor so I'm sure it can be optimised further.. Let me know if you need any further pointers .
devans
 
Posts: 6
Joined: Thu Feb 17, 2011 9:30 am

Re: Blinking without stoping the code.

by s7eve on Sun Mar 11, 2012 11:28 am

Hi
I know this is an old thread but im trying to learn about arrays and delay without using delay for a project im working on

Im getting some error, I spend a good 3+ hours going over it and missing something simple. The second one I really dont understand

: In function 'void loop()':
: lvalue required as left operand of assignment
: 'i' was not declared in this scope
: expected `}' at end of input

If anyone as the time to just look over it for me and put me right i would really appreciate it.

Thanks in advance

Code: Select all | TOGGLE FULL SIZE
nt topPir = 2; //digital input for top pir
int bottomPir = 3; //digital input for bottom pir

int lightPins[] = { 4,5,6,7,8,9,10,11,12};

boolean seqRunning = false;
boolean Blink = false;
int seqDirection = 0;
int seqPosition = 0;
long seqTime = 0;
int  seqDelayNextAction = 0;
long timeNow = 0;


void setup()
{
  for (int i = 0; i <9; i = i + 1){
    pinMode(lightPins[i], OUTPUT);
  }
  pinMode(topPir, INPUT); //declare topPir as input
  pinMode(bottomPir, INPUT); //declare bottomPir as input

}


void loop ()
{
    // check state of PIR's
    if (digitalRead(topPir) == HIGH)//checks topPir condition
    {
//      seqRunning = TRUE;
      seqDirection = -1;
      seqPosition = 8;
      seqTime = millis();
      seqDelayNextAction = 0;
    }
  if (digitalRead(bottomPir) == HIGH)//checks bottomPir condition
  {
//    seqRunning = TRUE;
    seqDirection = +1;
    seqPosition = 0;
    seqTime = millis();
    seqDelayNextAction = 0;
  }

  //Blink lights goes here...
  Blink=!Blink;
   if (seqDirection=-1)
   {
      digitalWrite(lightPins[8],Blink);
   }
   else
   {
      digitalWrite(lightPins[0],Blink);
   }
 
  timeNow = millis();
  if (seqTime + seqDelayNextAction <= timeNow)
  {
    // record the current time as the sequence time for future checks.
    seqTime = timeNow;
 
    // Progress Sequence
  seqPosition += seqDirection;
 
  if (seqPosition>=0 & seqPosition<=8)
  {
       //set the next light in sequence
       digitalWrite(lightPins[seqPosition],HIGH);
 

       //set the delay until the next sequence cycle
       if (seqPosition = 0 | seqPosition = 8) //Last lights lite
       {
          seqDelayNextAction = 60000; //All the lights have been lite. wait a minute before turning off
       }
       else
       {
          seqDelayNextAction = 1000; //delay 1 second until next sequence cycle.
       }
  }
  else //cycle out of bounds. shutdown
  {
    for (i = 0; i < 9; i = i + 1) {
      digitalWrite(lightPins[i],LOW);
    }
  }

   
  }
s7eve
 
Posts: 2
Joined: Sun Mar 11, 2012 11:14 am

Re: Blinking without stoping the code.

by Dan Malec on Sun Mar 11, 2012 12:02 pm

Hi s7eve, the three compiler errors are caused by the following:

lvalue required as left operand of assignment

Caused by:
Code: Select all | TOGGLE FULL SIZE
if (seqPosition = 0 | seqPosition = 8)

The short answer is that you're using a bitwise OR (single pipe) instead of logical OR (double pipe) and assignment (single equal) instead of comparison (double equal). You probably want:
Code: Select all | TOGGLE FULL SIZE
if (seqPosition == 0 || seqPosition == 8)

The longer answer for the lvalue error is that it comes down to operator precedence http://en.wikipedia.org/wiki/C_operator_precedence#Operator_precedence, with the bitwise OR being evaluated prior to the assignments. So the compiler thinks you're asking to put the value 8 into the result of doing a bitwise OR on 0 and seqPosition.

'i' was not declared in this scope

Caused by:
Code: Select all | TOGGLE FULL SIZE
for (i = 0; i < 9; i = i + 1) {

You haven't declared a variable i in the global scope or the scope of the loop function, only in the setup function. A quick fix is to do the following:
Code: Select all | TOGGLE FULL SIZE
for (int i = 0; i < 9; i = i + 1) {


expected `}' at end of input

Looks like the cause is the following block being opened, but never closed.
Code: Select all | TOGGLE FULL SIZE
if (seqTime + seqDelayNextAction <= timeNow)
  {

You need one more closing brace } at the end of your sketch.
User avatar
Dan Malec
 
Posts: 13
Joined: Fri Nov 18, 2011 2:53 pm

Re: Blinking without stoping the code.

by s7eve on Sun Mar 11, 2012 12:47 pm

Dan

Thank you, think its called looking at this screen for to long, I just couldnt see the this missing bit and as for " if (seqPosition == 0 || seqPosition == 8)" I wouldnt have had a clue so a BIG thank you for your time

Cheers Steve
s7eve
 
Posts: 2
Joined: Sun Mar 11, 2012 11:14 am

Re: Blinking without stoping the code.

by Dan Malec on Sun Mar 11, 2012 12:55 pm

Steve

Glad to help; I've been there too - after looking at the same code for a long amount of time, things stop standing out :)

- Dan
User avatar
Dan Malec
 
Posts: 13
Joined: Fri Nov 18, 2011 2:53 pm

Re: Blinking without stoping the code.

by henry.best on Mon Mar 19, 2012 9:59 pm

Dan Malec wrote:Steve

Glad to help; I've been there too - after looking at the same code for a long amount of time, things stop standing out :)

- Dan


Agreed. I find that errors in my own code are much harder to find than errors in someone else's code :wink:
henry.best
 
Posts: 13
Joined: Sat Mar 03, 2012 8:37 pm

Re: Blinking without stoping the code.

by diyrmakr on Mon Nov 12, 2012 4:12 pm

Can this array be used to blink 6 leds at six different frequencies?
And if so will it work in micros instead of millis?
diyrmakr
 
Posts: 1
Joined: Mon Nov 12, 2012 4:10 pm