Using serial input to blink 8 leds multiple cycles with a push button

I'm working on my project of blinking 8 LEDs multiple cycles using esp32-s3, which has this weird problem. In the first cycle, it has no problem. For example, all cycle inputs are the same (1 2 3 4 5 6 7 8). At first cycle, it's fine. In the second cycle, the LEDs start to bink like the input is ( 0 1 2 3 4 5 6 7). And in the third cycle, the output becomes (8 0 1 2 3 4 5 6). I think this is the problem when getting input from the serial monitor but I don't know how to fix this. Can someone help me find the solution for this?
(https://youtube.com/shorts/8EAeeey00Cg?si=fXKury9qSdx3suFj) Here is the video I made when trying with (1 1 1 1 1 1 1 1) input for all three cycles.

// Array of LED pins
int ledPins[] = {2, 4, 5, 12, 13, 14, 15, 16};

// Button pin
const int buttonPin = 17;

// Button state variables
int buttonState = 0;
int lastButtonState = 0;

// Button press counter to track which cycle to run
int cycleCounter = 0;

// Arrays to store the blink counts for each LED across 3 cycles
int blinkCountsCycle1[8];
int blinkCountsCycle2[8];
int blinkCountsCycle3[8];

// Variables for button debouncing
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;  // 50ms debounce delay

// Function to safely read input and avoid missing values
int readBlinkCount() {
  while (Serial.available() == 0) {
    // Wait for user input
  }
  return Serial.parseInt();
}

void setup() {
  // Initialize the LED pins as outputs
  for (int i = 0; i < 8; i++) {
    pinMode(ledPins[i], OUTPUT);
  }

  // Initialize the button pin as input
  pinMode(buttonPin, INPUT);

  // Start serial communication
  Serial.begin(115200);

  // Wait for serial monitor to connect
  while (!Serial) {
    delay(10);
  }

  // Prompt the user to input blink counts for Cycle 1
  Serial.println("Enter the blink count for each LED (8 values) for Cycle 1:");
  for (int i = 0; i < 8; i++) {
    blinkCountsCycle1[i] = readBlinkCount();
  }

  // Prompt the user to input blink counts for Cycle 2
  Serial.println("Enter the blink count for each LED (8 values) for Cycle 2:");
  for (int i = 0; i < 8; i++) {
    blinkCountsCycle2[i] = readBlinkCount();
  }

  // Prompt the user to input blink counts for Cycle 3
  Serial.println("Enter the blink count for each LED (8 values) for Cycle 3:");
  for (int i = 0; i < 8; i++) {
    blinkCountsCycle3[i] = readBlinkCount();
  }

  // Confirm that blink values are set for all 3 cycles
  Serial.println("Blink settings updated for all 3 cycles.");
}

void loop() {
  // Read the current button state
  int reading = digitalRead(buttonPin);

  // Debounce the button: If the button state has changed and it has been long enough
  if (reading != lastButtonState) {
    lastDebounceTime = millis();  // Reset the debounce timer
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // Only register the button press when the state has stabilized
    if (reading != buttonState) {
      buttonState = reading;

      // Only act if the button is pressed (HIGH state)
      if (buttonState == HIGH) {
        cycleCounter++;  // Increment cycle counter on valid button press

        // Pointer to hold the address of the current cycle's blink counts
        int* blinkCounts;

        if (cycleCounter == 1) {
          Serial.println("Starting Cycle 1:");
          blinkCounts = blinkCountsCycle1;  // Point to Cycle 1's blink counts
        } 
        else if (cycleCounter == 2) {
          Serial.println("Starting Cycle 2:");
          blinkCounts = blinkCountsCycle2;  // Point to Cycle 2's blink counts
        } 
        else if (cycleCounter == 3) {
          Serial.println("Starting Cycle 3:");
          blinkCounts = blinkCountsCycle3;  // Point to Cycle 3's blink counts
          cycleCounter = 0;  // Reset to 0 after the third cycle is complete
        }

        // If we have valid blink counts for this cycle, blink the LEDs
        if (blinkCounts != nullptr) {
          printBlinkCounts(blinkCounts);  // Show blink counts for current cycle
          blinkLEDs(blinkCounts);         // Use pointer to blink counts for current cycle
        }
      }
    }
  }

  // Save the current reading as the last button state for the next loop iteration
  lastButtonState = reading;

  delay(50);  // Short delay for button debounce
}

// Function to blink LEDs based on the provided blink counts array (using pointer)
void blinkLEDs(int* blinkCounts) {
  for (int i = 0; i < 8; i++) {
    // Debug output to ensure each LED is handled correctly
    Serial.print("Blinking LED ");
    Serial.print(i + 1);
    Serial.print(" for ");
    Serial.print(*(blinkCounts + i));  // Use pointer arithmetic to get blink count
    Serial.println(" times.");

    // Blink the current LED the specified number of times
    for (int j = 0; j < *(blinkCounts + i); j++) {
      digitalWrite(ledPins[i], HIGH);  // Turn the LED on
      delay(500);                      // Wait for 500 milliseconds
      digitalWrite(ledPins[i], LOW);   // Turn the LED off
      delay(500);                      // Wait for 500 milliseconds
    }
  }
}

// Function to print how many times each LED will blink per cycle (using pointer)
void printBlinkCounts(int* blinkCounts) {
  for (int i = 0; i < 8; i++) {
    Serial.print("LED ");
    Serial.print(i + 1);
    Serial.print(" will blink ");
    Serial.print(*(blinkCounts + i));  // Use pointer arithmetic to get blink count
    Serial.println(" times.");
  }
}

Here is the serial monitor when I did the (1 2 3 4 5 6 7 8) input for all three cycle.

16:52:14.537 -> Enter the blink count for each LED (8 values) for Cycle 1:
16:52:34.373 -> Enter the blink count for each LED (8 values) for Cycle 2:
16:52:38.776 -> Enter the blink count for each LED (8 values) for Cycle 3:
16:52:42.831 -> Blink settings updated for all 3 cycles.
16:52:47.845 -> Starting Cycle 1:
16:52:47.845 -> LED 1 will blink 1 times.
16:52:47.845 -> LED 2 will blink 2 times.
16:52:47.887 -> LED 3 will blink 3 times.
16:52:47.887 -> LED 4 will blink 4 times.
16:52:47.887 -> LED 5 will blink 5 times.
16:52:47.887 -> LED 6 will blink 6 times.
16:52:47.887 -> LED 7 will blink 7 times.
16:52:47.887 -> LED 8 will blink 8 times.
16:52:47.887 -> Blinking LED 1 for 1 times.
16:52:48.873 -> Blinking LED 2 for 2 times.
16:52:50.889 -> Blinking LED 3 for 3 times.
16:52:53.892 -> Blinking LED 4 for 4 times.
16:52:57.891 -> Blinking LED 5 for 5 times.
16:53:02.883 -> Blinking LED 6 for 6 times.
16:53:08.883 -> Blinking LED 7 for 7 times.
16:53:15.892 -> Blinking LED 8 for 8 times.
16:53:26.072 -> Starting Cycle 2:
16:53:26.072 -> LED 1 will blink 0 times.
16:53:26.072 -> LED 2 will blink 1 times.
16:53:26.072 -> LED 3 will blink 2 times.
16:53:26.072 -> LED 4 will blink 3 times.
16:53:26.072 -> LED 5 will blink 4 times.
16:53:26.117 -> LED 6 will blink 5 times.
16:53:26.117 -> LED 7 will blink 6 times.
16:53:26.117 -> LED 8 will blink 7 times.
16:53:26.117 -> Blinking LED 1 for 0 times.
16:53:26.117 -> Blinking LED 2 for 1 times.
16:53:27.085 -> Blinking LED 3 for 2 times.
16:53:29.085 -> Blinking LED 4 for 3 times.
16:53:32.106 -> Blinking LED 5 for 4 times.
16:53:36.085 -> Blinking LED 6 for 5 times.
16:53:41.085 -> Blinking LED 7 for 6 times.
16:53:47.103 -> Blinking LED 8 for 7 times.
16:54:02.648 -> Starting Cycle 3:
16:54:02.648 -> LED 1 will blink 8 times.
16:54:02.648 -> LED 2 will blink 0 times.
16:54:02.648 -> LED 3 will blink 1 times.
16:54:02.648 -> LED 4 will blink 2 times.
16:54:02.648 -> LED 5 will blink 3 times.
16:54:02.648 -> LED 6 will blink 4 times.
16:54:02.648 -> LED 7 will blink 5 times.
16:54:02.690 -> LED 8 will blink 6 times.
16:54:02.690 -> Blinking LED 1 for 8 times.
16:54:10.704 -> Blinking LED 2 for 0 times.
16:54:10.704 -> Blinking LED 3 for 1 times.
16:54:11.695 -> Blinking LED 4 for 2 times.
16:54:13.689 -> Blinking LED 5 for 3 times.
16:54:16.656 -> Blinking LED 6 for 4 times.
16:54:20.695 -> Blinking LED 7 for 5 times.
16:54:25.672 -> Blinking LED 8 for 6 times.```

what does the code need to do?

tldr; First print the results of taking all that input.

Next, place some numbers in your arrays and skip the serial input.

It looks plausible.

  // Confirm that blink values are set for all 3 cycles

First print the results of taking all that input. Just to see that you've acquired the three sets of blink counts correctly.

Then I got nothing until I can execute your code. Your description is a tiny bit vague to me, running the code we could see what is what.

It looks like you have enough serial

I am curious, however, why you have chosen to use pointers in this. Pointers are fun, but here they needlessly complicate the code, making it harder to roll along here on the rails and just read the code and see that it is correct, or spot the error accounting for your odd symptoms.

It need to blink the leds according to the serial input

Thanks, I can try that.
I tried pointer thinking it will fix my problem but seem like it not.

Sorry. I forgot to put the serial monitor screen for reference:

16:52:14.537 -> Enter the blink count for each LED (8 values) for Cycle 1:
16:52:34.373 -> Enter the blink count for each LED (8 values) for Cycle 2:
16:52:38.776 -> Enter the blink count for each LED (8 values) for Cycle 3:
16:52:42.831 -> Blink settings updated for all 3 cycles.
16:52:47.845 -> Starting Cycle 1:
16:52:47.845 -> LED 1 will blink 1 times.
16:52:47.845 -> LED 2 will blink 2 times.
16:52:47.887 -> LED 3 will blink 3 times.
16:52:47.887 -> LED 4 will blink 4 times.
16:52:47.887 -> LED 5 will blink 5 times.
16:52:47.887 -> LED 6 will blink 6 times.
16:52:47.887 -> LED 7 will blink 7 times.
16:52:47.887 -> LED 8 will blink 8 times.
16:52:47.887 -> Blinking LED 1 for 1 times.
16:52:48.873 -> Blinking LED 2 for 2 times.
16:52:50.889 -> Blinking LED 3 for 3 times.
16:52:53.892 -> Blinking LED 4 for 4 times.
16:52:57.891 -> Blinking LED 5 for 5 times.
16:53:02.883 -> Blinking LED 6 for 6 times.
16:53:08.883 -> Blinking LED 7 for 7 times.
16:53:15.892 -> Blinking LED 8 for 8 times.
16:53:26.072 -> Starting Cycle 2:
16:53:26.072 -> LED 1 will blink 0 times.
16:53:26.072 -> LED 2 will blink 1 times.
16:53:26.072 -> LED 3 will blink 2 times.
16:53:26.072 -> LED 4 will blink 3 times.
16:53:26.072 -> LED 5 will blink 4 times.
16:53:26.117 -> LED 6 will blink 5 times.
16:53:26.117 -> LED 7 will blink 6 times.
16:53:26.117 -> LED 8 will blink 7 times.
16:53:26.117 -> Blinking LED 1 for 0 times.
16:53:26.117 -> Blinking LED 2 for 1 times.
16:53:27.085 -> Blinking LED 3 for 2 times.
16:53:29.085 -> Blinking LED 4 for 3 times.
16:53:32.106 -> Blinking LED 5 for 4 times.
16:53:36.085 -> Blinking LED 6 for 5 times.
16:53:41.085 -> Blinking LED 7 for 6 times.
16:53:47.103 -> Blinking LED 8 for 7 times.
16:54:02.648 -> Starting Cycle 3:
16:54:02.648 -> LED 1 will blink 8 times.
16:54:02.648 -> LED 2 will blink 0 times.
16:54:02.648 -> LED 3 will blink 1 times.
16:54:02.648 -> LED 4 will blink 2 times.
16:54:02.648 -> LED 5 will blink 3 times.
16:54:02.648 -> LED 6 will blink 4 times.
16:54:02.648 -> LED 7 will blink 5 times.
16:54:02.690 -> LED 8 will blink 6 times.
16:54:02.690 -> Blinking LED 1 for 8 times.
16:54:10.704 -> Blinking LED 2 for 0 times.
16:54:10.704 -> Blinking LED 3 for 1 times.
16:54:11.695 -> Blinking LED 4 for 2 times.
16:54:13.689 -> Blinking LED 5 for 3 times.
16:54:16.656 -> Blinking LED 6 for 4 times.
16:54:20.695 -> Blinking LED 7 for 5 times.
16:54:25.672 -> Blinking LED 8 for 6 times.

what are those inputs? what should the LEDs do for the for each "command"?

can't tell you how to fix the code without knowing what it's suppose to do?

Sorry for being a bit vague. I want to make 8 LEDs blink in sequence 3 times( cycles), each time can have a different input for each LED and be separated by a pressed button. For example (I already put the serial monitor screen for reference): I input 8 digits into a serial monitor for the first cycle (1 2 3 4 5 6 7 8 ), second and third are the same. And the result is not the same for the second and the third cycles.

so you want to enter a list of #s thru the serial monitor, for example 2861 and you want those LEDs to turn on in that sequence and turn off at the end of the sequence, 3 times

why do you need a button?

The button is necessary for my project. This project is not about blinking led but something like door handles to open and close separately depend on time cycle. I just make it become led blinking to simplify my code. the button is to make sure the LEDs only blink when I allow it.

what does the button do?

when the LEDs blink, should all the LEDs that need to be turned on turn on at the same time?

each cycle is as long as necessary to blink the LEDs with the highest blink count?

it would help if you would explain things fully. otherwise i need to ask quesitons which takes time

(https://youtube.com/shorts/8EAeeey00Cg?si=CY2VMhYBuyqPdE_a)
Here is the video I made when trying with (1 1 1 1 1 1 1 1) input for all three cycle. Hope this will make thing clearer for everyone.

your code is hard to read

look this over, it does blinking without worrying about how to input blink counts and using the button

// Array of LED pins
#define MY_HW
#ifdef MY_HW
byte ledPins [] = { 10, 11, 12, 13 };
#else
byte ledPins [] = {2, 4, 5, 12, 13, 14, 15, 16};
#endif

const int Nled = sizeof(ledPins);

enum { Off = HIGH, On = LOW };

// Arrays to store the blink counts for each LED across 3 cycles
int blinkCountsCycle1 [8] = { 1, 2, 3, 4 };
int blinkCountsCycle2 [8] = { 0, 2, 0, 2 };
int blinkCountsCycle3 [8] = { 1, 1, 4, 1 };


// -----------------------------------------------------------------------------
void blink (
    int *ledCnts )
{
    int  cnt = 0;
    bool flag;
    do { 
        flag = false;
        for (int n = 0; n < Nled; n++)  {
            if (cnt < ledCnts [n])  {
                digitalWrite (ledPins [n], On);
                flag = true;
            }
            else
                digitalWrite (ledPins [n], Off);
        }
        delay (500);
        for (int n = 0; n < Nled; n++)              // all off
            digitalWrite (ledPins [n], Off);
        delay (500);

        cnt++;
    } while (flag);
}

// -----------------------------------------------------------------------------
void loop ()
{
    for (int cycle = 0; cycle < 3; cycle++)  {
        switch (cycle)  {
        case 0:
            blink ( blinkCountsCycle1);
            break;
        case 1:
            blink ( blinkCountsCycle2);
            break;
        case 2:
            blink ( blinkCountsCycle3);
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (115200);
    for (int i = 0; i < Nled; i++) {
        pinMode (ledPins [i], OUTPUT);
    }
}

Thank you for your answer. However, I need the button. It did not affect the outcome of the code, I tried the code without the button already.
Also, I want to be able to change the number of blinks without changing the code. I tried your code and it only blinked the 4th and 5th led (not in sequence btw).
You can check the video I made to see what I want to achieve. It has a problem with how the code reads the input in series or something about it.

Thanks, but I meant

First print the results of taking all that input.

That is to say in setup() write some code that outputs the contents of the arrays you've just asked for from the user. Use three for loops.

And/or…

Skip the user input stuff, and supply the data ahead of time so you don't need the user input.

int blinkCountsCycle1[8] = {2, 3, 4, 5, 6, 7, 8, 9};
int blinkCountsCycle2[8] = {3, 2, 3, 2, 1, 2, 1, 2};
int blinkCountsCycle3[8] = {5, 4, 3, 2, 5, 4, 3, 2};

Or whatever.

Speed debugging up by shortening those eternal delays in the actual blinking. I used 50 milliseconds, maybe a bit too fast to count, but you've printed the count and we can, I hope, trust for loops.

Speed debugging by reducing the number 8.

Crude but effective

# define EIGHT 3

at the top of your sketch, then use EIGHT everywhere you now literally do 8. in the loops.

Or call it something inoffensive

# define NLEDS 3    // 8 later, life too short 

Things will go faster, especially when you turn user input back on.

a7

1 Like

Back in the lab I took all my advice.

This is reduced to just three LEDs (# define EIGHT 3) , and uses the initialised arrays from #16, not the user input, which I just commented out.

Blink settings for all 3 cycles.
2 3 4 
3 2 3 
5 4 3 
Starting Cycle 1:
LED 1 will blink 2 times.
LED 2 will blink 3 times.
LED 3 will blink 4 times.
Blinking LED 1 for 2 times.
Blinking LED 2 for 3 times.
Blinking LED 3 for 4 times.
did.
Starting Cycle 2:
LED 1 will blink 3 times.
LED 2 will blink 2 times.
LED 3 will blink 3 times.
Blinking LED 1 for 3 times.
Blinking LED 2 for 2 times.
Blinking LED 3 for 3 times.
did.
Starting Cycle 3:
LED 1 will blink 5 times.
LED 2 will blink 4 times.
LED 3 will blink 3 times.
Blinking LED 1 for 5 times.
Blinking LED 2 for 4 times.
Blinking LED 3 for 3 times.
did.
Starting Cycle 1:
LED 1 will blink 2 times.
LED 2 will blink 3 times.
LED 3 will blink 4 times.
Blinking LED 1 for 2 times.
Blinking LED 2 for 3 times.
Blinking LED 3 for 4 times.
did.
Starting Cycle 2:

The observed number of blinks agreed with the claimed number of blinks.


A classic case of GIGO?

If you are using pointers gratuitously, I suggest dropping back to however you would do it without. If your teach is making you use pointers, I guess this is what you come up with, although if she were vague about it, there are better ways to use them for the problem description. Some maybe even rivalng doing without.

So again curious. It is foolish to fail at some algorithm and think it will be easier to get right by coding at it in a more difficult manner.

a7

1 Like

Thank you for your advice. I don't think a pointer would work either, I was just trying to see if it would change anything. The way you do it is actually almost the same as my old method. And yes, my professor did ask if I could do it the other way around then I could get more points for my project.

TBC I made no other changes to your code, so your pointer stuff and blinking works. You could go a bit further with that and make a more compact (less repetitive) expression of your algorithm but you seem to have hit the mark of passing an array using a pointer.

What does not work is something I haven't, and can't make myself look into: the user input stuff.

Which is why you should (always) check and double check any user input processes.

I don't use parseInt or any of those serial input functions, so I can't help you with what I think is the problem area. I learned how to do without, besides almost never using input like that in projects.

a7

still unclear what the purpose of the button is. is it for input or possibly control of when/which cycle to use?

did you notice which LEDs were being used (i tested on my hardware)

still unclear what you're trying to do

the code i posted demonstrated how a pointer can be used to avoid having separate code for each blink cycle array

Here's a variation uses an array as a parameter. I cannot test this from under the umbrella, but it should be close

void blinkLEDs(int blinkCounts[]) {
  for (int i = 0; i < 8; i++) 
    for (int j = 0; j < blinkCounts[i]; j++) {
      digitalWrite(ledPins[i], HIGH);  // Turn the LED on
      delay(500);                      // Wait for 500 milliseconds
      digitalWrite(ledPins[i], LOW);   // Turn the LED off
      delay(500);                      // Wait for 500 milliseconds
    }
  }
}

and call it like

  blinkLEDs(blinkCountsCycle1);

But… any time you see variables that are different only in name by use of an appended digit or letter, like blinkCountsCycle1, blinkCountsCycle2 and blinkCountsCycle3, you should think of using an array, viz:

int blinkCountsCycle[3][8];

Now blinkCountsCycle[i] is an array of 8 int integers, which can be passed to that function by index

  blinkLEDs(blinkCountsCycle[i]);  // blink out the numbers at index i

So all these

        if (cycleCounter == 1) {
          Serial.println("Starting Cycle 1:");
          blinkCounts = blinkCountsCycle1;  // Point to Cycle 1's blink counts
        } 

would end up in one code section

        Serial.print("Starting Cycle ");
        Serial.println(cycleCounter);
        blinkLEDs(blinkCountsCycle[cycleCounter]);    

This is the power of arrays, and shows the intimate relationship in C/C++ between arrays and pointers… your original function, unchanged, I think, would work here as well. As I said, I cannot test it, I may have missed a small detail.

The idea is that passed a pointer, the receiving function has no idea whether it was an array you named explicitly, or a row of an array of two dimensions.

A very good exposition of these concepts is to be found in the classic The C Programming Language by Kernighan and Richie , Chapter 5. It's a bit terse, but stick with it, or any other source you find, as mastery of these concepts is essential for things yet to come.

HTH

a7

1 Like