Yet again, removing delay from a Sketch.

I've been working on this Sketch on and off for three weeks and I officially give up.

I'm a newbie and I've looked at all the suggested examples and Sketches like "Blink Without Delay" without any success. I've also tried any Timer Library's that I can find and now I'm at the stage where I am likely to stupid to ever get this. It always either doesn't work at all or I keep getting "i was not declared in this scope" and so on.

Please someone help.
Thanks

const int k_numLEDs = 8;                      //Define the number of LED's
const int kPinLeds[k_numLEDs] = {22,23,24,25,26,27,28,29};  //define MEGA Digital Pins

void setup()
{
  for(int i = 0; i < k_numLEDs; i++)          //Set all Eight Pins to Outputs
  pinMode(kPinLeds[i], OUTPUT);
  delay(1500);
}

void loop()
{
//    digitalWrite(29, HIGH);                 //Blink LED on Pin 29 at one rate
//    delay(200);                             //Need to get Delay out of this entire Sketch
//    digitalWrite(29, LOW);
//    delay(200);

      for(int i = 0; i < k_numLEDs -1; i++)   //Turn 7 LED's on and off in sequence
      {digitalWrite(kPinLeds[i], HIGH);
      delay(500);
      digitalWrite(kPinLeds[i], LOW);}

      for(int i = k_numLEDs -2; i >= 0; i--)  //Reverse sequence
      {digitalWrite(kPinLeds[i], HIGH);
      delay(500);
      digitalWrite(kPinLeds[i], LOW);}
}

(deleted)

(deleted)

spycatcher2k:
I just tested it and it compiles fine for the mega2560

Ah yes, but you didn't remove the delay() statements for him as he would wish.

You must get rid of the for loops; let loop() do the counting. You can either use a global variable or a static local variable (the below code uses the latter).

void loop()
  // led counter
  static char counter = 0;

  // direction; up = 1, down = -1
  static char direction = 1;

The above declares a counter as well as an indication in which direction to count. Both are char type variables so we can use negative values (it's just the smaller version of int). The counter and direction are updated when all 8 leds are done (either forward or reverse direction).
The counter is updated after the current led is switched off; the direction is updated once one sequence (forward or reverse) is updated.

direction will be used to increment or decrement the counter. That way we can basically have an automatic forward / backward.

const int k_numLEDs = 8;                      //Define the number of LED's
const int kPinLeds[k_numLEDs] = {22, 23, 24, 25, 26, 27, 28, 29}; //define MEGA Digital Pins

void setup()
{
  for (int i = 0; i < k_numLEDs; i++)         //Set all Eight Pins to Outputs
  {
    pinMode(kPinLeds[i], OUTPUT);
    digitalWrite(kPinLeds[i], LOW);
  }
  delay(100);
}

// the current time
unsigned long currentTime;
// last time that a led changed state
unsigned long lastActionTime = 0;

void loop()
{
  // led counter; I use a char instead of a byte so we can use negative values
  static char counter = 0;
  // direction; up = 1, down = -1
  static char direction = 1;

  // get the current time
  currentTime = millis();

  // if it's time
  if (currentTime - lastActionTime >= 500)
  {
    // read the status of the current led
    byte ledState = digitalRead(kPinLeds[counter]);

    // toggle the status before we write it to the pin
    ledState = !ledState;

    // set current pin
    digitalWrite(kPinLeds[counter], ledState);

    // remember the last time that we did an action
    lastActionTime = currentTime;

    // if led state equals LOW, we have done the cycle (on/off) for one LED
    if (ledState == LOW)
    {
      // next time, do next led
      counter += direction;

      // if all leds done for forward sequence or for reverse sequence
      if (counter == k_numLEDs || counter == -1)
      {
        // change direction
        direction *= -1;
        // update counter; multiply by 2 so we don't do the last pin again
        counter += direction * 2;
      }
    }
    else
    {
      // nothing to do; we have to wait till the current led is switched off
    }
  }
}

Analyse it, play with it and ask if you don't understand.

// Edit: fixed a mistake in the explanation (see strike-throuugh)

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing. It may help with understanding the technique.

...R

Oh my sterretje, you are so close to what I had in mind it's amazing.
This is a great start, I don't understand it at this point in time but what an awesome place to start from.

The lines that are commented out (if that's the correct terminology) for the LED on Pin 29 are meant to blink separately at a different rate than the others.

//    digitalWrite(29, HIGH);                 //Blink LED on Pin 29 at one rate
//    delay(200);                             //Need to get Delay out of this entire Sketch
//    digitalWrite(29, LOW);
//    delay(200);

The other LED's were meant to turn on for 500ms and then off as the next one turns on.
When it gets to the last LED excluding 29 in all cases, that LED stays on for 1000ms before reversing direction. Then when it gets to the first one this time it again stays on for 1000ms before reversing direction again and so on forever.

I will try understand this code and modify it myself to get exactly what I'm looking for. I will not ask for any further help unless I get stuck again and will try to just get hints as opposed to all the code.

The next step is to replace a bunch of this code with a Timer Library, any suggestions which would be best for this particular application.

You guys are all so great and I don't know where you find the time to type in an entire Sketch to help newbies like me.

I can't Thank you enough.

Ok, so here's where I'm at.
This is so close to what I'm trying to achieve, just need help with one more thing.

LED 8 Blinks separately as I've set out to do. Perfect!
LED's - 1 to 7 Blink on for 1 sec then off for 1 sec then 2 goes on for 1 sec and so on. Close but not quite.

Where I would like to get to. LED 1 goes on for 1 sec then off as LED 2 turns on for 1 sec etc.
When we get to LED 7 it holds for 2 secs (I guess run two timer loops) then goes off as LED 6 goes on for 1 sec all the way back to LED 2. When we hit LED 1 this time it stays on for 2 secs then rinse and repeat.

Here's sterretje's code plus a small amount of mine.
Hints would be awesome not full code so that I can work this out myself.

One more thought. Is there any Timer Library that would allow me to keep the simplicity of the "for statements and replace the delays with a handoff to the Library. I almost had one working at one point, the only problem I always ran into was when I can out the " 'i' was not declared in this scope" error popped up.

Thanks again everyone. I'm almost there because of you guys.
Now maybe I will actually understand what's going on and I can move on to the next challenge in the book.

const int k_numLEDs = 8;                      //Define the number of LED's
const int kPinLeds[k_numLEDs] = {22, 23, 24, 25, 26, 27, 28, 29}; //Define MEGA 2560 Digital Pins

void setup()
{
  for (int i = 0; i < k_numLEDs; i++)         //Set all Eight Pins to OUTPUT's
  {
    pinMode(kPinLeds[i], OUTPUT);
    digitalWrite(kPinLeds[i], LOW);           //Set all Eight Pins LOW
  }
  delay(100);
}

// the current time
unsigned long currentTimeA;                   //Set the currentTime variable for Timer A
unsigned long currentTimeB;                   //Set the currentTime variable for Timer B
// last time that a LED changed state
unsigned long lastActionTimeA = 0;            //Set the last time an LED chnged State A
unsigned long lastActionTimeB = 0;            //Set the last time an LED chnged State B

void loop()
{

  // LED counter; I use a char instead of a byte so we can use negative values
  static char counter = 0;
  // direction; up = 1, down = -1
  static char direction = 1;

  // get the current time
  currentTimeA = millis();            //set currentTimeA to current milliseconds
  currentTimeB = millis();            //set currentTimeB to current milliseconds

  // if it's time

  if (currentTimeA - lastActionTimeA >= 300)    //Flash Pin 29 LED
{
    {byte leadStateA = digitalRead(29);
    leadStateA = !leadStateA;
    digitalWrite(29, leadStateA);}
    lastActionTimeA = currentTimeA;
}
    else    
    {
      // nothing to do; we have to wait till the current led is switched off
    }

  if (currentTimeB - lastActionTimeB >= 1000)
  {
    // read the status of the current led
    byte ledStateB = digitalRead(kPinLeds[counter]);

    // toggle the status before we write it to the pin
    ledStateB = !ledStateB;

    // set current pin
    digitalWrite(kPinLeds[counter], ledStateB);

    // remember the last time that we did an action
    lastActionTimeB = currentTimeB;

    // if led state equals LOW, we have done the cycle (on/off) for one LED
    if (ledStateB == LOW)
    {
      // next time, do next led
      counter += direction;

      // if all leds done for forward sequence or for reverse sequence
      if (counter == k_numLEDs -1 || counter == -1)   //-1 Exclude Pin 29 LED
      {
        // change direction
        direction *= -1;
        // update counter; multiply by 2 so we don't do the last pin again
        counter += direction * 2;
      }
    }
    else
    {
      // nothing to do; we have to wait till the current led is switched off
    }
  }
}
      for(int i = 0; i < k_numLEDs -1; i++)   //Turn 7 LED's on and off in sequence
      {digitalWrite(kPinLeds[i], HIGH);
      delay(500);
      digitalWrite(kPinLeds[i], LOW);}

      for(int i = k_numLEDs -2; i >= 0; i--)  //Reverse sequence
      {digitalWrite(kPinLeds[i], HIGH);
      delay(500);
      digitalWrite(kPinLeds[i], LOW);}

You need to include a flag for which timer is running.
Your code such as

 if (currentTimeB - lastActionTimeB >= 1000)
/[code]

Always execute if you are using timer B or not.
If you are not using timer B you shouldn't be doing anything
that depends on its value.
Dwight

I'm not quite at the point where I understand what you mean.

Both timers are running all the time as far as I know because the LED's are always Blinking.

Do however explain further for future reference.

Edit!!!!!!, maybe I do get what your saying. Below is the Sketch with the "currentTimeB = millis();" moved down just before the if statement for the second loop.

Thanks again.

const int k_numLEDs = 8;                      //Define the number of LED's
const int kPinLeds[k_numLEDs] = {22, 23, 24, 25, 26, 27, 28, 29}; //Define MEGA 2560 Digital Pins

void setup()
{
  for (int i = 0; i < k_numLEDs; i++)         //Set all Eight Pins to OUTPUT's
  {
    pinMode(kPinLeds[i], OUTPUT);
    digitalWrite(kPinLeds[i], LOW);           //Set all Eight Pins LOW
  }
  delay(100);
}

// the current time
unsigned long currentTimeA;                   //Set the currentTime variable for Timer A
unsigned long currentTimeB;                   //Set the currentTime variable for Timer B
// last time that a LED changed state
unsigned long lastActionTimeA = 0;            //Set the last time an LED chnged State A
unsigned long lastActionTimeB = 0;            //Set the last time an LED chnged State B

void loop()
{

  // LED counter; I use a char instead of a byte so we can use negative values
  static char counter = 0;
  // direction; up = 1, down = -1
  static char direction = 1;

  // get the current time
  currentTimeA = millis();            //set currentTimeA to current milliseconds

  // if it's time

  if (currentTimeA - lastActionTimeA >= 300)    //Flash Pin 29 LED
{
    {byte leadStateA = digitalRead(29);
    leadStateA = !leadStateA;
    digitalWrite(29, leadStateA);}
    lastActionTimeA = currentTimeA;
}
    else    
    {
      // nothing to do; we have to wait till the current led is switched off
    }
    currentTimeB = millis();            //set currentTimeB to current milliseconds
    if (currentTimeB - lastActionTimeB >= 1000)
  {
    // read the status of the current led
    byte ledStateB = digitalRead(kPinLeds[counter]);

    // toggle the status before we write it to the pin
    ledStateB = !ledStateB;

    // set current pin
    digitalWrite(kPinLeds[counter], ledStateB);

    // remember the last time that we did an action
    lastActionTimeB = currentTimeB;

    // if led state equals LOW, we have done the cycle (on/off) for one LED
    if (ledStateB == LOW)
    {
      // next time, do next led
      counter += direction;

      // if all leds done for forward sequence or for reverse sequence
      if (counter == k_numLEDs -1 || counter == -1)   //-1 Exclude Pin 29 LED
      {
        // change direction
        direction *= -1;
        // update counter; multiply by 2 so we don't do the last pin again
        counter += direction * 2;
      }
    }
    else
    {
      // nothing to do; we have to wait till the current led is switched off
    }
  }
}

You can remove the else statements, unless you expect to add something to it latter.
I see that you are using the two timers for two purposes.
It was OK the way it was.
I'm checking the rest of the code to figure what went wrong.
Dwight

Move setting the timer B to after the 'if' where it belongs.
You have nothing to make it hold the last count for 2 seconds.
You can't use counter for that because you would run the array wrong.

Another way to deal with it is to double the end LEDs in the array.
That would be two 22s and two 29s.
When counter over does the array, use your direction*2 to skip back.
You should be using -1 to k_numLEDs not to k_numLEDs-1.
Remember, arrays are 0 to size-1. You want to change it
when it reverses.
Also, set k_numLEDs to the new size of the array ( you added two values ).
Dwight

Please before reading this novel could I have this one question I've asked a couple of times answered.
Is there a Timer Library that will either simplify things or allow me to leave the for statements in as below and just replace the delay statements.

      for(int i = 0; i < k_numLEDs -1; i++)   //Turn 7 LED's on and off in sequence
      {digitalWrite(kPinLeds[i], HIGH);
      delay(500);
      digitalWrite(kPinLeds[i], LOW);}

      for(int i = k_numLEDs -2; i >= 0; i--)  //Reverse sequence
      {digitalWrite(kPinLeds[i], HIGH);
      delay(500);
      digitalWrite(kPinLeds[i], LOW);}

Ok I removed the else statements, I left them in at first because the sketch would do nothing without them. I must have been removing or leaving something else in that caused that problem.

Yep, I am using two timers for two purposes is that correct. What do mean by "It was OK the way it was.". Do you mean the I could have left "currentTimeB = millis();" below "currentTimeA = millis();" where I originally had it.

If I move the "currentTimeB = millis();" after second if statement the seven LED's never come on or do you mean put it after the first if statement.

I'm confused about this, "you should be using -1 to k_numLEDs not to k_numLEDs-1.". The "k_numLEDs-1" stops the LED on Pin 29 from flashing in the second loop. I want it to flash only in the first loop at a different rate. I've tried this "if (counter +1 == k_numLEDs || counter == -1)" and it also works.

I'm still trying to get the LED's to flash as explained earlier. LED 1 on 1 sec, then off as 2 turns on etc. instead of LED 1 on for 1 sec then off for 1 sec and next LED 2 on for 1 sec, etc..

Thanks

dwightthinker:
You have nothing to make it hold the last count for 2 seconds.

Another way to deal with it is to double the end LEDs in the array.
That would be two 22s and two 29s.
When counter over does the array, use your direction*2 to skip back.
Also, set k_numLEDs to the new size of the array ( you added two values ).
Dwight

Just had an idea and it now holds the last LED and the first LED on the second round and forever after.

I changed direction*2 to direction. It was there in the comment he left right from the beginning.

Thanks, thanks, thanks, thanks.

technogeekca:
Please before reading this novel could I have this one question I've asked a couple of times answered.
Is there a Timer Library that will either simplify things or allow me to leave the for statements in as below and just replace the delay statements.

Only with multi-tasking - which is not standard on Arduinos. You have one thread of control with one
stack so to do two things in parallel the code has to be event-driven.

Show your current code complete.
I didn't make sense out of that last post.
Dwight

technogeekca:
I'm not quite at the point where I understand what you mean.

Both timers are running all the time as far as I know because the LED's are always Blinking.

Do however explain further for future reference.

Edit!!!!!!, maybe I do get what your saying. Below is the Sketch with the "currentTimeB = millis();" moved down just before the if statement for the second loop.

Thanks again.

const int k_numLEDs = 8;                      //Define the number of LED's

const int kPinLeds[k_numLEDs] = {22, 23, 24, 25, 26, 27, 28, 29}; //Define MEGA 2560 Digital Pins

void setup()
{
  for (int i = 0; i < k_numLEDs; i++)        //Set all Eight Pins to OUTPUT's
  {
    pinMode(kPinLeds[i], OUTPUT);
    digitalWrite(kPinLeds[i], LOW);          //Set all Eight Pins LOW
  }
  delay(100);
}

// the current time
unsigned long currentTimeA;                  //Set the currentTime variable for Timer A
unsigned long currentTimeB;                  //Set the currentTime variable for Timer B
// last time that a LED changed state
unsigned long lastActionTimeA = 0;            //Set the last time an LED chnged State A
unsigned long lastActionTimeB = 0;            //Set the last time an LED chnged State B

void loop()
{

// LED counter; I use a char instead of a byte so we can use negative values
  static char counter = 0;
  // direction; up = 1, down = -1
  static char direction = 1;

// get the current time
  currentTimeA = millis();            //set currentTimeA to current milliseconds

// if it's time

if (currentTimeA - lastActionTimeA >= 300)    //Flash Pin 29 LED
{
    {byte leadStateA = digitalRead(29);
    leadStateA = !leadStateA;
    digitalWrite(29, leadStateA);}
    lastActionTimeA = currentTimeA;
}
    else   
    {
      // nothing to do; we have to wait till the current led is switched off
    }
    currentTimeB = millis();            //set currentTimeB to current milliseconds
    if (currentTimeB - lastActionTimeB >= 1000)
  {
    // read the status of the current led
    byte ledStateB = digitalRead(kPinLeds[counter]);

// toggle the status before we write it to the pin
    ledStateB = !ledStateB;

// set current pin
    digitalWrite(kPinLeds[counter], ledStateB);

// remember the last time that we did an action
    lastActionTimeB = currentTimeB;

// if led state equals LOW, we have done the cycle (on/off) for one LED
    if (ledStateB == LOW)
    {
      // next time, do next led
      counter += direction;

// if all leds done for forward sequence or for reverse sequence
      if (counter == k_numLEDs -1 || counter == -1)  //-1 Exclude Pin 29 LED
      {
        // change direction
        direction *= -1;
      // update counter; multiply by 2 so we don't do the last pin again
        counter += direction * 2;
      }
    }
    else
    {
      // nothing to do; we have to wait till the current led is switched off
    }
  }
}

OK, lets see if this works. From code in #9

change:

  {
    // read the status of the current led
    byte ledStateB = digitalRead(kPinLeds[counter]);

    // toggle the status before we write it to the pin
    ledStateB = !ledStateB;

    // set current pin
    digitalWrite(kPinLeds[counter], ledStateB);

    // remember the last time that we did an action
    lastActionTimeB = currentTimeB;

    // if led state equals LOW, we have done the cycle (on/off) for one LED
    if (ledStateB == LOW)
    {
      // next time, do next led
      counter += direction;

      // if all leds done for forward sequence or for reverse sequence
      if (counter == k_numLEDs -1 || counter == -1)   //-1 Exclude Pin 29 LED
      {
        // change direction
         direction *= -1;
      // update counter; multiply by 2 so we don't do the last pin again
        counter += direction * 2;
      }
    }
    else
    {
      // nothing to do; we have to wait till the current led is switched off
    }
   }

to:

  {
 
     if ( ledStateB == LOW ) // the next state
     {
            counter += direction;  // next light
     } 
     if ( counter == -1 || counter == k_numLEDs )  // illegal values for counter so turn around
     {
            direction *= -1;          // change direction
            counter += direction;  // do the last LED again
            lesStateB == HIGH;    // keep it back on one more time count
     }

     writeDigital( kPinLeds[counter],ledStateB);
     ledStateB = !ledStateB ;   // flip state

   }

I should note that you should move both lastActionTimeA and lastActionTimeB
before setup and set them to millis() in setup();
It may not be needed but then you don't assume that millis() always
starts at 0, even though I expect it does.
Check for matching {}
Dwight

// the current time

unsigned long currentTimeA;                  //Set the currentTime variable for Timer A
unsigned long currentTimeB;                  //Set the currentTime variable for Timer B

There is no need for two currentTime variables; one is sufficient.

technogeekca:
I changed direction*2 to direction. It was there in the comment he left right from the beginning.

Whatever is needed to achieve the desired affect; direction * 2 (in reply #4) just prevents that the first and the last led flash twice.
With direction * 2 the sequence is 1234567876543212345678......; with direction * 1 the sequence is 1234567888765432112345678......

dwightthinker:
It may not be needed but then you don't assume that millis() always
starts at 0, even though I expect it does.
Check for matching {}

millis() does start at zero :wink: But if you have a setup function that takes long (just add a delay to see the effect) it will not be zero by the time loop() is called for the first time.

sterretje:
millis() does start at zero :wink: But if you have a setup function that takes long (just add a delay to see the effect) it will not be zero by the time loop() is called for the first time.

That is a good reason why to set it in serup(). Modifying code later could
produce unexpected behavior.
Dwight