No delay() led sequencing

Hello everyone. I have been working on a project now that involves using an IR remote control to select a couple of different patters of 3 LEDs built into a sign. Nothing very dramatic, for example I have 3 leds that I want to turn on in sequence with one second delay then after they are all on, turn them all off at once. Then maybe flash them once of twice then start all over again.
I have seen plenty of codes written for this however all the ones I have seen, turn off each LED before sequencing to the next one. Here is the code that I believe is close to what I want so I have been working off this one.

const byte ledPin[] = {5,6,7};   

byte ledCount = sizeof(ledPin) / sizeof(ledPin[0]);

const byte sequence[] = {0,1,2};

byte sequenceCount = sizeof(sequence) / sizeof(sequence[0]);

const unsigned long duration = 1000; // it's best to use unsigned longs with timing variables

// now we're ready to set our pins
void setup(){
    for (byte index = 0; index < ledCount; index++)
    {
         pinMode(ledPin[index], OUTPUT);
    }
}


void loop(){

static byte pointer = 0; // we'll use this to point to the current sequence
static unsigned long lastChangeTime = 0; // for timing purposes
unsigned long currentTime = millis();


if (currentTime - lastChangeTime > duration)
    {
     
         lastChangeTime = currentTime;
        
        for (byte index = 0; index < ledCount; index++)
        {
            if (index == sequence[pointer]) digitalWrite(ledPin[index], HIGH);
            else  digitalWrite(ledPin[index], LOW);
        }
      
     
        pointer = ++pointer % sequenceCount; // this will roll the pointer over to display the sequence again
    }
}

I'm betting that this is easy but I have been working on this for several weeks to no avail.
Thanks to all with any help.
Mark

How will this work when you reset lastChangeTime to 0 every time at the start of loop?

if (currentTime - lastChangeTime > duration)

After 1 second, it's always > duration.

sequencer can be done with: byte seq[nn]
Insert sequence data (up to 8 LEDs) in the array
led pattern example
ABC
b001
b011
b111
b111
b110
b100
b000
Your loop can use PORT-command to toggle all LEDs at a time
use a timer intr. to display 'next'

if this is the only thing to be done, each step in the sequence can even contain (use 3-4 bits) to indicate 'how many timeslices' this patter shall show. Should make this approach possible

CrossRoads,
Not sure exactly, but as it is now it stays in the loop but blinks on/off in sequence instead of turns on, one by one and then all turn off.
How would I modify that code to make that change?
I'm brand new to this as if you couldn't tell :slight_smile:

With some smart coding the contents in the array can change - radio or IR control
I was thinking like this (hav no leds - so not tested)
I

const byte ledPin[] = {5,6,7};   // port 
byte leds=sizeof(ledPin);

const byte seq[] = {0x11,0x13,0x17,0x16,0x14,0x10,0x10,0x31,0x33,0x37,0x36,0x34,0x30,0x10};
byte seqC=sizeof(seq);

unsigned int durfactor=300; // two to be altered by remote control if needed
byte i,first,present,last=seqC;  // first and last to be altered by remote control if needed
long next_time;

void setup()
{
  for (i=0;i<leds;i++) pinMode(ledPin[i],OUTPUT);
}

void loop()
{
  if (millis()>next_time)
  { // display current byte
    byte thisbyte=seq[present];
    next_time=millis()+((thisbyte&0xf0)>>4)*durfactor; // calculate time for next change
    //now display present status
    for (i=0; i<leds; i++)
    {
      digitalWrite(ledPin[i],thisbyte&1);
      thisbyte>>1;
    }
    present++;
    if (present>last) present=first;
  }
  // code for IR goes here  
}
void loop(){
currentTime = millis();
elapsedTime = currentMillis - previousMillis;
if (elapsedTime >= oneSecond){
previousMillis = previousMillis + oneSecond;
LEDcount = LEDcount +1;
if (LEDcount == 4){
LEDcount = 0;
digitalWrite (ledPinsArray[0], LOW); // assume Low = off, High = on
digitalWrite (ledPinsArray[1], LOW);
digitalWrite (ledPinsArray[2], LOW);
}
// crude method:
if (LEDcount == 1){
digitalWrite (ledPinsArray[0], HIGH);
}
if (LEDcount == 2){
digitalWrite (ledPinsArray[1], HIGH);
}
if (LEDcount == 3){
digitalWrite (ledPinsArray[2], HIGH);
}
} // end time check
} // end loop

Make sense? Checking time, and checking status/state

Thanks to both of you.
I am working on incorporating both of your suggestions to see which one works best with me.
I don't really understand yours knut_ny but it does work!
Once I get it looking pretty I'll post the total sketch.
I have a fundamental question about scope.
To make the whole script more readable, I have been trying to put all the functions at the bottom of the sketch and then just call them in the working body. My question is, I can make all my declarations within that function can't I ? Even the pinMode()? ( I normally see that in the setup(). )

To make the whole script more readable, I have been trying to put all the functions at the bottom of the sketch and then just call them in the working body.

As a hardware engineer, I find that approach really aggravating to work with. Too much scrolling back & forth to see what's going on.
I normally declare all variable types before setup, delclare all pinModes in setup, and then have inline code for loop. I don't (fully) buy the limited scope argument as saving any memory. If you're gonna need a variable, declare it and use it. If you have several for:loops, use 'x' as the counter for all of them if they run individually. If you have a loop within a loop, use x and y. Gonna need 2 bytes of SRAM free no matter what, so declare them at the top and use where needed.
Just my little hardware rant for the day, software guys will likely have lots of rationale why this isn't a good approach.

in programming its usual to select i,j,k for counters , often delared at 1.time use :
like : for (int i=0; .....)
Variables in general should have stateful names for easy reading

I wonder what is the difficult part with my example of 'running' leds.
I hope you can easily this composition.
Each byte ie seq:
Binary TTTT ABCD ,
e.g. 0x33= B 0011 0011 relates to: LED C and D on for 3 times duratation-time
and 0xA2 =B 1010 0010 relates to: LED C ony on for 10 times duratation-time
I selected to stuff both delay and pattern into same byte for saving RAM

To CrossRoads (on declaring global vars)

void stepforward( int no)
{  for (i=0; i<no; i++)
   {  // do something
      if (thishappens)  stepback();
  }
}
void stepback()
{  for (i=5; i>0; i--)
   {  // do something
  }
  return;
}

This is why those 'not important' variables chould be declared locally

Crossroads,
Yours makes sense. I am building your sketch as a stand alone first to try it out.
Could you please tell me whatI am leaving out as I am trying to declare the variables correctly. Thanks

unsigned long currentTime = millis();
unsigned long elapsedTime = 0;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;

const byte ledPinsArray[] = {5,6,7};
const unsigned long oneSecond=1000;
byte LEDcount;
void setup()
{
 Serial.begin(9600);
  unsigned char i;
  for(i=3;i<=7;i++)           //set pins 3-7 as output
    pinMode(i,OUTPUT); 
}
void loop(){
currentTime = millis();
elapsedTime = currentMillis - previousMillis;
if (elapsedTime >= oneSecond){
previousMillis = previousMillis + oneSecond;
LEDcount = LEDcount +1;
if (LEDcount == 4){
LEDcount = 0;
digitalWrite (ledPinsArray[0], LOW); // assume Low = off, High = on
digitalWrite (ledPinsArray[1], LOW);
digitalWrite (ledPinsArray[2], LOW);
}
// crude method:
if (LEDcount == 1){
digitalWrite (ledPinsArray[0], HIGH);
}
if (LEDcount == 2){
digitalWrite (ledPinsArray[1], HIGH);
}
if (LEDcount == 3){
digitalWrite (ledPinsArray[2], HIGH);
}
} // end time check
} // end loop

If it doesn't complain when compiling, then you got them all. That's how I find the ones I missed.

No complaints when compiling but nothing happens after upload.

LEDs are not wired backwards, are they? Code is expecting pin to anode, cathode (flatted edge of LED) to resistor to Gnd.

no my leds are working perfectly in other sketches as they are wired
using pins 5 6 7 right? let me analyze it a bit more and see what I'm missing

CrossRoads,
Got it working! And I makes sense to me too!
Thanks! Now I need to incorporate an led fade routine on the sketch for when the display is in idle.
I'll post when I got it !

My question is does that make the processor work harder and cause a possible problem/freeze later on?

Processor is running all the time, either watching time go by, or doing something after time has gone by.
So, no, not really.

Re: IR Interference, can you do this:

Serial.println(decCode);
if ( (results.value == IR_Key_1) ||  (results.value == IR_Key_2) ||  (results.value == IR_Key_3){
    switch (results.value) {

:
:
  }
}
else {
Serial.println ("bad value");   // for debugging
}

so you only act on good values and can see when bad one comes in?

Thank you CrossRoads, That makes perfect sense. I'll try it and let you know if it works.
Cheers,
Mark

CrossRoads,
Thanks again so much for your help.
As I mentioned your answer makes perfect sense, however I'm struggling to correctly insert this in my existing code.
Here is what I attempted but got several code violations of which most of them I didn't understand.

void loop() {
  if (irrecv.decode(&results)) {
    long int decCode = results.value;
    Serial.println(decCode);  {
    if ( (results.value == IR_Key_1) ||  (results.value == IR_Key_2) ||  (results.value == IR_Key_3)){
      switch (results.value) {

      //--------------------------Button 0 (power On/Off button)---------------------------------

    case IR_Key_PWR:                       //Power button pressed
      senseFlash();                     //Red LED flashes fast. Means IR signal was sensed
      togglePWR();                      //toggles all leds on or off depending on boolean state

      break;
      //--------------------------Button 1---------------------------------

    case IR_Key_1:
      delay(300);   //see if this helps debounce the IR sensor  
      irrecv.resume();  
      delay(300);   //see if this helps debounce the IR sensor 
      poweredOn=true;       //sets mode for the powerbutton toggle 
      ledCount=0;

      senseFlash();                         //Called senseFlash() Red LED flashes fast. Means IR signal was sensed
      Serial.println("Button 1");          //displays "button 4" on serial monitor
      allOff();                            //turn off any leftover lights before starting new pattern.
      digitalWrite(firstLEDPin, HIGH);
      do
      {
        static unsigned long lastChangeTime = 0; // for timing purposes
        unsigned long currentTime = millis();


        // we'll display all the leds then advance the pointer if it's time to
        {
          if (currentTime - lastChangeTime > duration)

          {
            lastChangeTime = currentTime;
            ledCount = ledCount + 1;
            if (ledCount == 10) {

              digitalWrite (secondLEDPin, HIGH); 
            }
            if (ledCount == 20) {
              digitalWrite (thirdLEDPin, HIGH); 
            }
            if (ledCount == 30) {
              digitalWrite (fourthLEDPin, HIGH); 
            }
            if (ledCount == 40) {
              threeOff();
            }
            if (ledCount==50){
              threeOn();
            }
            if (ledCount==55 ) {
              threeOff();

            }
            if (ledCount==60 ) {
              threeOn();

            }
            if (ledCount==80 ) {
              threeOff();
              ledCount=0;
            }
          }
        }
        irrecv.decode(&results);
      }
      while (results.value==IR_Key_1 );

      break; 

      //--------------------------Button 2---------------------------------

    case IR_Key_2:   
      delay(300);   //see if this helps debounce the IR sensor  
      irrecv.resume();  
      delay(300);   //see if this helps debounce the IR sensor 
      ledCount=0;
      senseFlash();                         //Red LED flashes fast. Means IR signal was sensed
      allOff();                            //turn off any leftover lights before starting new pattern.
      Serial.println("Button 2");            
      poweredOn=true; 
      digitalWrite(firstLEDPin, HIGH);
      do
      {
        static unsigned long lastChangeTime = 0; // for timing purposes
        unsigned long currentTime = millis();


        // we'll display all the leds then advance the pointer if it's time to
        {
          if (currentTime - lastChangeTime > duration)

          {
            lastChangeTime = currentTime;
            ledCount = ledCount + 10;
            if (ledCount == 10) {

              digitalWrite (secondLEDPin, HIGH); 
            }
            if (ledCount == 20) {
              digitalWrite (thirdLEDPin, HIGH); 
            }
            if (ledCount == 30) {
              digitalWrite (fourthLEDPin, HIGH); 
            }
            if (ledCount == 40) {
              threeOff();
            }
            if (ledCount==50){
              threeOn();
            }
            if (ledCount==55 ) {
              threeOff();

            }
            if (ledCount==60 ) {
              threeOn();

            }
            if (ledCount==80 ) {
              threeOff();
              ledCount=0;
            }
          }
        }
        irrecv.decode(&results);
      }
      while (results.value==IR_Key_2);

      break;
      //------------------------------------Button 3----------------------------------
    case IR_Key_3:
      senseFlash();
      Serial.println("Button 3");

    default:
      allOn();
      poweredOn==true;
      Serial.println("Default");

      break;
    }

    irrecv.resume();                             // Receive the next value
  }
else {
Serial.println ("bad value");   // for debugging
}
}

What are the violations?
We can help debug if you post the whole code so we can see how it compiles.

hello arduino team, this is my first forum post. I have only started to try coding recently because of this community and am grateful for any assistance anyone can offer.

I have began coding a polyphonic "note" (LED) sequencer. simple concept I hope
Basic setup so far
8 step
4 part
input : ps2 keyboard
output : ascii terminal characters + digital pin triggers analog drum triggers or others possibly arpeggios for Mozzi synth

I would rather not use the delay function.

/*
PS2 KEYBOARD -> ASCII Terminal + pinMode output trigger////////////////////////////////////////// * music note Step Sequencer * //////////////////////////////////////////////////
THIS IS THE PROGRAM I "CUT MY TEETH" ON PLEASE HELP ME ADD A BPM METRONOME AND REMOVE THE delays 
*/

#include <PS2Keyboard.h>

const int DataPin = 2;
const int IRQpin =  3;
int playStop = 8;
PS2Keyboard keyboard;
int time = 300;
int kick  = 4;
int snare = 7;
int hat   = 8;
char drum_1[9] =  { '-', '-', '-', '-', '-', '-', '-', '-', } ;   
char drum_2[9] =  { '-', '-', '-', '-', '-', '-', '-', '-', } ;
char drum_3[9] =  { '-', '-', '-', '-', '-', '-', '-', '-', } ;



void setup()			  
{
  delay(1000);
  keyboard.begin(DataPin, IRQpin);
  Serial.begin(9600);
  pinMode(kick,OUTPUT);
  pinMode(snare,OUTPUT);
  
}

void loop()
{
  if ( playStop == 0){
             
             play();
             
  } else if  (keyboard.available())
  {
    char c = keyboard.read();




    if (c == PS2_ENTER & playStop == 8){
             playStop = 0;
             //play();
  
     
   }  
 }
}


void play()
{
   
   for (int i = playStop; i < 8; i++)
   
    
                       
   {
     
    Serial.print   (drum_1[i] );           
    Serial.print   (drum_2[i]);
    Serial.println (drum_3[i]);
    digitalWrite (kick, LOW);
     delay(time);
     
     
     if (keyboard.available())
   {   
            
           char c = keyboard.read();   
           {
   
           if  (c == PS2_ENTER & playStop == 0){
             playStop = 8;
             i = 8;
     /*                                             This is where I began to tiker with the tempo/metronome I eventuall want to use a 8 or 4 count modulo operator for BPM 
                                                     also I WOULD RATHER NOT USE THE DELAY function so other actions can take place.
    } else if  (c == '-' &  time <= 300)  {       
              time + 20 ;
            
    } else if  (c == '=' & time >= 100)  {       
              time - 20 ;        
    */          
              
    } else if (c == '1' & drum_1[0] == '-' ) {
             drum_1[0] = 'K';             
    } else if (c == '1' & drum_1[0] == 'K' ) {
             drum_1[0] = '-';
    } else if (c == 'q' & drum_2[0] == '-' ) {
             drum_2[0] = 'S';             
    } else if (c == 'q' & drum_2[0] == 'S' ) {
             drum_2[0] = '-';
    } else if (c == 'a' & drum_3[0] == '-' ) {
             drum_3[0] = 'H';             
    } else if (c == 'a' & drum_3[0] == 'H' ) {
             drum_3[0] = '-'; 
             
              
    } else if (c == '2' & drum_1[1] == '-' ) {
             drum_1[1] = 'K';             
    } else if (c == '2' & drum_1[1] == 'K' ) {
             drum_1[1] = '-';
    } else if (c == 'w' & drum_2[1] == '-' ) {
             drum_2[1] = 'S';             
    } else if (c == 'w' & drum_2[1] == 'S' ) {
             drum_2[1] = '-';
    } else if (c == 's' & drum_3[1] == '-' ) {
             drum_3[1] = 'H';             
    } else if (c == 's' & drum_3[1] == 'H' ) {
             drum_3[1] = '-';
             
             
    } else if (c == '3' & drum_1[2] == '-') {
             drum_1[2] = 'K';
    } else if (c == '3' & drum_1[2] == 'K') {
             drum_1[2] = '-';
    } else if (c == 'e' & drum_2[2] == '-') {
             drum_2[2] = 'S';
    } else if (c == 'e' & drum_2[2] == 'S') {
             drum_2[2] = '-';
    } else if (c == 'd' & drum_3[2] == '-') {
             drum_3[2] = 'H';
    } else if (c == 'd' & drum_3[2] == 'H') {
             drum_3[2] = '-';
             
             
    } else if (c == '4' & drum_1[3] == '-' ) {
             drum_1[3] = 'K';             
    } else if (c == '4' & drum_1[3] == 'K' ) {
             drum_1[3] = '-';
    } else if (c == 'r' & drum_2[3] == '-' ) {
             drum_2[3] = 'S';             
    } else if (c == 'r' & drum_2[3] == 'S' ) {
             drum_2[3] = '-';
    } else if (c == 'f' & drum_3[3] == '-' ) {
             drum_3[3] = 'H';             
    } else if (c == 'f' & drum_3[3] == 'H' ) {
             drum_3[3] = '-';
             
             
    } else if (c == '5' & drum_1[4] == '-') {
             drum_1[4] = 'K';
    } else if (c == '5' & drum_1[4] == 'K') {
             drum_1[4] = '-';
    } else if (c == 't' & drum_2[4] == '-') {
             drum_2[4] = 'S';
    } else if (c == 't' & drum_2[4] == 'S') {
             drum_2[4] = '-';
    } else if (c == 'g' & drum_3[4] == '-') {
             drum_3[4] = 'H';
    } else if (c == 'g' & drum_3[4] == 'H') {
             drum_3[4] = '-';
             
             
    } else if (c == '6' & drum_1[5] == '-' ) {
             drum_1[5] = 'K';             
    } else if (c == '6' & drum_1[5] == 'K' ) {
             drum_1[5] = '-';
    } else if (c == 'y' & drum_2[5] == '-' ) {
             drum_2[5] = 'S';             
    } else if (c == 'y' & drum_2[5] == 'S' ) {
             drum_2[5] = '-';
    } else if (c == 'h' & drum_3[5] == '-' ) {
             drum_3[5] = 'H';             
    } else if (c == 'h' & drum_3[5] == 'H' ) {
             drum_3[5] = '-';
             
             
    } else if (c == '7' & drum_1[6] == '-') {
             drum_1[6] = 'K';
    } else if (c == '7' & drum_1[6] == 'K') {
             drum_1[6] = '-';
    } else if (c == 'u' & drum_2[6] == '-') {
             drum_2[6] = 'S';
    } else if (c == 'u' & drum_2[6] == 'S') {
             drum_2[6] = '-';
    } else if (c == 'j' & drum_3[6] == '-') {
             drum_3[6] = 'H';
    } else if (c == 'j' & drum_3[6] == 'H') {
             drum_3[6] = '-';         
                       
    } else if (c == '8' & drum_1[7] == '-') {
             drum_1[7] = 'K';
    } else if (c == '8' & drum_1[7] == 'K') {
             drum_1[7] = '-';
    } else if (c == 'i' & drum_2[7] == '-') {
             drum_2[7] = 'S';
    } else if (c == 'i' & drum_2[7] == 'S') {
             drum_2[7] = '-';         
    } else if (c == 'k' & drum_3[7] == '-') {
             drum_3[7] = 'H';
    } else if (c == 'k' & drum_3[7] == 'H') {
             drum_3[7] = '-';         
  /*                                               This is where I began trying to add the digital pinsMode ouputs pulse triggers. I realized that there must be a more appropriate way and the delays are not the best method please help
  
  //                                                    thanksAlot[] {"arduinoTeam"};
                                                          
     if (drum_1[i] == 'K') {
          digitalWrite(kick,HIGH); 
          delay (12); 
    } else if (drum_1[i] == '-') {
           digitalWrite(kick,LOW); 
           delay (12);  
           
     if (drum_2[i] == 'S') {
            digitalWrite(snare,HIGH); 
            delay (12); 
            digitalWrite(kick,LOW);  
   } else if (drum_2[i] == '-') {
            digitalWrite(snare,LOW); 
            delay (12);   
      
           if (drum_3[i] == 'H') {
           digitalWrite(hat,HIGH); 
           delay (12); 
           digitalWrite(kick,LOW);  
    } else if (drum_3[i] == '-') {
           digitalWrite(hat,LOW); 
           delay (12);      
    } else if (drum_3[i] == 'H') {
            digitalWrite(kick,HIGH); 
            delay (12); 
            digitalWrite(kick,LOW);   
   */

    

   }
           }
   }
   }
   }