output states carried through multiple loops

I am new to Arduino and very rusty with any kind of programming, but I have been working on a bit of code for some flashing Christmas lights. I have succeeded in getting three separate flash patterns to alternate between each other like this:

void loop() {
unsigned long looptime = (millis() - startTime);

//run alpha loop
if (looptime <= 5000){
  alpha();
}// end alpha loop

//run bravo loop
else if (looptime > 5000 && looptime <= 10000){
  bravo();
}//end bravo loop

//run charlie loop
else if (looptime > 10000 && looptime <= 15000){
  charlie();
}//end charlie loop

//reset the clock to begin again
else if (looptime > 15000){
  startTime = millis();
}//end of reset
}

Each loop is merely variations on the "blink without delay" sample code. Right now I have 9 different LEDs on a breadboard that I am trying to bend to my will before I scale up to relays and strings of lights and such.

My problem is that at the end of each loop the state of the outputs carries over into the beginning of the next loop, but I want the lights to all be off at the beginning of each sequence. For example, the alpha loop has each light blinking at different speeds but the bravo loop has them all blinking at the same speed. I want them to all blink on and off together, but because some were on and some were off at the beginning of the alpha loop, although they blink at the same speed in the bravo loop, some are ON-OFF-ON and some are OFF-ON-OFF.

This seems like a simple problem but I cannot beat it. I appreciate any advice. How can I start each new loop with all outputs off?

Why not have another function switchAllOff() in which you set all the led outputs low, and ditto any led state flags you might have. Then call that just before calling a, b or c?

//run bravo loop
else if (looptime > 5000 && looptime <= 10000){
  switchAllOff()
  bravo();
}//end bravo loop

I tried that and could not get it too work. The program ran switchalloff() and bravo() at the same time for 5 seconds, and they fought with each other over whether the LEDs should blink or be off. Then I tried to get switchalloff() to run only once prior to calling bravo(), but I could not get that to work either.

Mine looked like this:

//run bravo loop
else if (looptime > 5000 && looptime <= 10000){
  turnalloff();
  bravo();
}//end bravo loop
[/void turnalloff(){
  digitalWrite(string1,LOW);
  digitalWrite(string2,LOW);
  digitalWrite(string3,LOW);
  digitalWrite(string4,LOW);
  digitalWrite(string5,LOW);
  digitalWrite(string6,LOW);
  digitalWrite(string7,LOW);
  digitalWrite(string8,LOW);
  digitalWrite(wreath,LOW);
}code]

Hmmmm... needs some flags then?

Have boolean turnedAllOff initialised false and only run turnalloff when turnedAllOff's false. Set it true when it's run, and find a place to set it false again for when you switch among a, b and c.

I have come to decide that what I was trying to do is not possible. I was trying to use the "blink without delay" example to flash 9 different LEDs on and off at the same time using 9 different digital outputs. The nature of the loop execution throws off the timing because they aren't all getting told to turn on and off at the same time.

I ended up rewriting my bravo loop to use the delay() function and it works just fine. Turn them all on, delay, turn them all off, delay, etc.

Where is the whole sketch? Without alpha(), bravo() and charlie() I am seeing snippets.

What I do see in

void loop() {
unsigned long looptime = (millis() - startTime);

//run alpha loop
if (looptime <= 5000){
  alpha();
}// end alpha loop

//run bravo loop
else if (looptime > 5000 && looptime <= 10000){
  bravo();
}//end bravo loop

//run charlie loop
else if (looptime > 10000 && looptime <= 15000){
  charlie();
}//end charlie loop

//reset the clock to begin again
else if (looptime > 15000){
  startTime = millis();
}//end of reset
}

is what I call event-driven code using time events.

But still I don't know what those three functions do. Could be good.....

This is a useful youtube video on using BlinkWithOutDelay on 2 totally independent LEDs, and the timing's in functions to keep loop() nice and tidy.

Where is the whole sketch? Without alpha(), bravo() and charlie() I am seeing snippets.

Here is as much of it as I can post at once due to length constraints. My original bravo loop was exactly the same as charlie loop except that all of the individual blinks were at the same speed.

void setup() {
  // set all used pins as outputs:
pinMode (string1, OUTPUT);
pinMode (string2, OUTPUT);
pinMode (string3, OUTPUT);
pinMode (string4, OUTPUT);
pinMode (string5, OUTPUT);
pinMode (string6, OUTPUT);
pinMode (string7, OUTPUT);
pinMode (string8, OUTPUT);
pinMode (wreath, OUTPUT);
}

void loop() {
unsigned long looptime = (millis() - startTime);

//run alpha loop
//all on
if (looptime <= 10000){
  alpha();
}// end alpha loop

//run bravo loop
//all blink together
else if (looptime > 10000 && looptime <= 15000){
 bravo();
 }//end bravo loop

//run charlie loop
//all blink at different speed
else if (looptime > 15000 && looptime <= 23000){
  charlie();
}//end charlie loop

//run delta loop
//house and wreath on, garage blinks at different speeds
else if (looptime > 23000 && looptime <= 31000){
  delta();
}//end delta loop

//run echo loop
//garage on, house and wreath blink at different speeds
else if (looptime > 31000 && looptime <= 39000){
  echo();
}//end echo loop

//run foxtrot loop
//knight rider
else if (looptime > 39000 && looptime <= 45400){
  foxtrot();
}//end foxtrot loop

//reset the clock to begin again
else if (looptime > 45400){
  startTime = millis();
}//end of reset
}

// describe alpha sequence
void alpha(){
  digitalWrite(string1,HIGH);
  digitalWrite(string2,HIGH);
  digitalWrite(string3,HIGH);
  digitalWrite(string4,HIGH);
  digitalWrite(string5,HIGH);
  digitalWrite(string6,HIGH);
  digitalWrite(string7,HIGH);
  digitalWrite(string8,HIGH);
  digitalWrite(wreath,HIGH);
} //end of alpha sequence

// describe bravo sequence
void bravo(){

  digitalWrite(string1,HIGH);
  digitalWrite(string2,HIGH);
  digitalWrite(string3,HIGH);
  digitalWrite(string4,HIGH);
  digitalWrite(string5,HIGH);
  digitalWrite(string6,HIGH);
  digitalWrite(string7,HIGH);
  digitalWrite(string8,HIGH);
  digitalWrite(wreath,HIGH);

  delay(500);

  digitalWrite(string1,LOW);
  digitalWrite(string2,LOW);
  digitalWrite(string3,LOW);
  digitalWrite(string4,LOW);
  digitalWrite(string5,LOW);
  digitalWrite(string6,LOW);
  digitalWrite(string7,LOW);
  digitalWrite(string8,LOW);
  digitalWrite(wreath,LOW);

  delay(500);

  digitalWrite(string1,HIGH);
  digitalWrite(string2,HIGH);
  digitalWrite(string3,HIGH);
  digitalWrite(string4,HIGH);
  digitalWrite(string5,HIGH);
  digitalWrite(string6,HIGH);
  digitalWrite(string7,HIGH);
  digitalWrite(string8,HIGH);
  digitalWrite(wreath,HIGH);

  delay(500);

  digitalWrite(string1,LOW);
  digitalWrite(string2,LOW);
  digitalWrite(string3,LOW);
  digitalWrite(string4,LOW);
  digitalWrite(string5,LOW);
  digitalWrite(string6,LOW);
  digitalWrite(string7,LOW);
  digitalWrite(string8,LOW);
  digitalWrite(wreath,LOW);

  delay(500);

  digitalWrite(string1,HIGH);
  digitalWrite(string2,HIGH);
  digitalWrite(string3,HIGH);
  digitalWrite(string4,HIGH);
  digitalWrite(string5,HIGH);
  digitalWrite(string6,HIGH);
  digitalWrite(string7,HIGH);
  digitalWrite(string8,HIGH);
  digitalWrite(wreath,HIGH);

  delay(500);

  digitalWrite(string1,LOW);
  digitalWrite(string2,LOW);
  digitalWrite(string3,LOW);
  digitalWrite(string4,LOW);
  digitalWrite(string5,LOW);
  digitalWrite(string6,LOW);
  digitalWrite(string7,LOW);
  digitalWrite(string8,LOW);
  digitalWrite(wreath,LOW);

  delay(500);

  digitalWrite(string1,HIGH);
  digitalWrite(string2,HIGH);
  digitalWrite(string3,HIGH);
  digitalWrite(string4,HIGH);
  digitalWrite(string5,HIGH);
  digitalWrite(string6,HIGH);
  digitalWrite(string7,HIGH);
  digitalWrite(string8,HIGH);
  digitalWrite(wreath,HIGH);

  delay(500);

  digitalWrite(string1,LOW);
  digitalWrite(string2,LOW);
  digitalWrite(string3,LOW);
  digitalWrite(string4,LOW);
  digitalWrite(string5,LOW);
  digitalWrite(string6,LOW);
  digitalWrite(string7,LOW);
  digitalWrite(string8,LOW);
  digitalWrite(wreath,LOW);

  delay(500);

  digitalWrite(string1,HIGH);
  digitalWrite(string2,HIGH);
  digitalWrite(string3,HIGH);
  digitalWrite(string4,HIGH);
  digitalWrite(string5,HIGH);
  digitalWrite(string6,HIGH);
  digitalWrite(string7,HIGH);
  digitalWrite(string8,HIGH);
  digitalWrite(wreath,HIGH);

  delay(500);

  digitalWrite(string1,LOW);
  digitalWrite(string2,LOW);
  digitalWrite(string3,LOW);
  digitalWrite(string4,LOW);
  digitalWrite(string5,LOW);
  digitalWrite(string6,LOW);
  digitalWrite(string7,LOW);
  digitalWrite(string8,LOW);
  digitalWrite(wreath,LOW);

  delay(500);

  digitalWrite(string1,HIGH);
  digitalWrite(string2,HIGH);
  digitalWrite(string3,HIGH);
  digitalWrite(string4,HIGH);
  digitalWrite(string5,HIGH);
  digitalWrite(string6,HIGH);
  digitalWrite(string7,HIGH);
  digitalWrite(string8,HIGH);
  digitalWrite(wreath,HIGH);

}//end of bravo sequence

//describe charlie sequence
void charlie(){

unsigned long current1millis = millis();
unsigned long current2millis = millis();
unsigned long current3millis = millis();
unsigned long current4millis = millis();
unsigned long current5millis = millis();
unsigned long current6millis = millis();
unsigned long current7millis = millis();
unsigned long current8millis = millis();
unsigned long currentwreath = millis();

//string #1 blink at 250 ms
if (current1millis - string1millis >= interval1){
  string1millis = current1millis;
if (string1state == LOW)
  {string1state = HIGH;}
  else
  {string1state = LOW;}
digitalWrite(string1, string1state);}

//string #2 blink at 500 ms
if (current2millis - string2millis >= interval2){
  string2millis = current2millis;
if (string2state == LOW)
  {string2state = HIGH;}
  else
  {string2state = LOW;}
digitalWrite(string2, string2state);}

//string #3 blink at 1000 ms
if (current3millis - string3millis >= interval3){
  string3millis = current3millis;
if (string3state == LOW)
  {string3state = HIGH;}
  else
  {string3state = LOW;}
digitalWrite(string3, string3state);}

//string #4 blink at 2000 ms
if (current4millis - string4millis >= interval4){
  string4millis = current4millis;
if (string4state == LOW)
  {string4state = HIGH;}
  else
  {string4state = LOW;}
digitalWrite(string4, string4state);}

//string #5 blink at 250 ms
if (current5millis - string5millis >= interval1){
  string5millis = current5millis;
if (string5state == LOW)
  {string5state = HIGH;}
  else
  {string5state = LOW;}
digitalWrite(string5, string5state);}

//string #6 blink at 500 ms
if (current6millis - string6millis >= interval2){
  string6millis = current6millis;
if (string6state == LOW)
  {string6state = HIGH;}
  else
  {string6state = LOW;}
digitalWrite(string6, string6state);}

//string #7 blink at 1000 ms
if (current7millis - string7millis >= interval3){
  string7millis = current7millis;
if (string7state == LOW)
  {string7state = HIGH;}
  else
  {string7state = LOW;}
digitalWrite(string7, string7state);}

//string #8 blink at 2000 ms
if (current8millis - string8millis >= interval4){
  string8millis = current8millis;
if (string8state == LOW)
  {string8state = HIGH;}
  else
  {string8state = LOW;}
digitalWrite(string8, string8state);}

//wreath blink at 5000 ms
if (currentwreath - wreathmillis >= intervalwr){
  wreathmillis = currentwreath;
if (wreathstate == LOW)
  {wreathstate = HIGH;}
  else
  {wreathstate = LOW;}
digitalWrite(wreath, wreathstate);}
}//end charlie sequence

manor_royal:
This is a useful youtube video on using BlinkWithOutDelay on 2 totally independent LEDs, and the timing's in functions to keep loop() nice and tidy.

Thanks for this link, I just watched the video. I may play with writing a separate loop to call out for each individual LED I'm operating to see if I can get them to all blink together that way.

Those 3 functions block/hold up execution badly: while any 1 runs, nothing else does.
That kind of wrecks the system you put in loop(). A 1 milli delay costs wastes 16000 cpu cycles.

Non-blocking functions don't have delays, they have timers or are called from inside of timers, only run if ( some time condition ) { run non-blocking function } -- always return quickly when waiting, not holding up execution and wasting cycles.

Have you seen how to use arrays and loops? Those could save you a lot of typing.

These Examples are in your IDE under File->Examples
https://www.arduino.cc/en/Tutorial/BuiltInExamples

You want to load and try these in your IDE while keeping the page for the example (with all the explains) you try on your browser. You can even open up a tab to the Arduino Reference Page to look up unfamiliar commands.

  1. Control Structures
  • Arrays: A variation on the For Loop example that demonstrates how to use an array.
  • For Loop Iteration: Control multiple LEDs with a for loop and.
  • If Statement Conditional: Use an ‘if statement’ to change the output conditions based on changing the input conditions.
  • Switch Case: How to choose between a discrete number of values.
  • Switch Case 2: A second switch-case example, showing how to take different actions based on the characters received in the serial port.
  • While Statement Conditional: How to use a while loop to calibrate a sensor while a button is being read.

An array lets you have one name for many values that you access by number(s). You can organize data into lines or matrices and get at it in various ways.

Loops tell you how to walk through arrays but warning here: long internal loops block, use an index but the outside Arduino void loop() that should step the indexed walk so that all functions take one step at a time together even if just to see it's not time or a pin hasn't changed yet because when it does you want to catch it ASAP.

Still the loop examples does show about accessing arrays through indexes.

Switch-case is key to making a function that behaves different ways depending on a value.
Do not miss that.

Please go through those section 5 tutorials. They will be your new tools, save you loads of time.

BUT don't recode alpha, bravo, etc, just yet. There's more savings to go.

Bytes are made of 8 bits. Bits are all 0 or 1, OFF or ON, false or true. You can loop through the bits in a byte and set pins, the patterns become numbers instead of lines of code. Saves a LOT of space and has advantages you can learn about later.

Let's see how you like this serial monitor (set to 250000) demo to show light pattern ability.

The code.

void showBits( byte bits )
{
  for ( byte i = 0; i < 8; i++ ) // show the bits of bits from high to low 
  {
    if ( bits & 128 ) // if bit 7 of bits is set, this is true
    {
      Serial.write( '*' ); 
    }
    else
    {
      Serial.write( '_' );
    }
    bits = bits << 1; // shift all the bits in bits up 1 bit. Bit 7 gets shifted out.
  }
}

void showVal( byte val )
{
    Serial.print( F( "  = " ));
    Serial.print( val );
    Serial.print( F( "  = 0x" ));
    if ( val < 0x10 )
    {
      Serial.write( '0' );
    }
    Serial.print( val, HEX );  
}

const byte patterns = 6; // room for more. Put in flash, a whole lot more.
byte pattern[ patterns ] = 
{ 
  0xF0, 0x0F, 0xCC, 0x33, 0xAA, 0x55 
};

void setup() 
{
  Serial.begin( 250000 ); // fastest rate I can use

  Serial.println( F( "Bit pattern demo, show 8 binary values.\n" )); // \n is newline

  byte x = 1;

  while ( x > 0 )
  {
    showBits( x );
    showVal( x );
    Serial.println();
    x = x << 1;
  }
  Serial.println( F( "\n" ));

  for ( x = 0; x < patterns; x++ )
  {
    showBits( pattern[ x ] );
    showVal( pattern[ x ] );
    Serial.println();
  }
}

void loop() 
{
}

The output. First it shows steps of light moving right to left then it shows 6 stored patterns.
Numbers that start with 0x are base 16, hexadecimal. Each hex digit is 4 bits, 2 per byte.

Bit pattern demo, show 8 binary values.

* = 1 = 0x01
* = 2 = 0x02
* = 4 = 0x04
* = 8 = 0x08
*
= 16 = 0x10
*
= 32 = 0x20
*
= 64 = 0x40
*
= 128 = 0x80

____ = 240 = 0xF0
____
= 15 = 0x0F
____ = 204 = 0xCC
**** = 51 = 0x33
_*_ = 170 = 0xAA
_
*_ = 85 = 0x55

What I print here can be leds ON and OFF. Point is that 8 light pattern only needs 1 byte storage.

GoForSmoke:
Those 3 functions block/hold up execution badly: while any 1 runs, nothing else does.

That was the whole point. I want it to step through each sequence one at a time for a specific duration. Nothing else needs to happen at the same time, flashing the lights in different patterns is what I wrote the code for.

I think I understand what you're saying with the for loops and arrays. I will go through those tutorials and try to learn something. I did look at the examples early on, that's where I found the blink without delay code I've copied and pasted in my charlie loop.

Honestly, the entirety of your last post is over my head. I'm not seeing how to apply printing stuff on my screen to making lights flash. I'm not doubting what you say, I'm just not understanding it.

The printing is just a simulation. People usually don't have the same setup as you do so they simulate using the serial port as (nearly?) everybody has the serial port in their setup.

@GoForSmoke tested the presented code and gave you the output. It's up to you to analyse and understand (and ask if you don't understand :wink: ).

It does not make much sense to use a millis() based timing in loop() but use delays in e.g. the bravo() function.

First of all you should read up on the for loop. Your bravo function repeats the on/off functionality numerous times.

The below flashes the leds 10 times (I did not count your number of flashes) and ends with all leds on

void bravo()
{
  for (int cnt = 0; cnt < 10; cnt++)
  {
    digitalWrite(string1, HIGH);
    digitalWrite(string2, HIGH);
    digitalWrite(string3, HIGH);
    digitalWrite(string4, HIGH);
    digitalWrite(string5, HIGH);
    digitalWrite(string6, HIGH);
    digitalWrite(string7, HIGH);
    digitalWrite(string8, HIGH);
    digitalWrite(wreath, HIGH);

    delay(500);

    digitalWrite(string1, LOW);
    digitalWrite(string2, LOW);
    digitalWrite(string3, LOW);
    digitalWrite(string4, LOW);
    digitalWrite(string5, LOW);
    digitalWrite(string6, LOW);
    digitalWrite(string7, LOW);
    digitalWrite(string8, LOW);
    digitalWrite(wreath, LOW);

    delay(500);
  }


  digitalWrite(string1, HIGH);
  digitalWrite(string2, HIGH);
  digitalWrite(string3, HIGH);
  digitalWrite(string4, HIGH);
  digitalWrite(string5, HIGH);
  digitalWrite(string6, HIGH);
  digitalWrite(string7, HIGH);
  digitalWrite(string8, HIGH);
  digitalWrite(wreath, HIGH);
}

You did not show how string1..string8 are declared. You can however declare it like (just change the pin numbers as needed)

const byte ledstring[] = {2, 3, 4, 5, 6, 7, 8, 9, 10};

And in setup() use a for loop go set them all to output.

const byte ledstring[] = {2, 3, 4, 5, 6, 7, 8, 9, 10};
const byte wreath = 11;

void setup()
{

  for(int ledcnt=0;ledcnt<sizeof(ledstring); ledcnt++)
  {
    pinMode(ledstring[ledcnt], OUTPUT);
  }
  pinMode (wreath, OUTPUT);
}

I have kept wreath as a separate variable, it can be incorporated in the array if needed (which will probably make the coding easier).

Now for the simple alpha and bravo patterns you can use for loops again to switch leds on or off

void alpha()
  for (int ledcnt = 0; ledcnt < sizeof(ledstring); ledcnt++)
  {
    digitalWrite(ledstring[ledcnt], HIGH);
  }
  digitalWrite(wreath, HIGH);
}

void bravo()
{
  for (int cnt = 0; cnt < 10; cnt++)
  {
    for (int ledcnt = 0; ledcnt < sizeof(ledstring); ledcnt++)
    {
      digitalWrite(ledstring[ledcnt], HIGH);
    }
    digitalWrite(wreath, HIGH);
    delay(500);

    for (int ledcnt = 0; ledcnt < sizeof(ledstring); ledcnt++)
    {
      digitalWrite(ledstring[ledcnt], LOW);
    }
    digitalWrite(wreath, LOW);
    delay(500);
  }

  for (int ledcnt = 0; ledcnt < sizeof(ledstring); ledcnt++)
  {
    digitalWrite(ledstring[ledcnt], HIGH);
  }
  digitalWrite(wreath, HIGH);
}

As said, it does not make much sense to use delays when using millis() based timings. So we can use a millis() based timing in bravo().

/*
  flash all leds 10 times
  starts with switching all leds on
  ends with all leds on

  returns:
    true if sequence has finished, else false
*/
bool bravo()
{
  // last time led state changed
  static unsigned long lastTime = 0;
  // current led state
  static int currentLedstate = HIGH;
  // count number of flashes
  static int flashcount = 0;

  // if it's time
  if (millis() - lastTime >= 500)
  {
    // update last time
    lastTime = millis();

    // toggle leds
    for (int ledcnt = 0; ledcnt < sizeof(ledstring); ledcnt++)
    {
      digitalWrite(ledstring[ledcnt], currentLedstate);
    }
    digitalWrite(wreath, currentLedstate);

    // change led state for next time that timer expires
    currentLedstate = !currentLedstate;

    // update flashcount
    flashcount++;
  }

  if (flashcount == 21)   // 10 times on/off plus 1 on at the end
  {
    currentLedstate = HIGH;
    flashcount = 0;
    lastTime = 0;

    // indicate sequence is finished
    return true;
  }

  // indicate sequence not finished
  return false;
}

And in loop you can test the return value to see if the sequence is completed or not

if (bravo() == true)
{
  // do charlie
  ...
  ...
}

Code not compiled or tested; it's meant to show you a different approach to your original bravo.

Note that the above is not a perfect solution; I would probably use bit patterns and loop through those.

bonddr24:
That was the whole point. I want it to step through each sequence one at a time for a specific duration. Nothing else needs to happen at the same time, flashing the lights in different patterns is what I wrote the code for.

That loses a lot of the flexibility the main code starts with. Otherwise, no biggie if you're happy with it.

I think I understand what you're saying with the for loops and arrays. I will go through those tutorials and try to learn something. I did look at the examples early on, that's where I found the blink without delay code I've copied and pasted in my charlie loop.

The arrays and loops can save the multiple copy, paste and modify method of coding by letting you write one set of lines to do all the patterns since they won't have different names to code, just different index numbers that can be looped through.

If I keep pin numbers in anrray;

const byte ledCount = 8;
const byte ledPin[ ledCount ] = { 2,7,4,9,5,12,A1,A4 }; // const never changes, pins can be in any order
....
....
for ( byte i = 0; i < ledCount; i++ ) // count through ledPin[] array indexes 0,1,2,..., ledCount-1
{
digitalWrite( ledPin[ i ], HIGH ); // turn the pin number stored in ledPin[ i ] to HIGH
}

One loop sets 8 pins HIGH in this case. That could vary with different code.

Honestly, the entirety of your last post is over my head. I'm not seeing how to apply printing stuff on my screen to making lights flash. I'm not doubting what you say, I'm just not understanding it.

Here's the function that prints those lines of * or _ to stand for led ON or OFF.

void showBits( byte bits )
{
  for ( byte i = 0; i < 8; i++ ) // show the bits of bits from high to low 
  {
    if ( bits & 128 ) // if bit 7 of bits is set, this is true
    {
      Serial.write( '*' ); 
    }
    else
    {
      Serial.write( '_' );
    }
    bits = bits << 1; // shift all the bits in bits up 1 bit. Bit 7 gets shifted out.
  }
}

Those lines that say Serial.write() could as easily be digitalWrite() with variable i used to tell which pin array element has the pin number and HIGH or LOW instead of '*' or '_'.

The deal about bits is that a single byte can hold 8 ON/OFF settings instead of using 8 variables or 8 digitalWrite() to do the same.

Right below I set up the 48 bits to make those 6 patterns in the bottom of the printout. It's a lot quicker to write than defining 48 different named variables and then coding one line each to show them.

byte pattern[ patterns ] = 
{ 
  0xF0, 0x0F, 0xCC, 0x33, 0xAA, 0x55 
}

____ = 240 = 0xF0
____
= 15 = 0x0F
____ = 204 = 0xCC
**** = 51 = 0x33
_*_ = 170 = 0xAA
_
*_ = 85 = 0x55

You have to read this stuff a bit more attentively than the latest news. The output shows what the code put out, reading the code to see how could show you something new.

sterretje:
As said, it does not make much sense to use delays when using millis() based timings. So we can use a millis() based timing in bravo().

/*

flash all leds 10 times
  starts with switching all leds on
  ends with all leds on

returns:
    true if sequence has finished, else false
*/
bool bravo()
{
  // last time led state changed
  static unsigned long lastTime = 0;
  // current led state
  static int currentLedstate = HIGH;
  // count number of flashes
  static int flashcount = 0;

// if it's time
  if (millis() - lastTime >= 500)
  {
    // update last time
    lastTime = millis();

// toggle leds
    for (int ledcnt = 0; ledcnt < sizeof(ledstring); ledcnt++)
    {
      digitalWrite(ledstring[ledcnt], currentLedstate);
    }
    digitalWrite(wreath, currentLedstate);

// change led state for next time that timer expires
    currentLedstate = !currentLedstate;

// update flashcount
    flashcount++;
  }

if (flashcount == 21)  // 10 times on/off plus 1 on at the end
  {
    currentLedstate = HIGH;
    flashcount = 0;
    lastTime = 0;

// indicate sequence is finished
    return true;
  }

// indicate sequence not finished
  return false;
}

This is actually the answer to the question I started the thread for. I was not able to get all lights to flash on and off together using millis() because I was commanding each light individually and they were getting out of sequence. An array takes care of that.

Thank you all for your input.

That last post was a lot more clear to me, GoForSmoke. Thank you for elaborating. I only get to play with this once or twice a week, but I will be working to improve my understanding and make my code more efficient. I think I understand what you're telling me now, I'm just going to have to study it and practice to get where I need to be.

I am incorporating improvements one at a time to my original code and testing each as I go to make sure my overall plan is still working. It'll get better as I go.

I don't know your background level, your computer and C literacy, and where you have holes. That makes it harder to know how best to get through.

If you don't know C then keeping a browser tab open to the Arduino Reference Page when you have a working example sketch in your open IDE. The Ref Page doesn't have everything but there's links there to a lot of everything, including the Learning link in the top green bar -- don't miss the resources on site here.

I've kept tabs open to library reference pages, I can view any at a click. I can zoom by steps (Firefox).

I have a technique to un-delay code, to make any function do actions on time without blocking as long as it gets called frequently. I prefer frequently per millisecond. :slight_smile:

---- this is not tested but it's kind of like spelling cat after a while.

void myUnDelayedFunction( )
{
static byte state = 0;
static unsigned long startMillis = 0, waitMillis = 0;

if ( waitMillis )
{
if ( millis() - startMillis >= waitMillis )
{
waitMillis = 0; // makes this timer a 1-shot
}
else
{
return; // non-blocking
}
}

switch ( state ) // there can be LOTS of cases below. simple example
{
case 0 :
// do something up to the point of needing a delay, maybe change a led pin
state = 1; // run case 1 next time
waitMillis = 500; // after half a second
break;

case 1 :
// do something up to the point of needing a delay, maybe change a led pin
state = 0; // run case 1 next time
waitMillis = 250; // after a quarter second
break;
}
}