Switching period groups with the button

Ideally this code should toggle the LED flashing periods with a button. The code compiles successfully, but in practice it does not work as it should. The LEDs blink somehow, but it doesn't look like the specified algorithm.
Could you please tell me what could be the error in the code?

const byte ledPins[] = {1,2,3,4,5,6,7,8,9,10,11,12,13};
const byte NUMBER_OF_LEDS = sizeof(ledPins);
unsigned long startTimes[NUMBER_OF_LEDS] = {};
byte indexes[NUMBER_OF_LEDS] = {0};
const byte MAX_NUMBER_OF_PERIODS = 50;
int mp = 1;// multiplier

// periods for each LED. 0 indicates end of sequence
unsigned long periods1[][MAX_NUMBER_OF_PERIODS] = {
    {0, 1, 700, 600, 0},
      {0, 101, 700, 500, 0},
      {0, 201, 700, 400, 0},
      {0, 301, 700, 300, 0},
      {0, 401, 700, 200, 0},
      {0, 501, 700, 100, 0},
      {0, 601, 700, 0},
      {0, 501, 700, 100, 0},
      {0, 401, 700, 200, 0},
      {0, 301, 700, 300, 0},
      {0, 201, 700, 400, 0},
      {0, 101, 700, 500, 0},
      {0, 1, 700, 600, 0}
};

unsigned long periods2[][MAX_NUMBER_OF_PERIODS] = {
    {0, 1, 100, 700, 0},
      {0, 101, 100, 600, 0},
      {0, 201, 100, 500, 0},
      {0, 301, 100, 400, 0},
      {0, 401, 100, 300, 0},
      {0, 501, 100, 200, 0},
      {0, 601, 100, 100, 0},
      {0, 501, 100, 200, 0},
      {0, 401, 100, 300, 0},
      {0, 301, 100, 400, 0},
      {0, 201, 100, 500, 0},
      {0, 101, 100, 600, 0},
      {0, 1, 100, 700, 0}
};

unsigned long periods3[][MAX_NUMBER_OF_PERIODS] = {
    {0, 1, 100, 2300, 100, 100, 0},
      {0, 201, 100, 1900, 100, 300, 0},
      {0, 401, 100, 1500, 100, 500, 0},
      {0, 601, 100, 1100, 100, 700, 0},
      {0, 801, 100, 700, 100, 900, 0},
      {0, 1001, 100, 300, 100, 1100, 0},
      {0, 1201, 100, 1300, 0},
      {0, 1001, 100, 300, 100, 1100, 0},
      {0, 801, 100, 700, 100, 900, 0},
      {0, 601, 100, 1100, 100, 700, 0},
      {0, 401, 100, 1500, 100, 500, 0},
      {0, 201, 100, 1900, 100, 300, 0},
      {0, 1, 100, 2300, 100, 100, 0}
};

int currentPeriod = 0;
int totalPeriods = 3;
unsigned long (*periods[])[MAX_NUMBER_OF_PERIODS] = {periods1, periods2, periods3};

const byte BUTTON_PIN = 14;  // Define the button pin
bool buttonState = false;    // Variable to store the button state
unsigned long lastDebounceTime = 0;  // Variable to store the last time the button was pressed
const unsigned long DEBOUNCE_DELAY = 50;  // Debounce delay in milliseconds

void switchPeriods()
{
  //currentPeriod = (currentPeriod + 1) % totalPeriods;
  currentPeriod = currentPeriod + 1;
  if (currentPeriod >= totalPeriods)
  {
    currentPeriod = 0;
  }
  for (int led = 0; led < NUMBER_OF_LEDS; led++)
  {
    indexes[led] = 0;
  }
}

void setup()
{
  for (int led = 0; led < NUMBER_OF_LEDS; led++)
  {
    pinMode(ledPins[led], OUTPUT);
    // Initialize LEDs to ON state
    digitalWrite(ledPins[led], HIGH);
  }

  pinMode(BUTTON_PIN, INPUT_PULLUP);  // Set the button pin as input with internal pull-up resistor
}

void loop()
{
  unsigned long currentTime = millis();

  // Check the button state
  bool reading = digitalRead(BUTTON_PIN);
  if (reading != buttonState) {
    lastDebounceTime = currentTime;
    buttonState = reading;
  }

  if ((currentTime - lastDebounceTime) > DEBOUNCE_DELAY) {
    if (buttonState == LOW) {
      // Button is pressed, switch to the next group of periods
      switchPeriods();
    }
  }

  for (int led = 0; led < NUMBER_OF_LEDS; led++)  //iterate through the LEDs
  {
    if (currentTime - startTimes[led] >= periods[currentPeriod][led][indexes[led]])
    {
      // Flip LED state and update start time only if the current period is not the first one (i.e., it's a period for turning OFF the LED)
      if (indexes[led] > 0) {
        digitalWrite(ledPins[led], !digitalRead(ledPins[led]));  //flip led state
        startTimes[led] = currentTime;  //save start time of state
      }
      indexes[led]++;                    //increment index
    }
    if (periods[currentPeriod][led][indexes[led]] == 0)  //if next period is zero (end of sequence)
    {
      indexes[led] = 0;        //reset period index for this LED
      digitalWrite(ledPins[led], HIGH);
    }
  }  //end for loop
}

There are so many questions about your project and code / strategy….

Which processor / board are you using.
If it’s an AVR, pins 0-1 are typically used by the serial port for uploading, and potentially debugging.

Why are you using arrays of unsigned longs ? All your intervals are less than 65K.= wasted RAM

What is the code supposed to do ?

currentmillis should be global, otherwise as it is, you're wasting processor microseconds - creating and destroying the variable each time around loop().

The debounce processing is happening every time around loop, it should only happen if the button state has changed.

…and many more to come.

This returns the number of bytes... but I suspect you were looking for number of elements... try the following which reads the total bytes, then divides by the number of bytes in the first element to return number of elements.

const byte NUMBER_OF_LEDS = sizeof(ledPins)/sizeof(ledPins[0]);

Not an Uno/Nano. "Not enough memory" for my Nano.

What´s the task of the sketch in real life?

@kazan116 - I noticed your arrays have patterns. You can calculated those pattern to reduce the size of your compiled sketch. I wrote a similar "LED timing" sketch (see the timing diagram at the bottom). Maybe you can include your buttons into my sketch to create the timing you desire?

1 Like

Thank you so much! This code is much lighter and uses much less memory

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.