Recalling a led sequence

Hello! In the attached circuit, after pressing the pushbutton, leds will sequencially on and off upwards.

I used this code:

int interval = 500;

const int numLeds = 10;

const int buttonPin = 12;
int buttonState = 0;

void setup() {
  pinMode(buttonPin, INPUT);
  
  for (int thisPin = 2; thisPin <= numLeds+1; thisPin++) {
    pinMode(thisPin, OUTPUT);
  }
}

void loop() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
  	for (int thisPin = 2; thisPin <= numLeds+1; thisPin++) {
      digitalWrite(thisPin, HIGH);
      delay(interval);
      digitalWrite(thisPin, LOW);
    }
  }
}

What i want to do is that every time i press the pushbutton the new sequence would add to the previous.

Example:
Button pressed -> start light sequence -> when led number 5 is ON i press the button again -> led 1 and 6 ON -> wait interval -> led2 and 7 ON -> etc

Is it possible?
Can someone give me some pointers on how to achieve this, please?

Thanks in advance!

Yes, what you ask is possible. But there are two problems.

  1. Your for-loop containing a delay() is what is called "blocking code" because it will not allow other actions to be performed until it is finished. Other actions include testing if a button is pressed. You will need to re-write the code to remove the blocking parts. In the programming questions forum section, there is a sticky post which explains how to do this.

  2. Looking at the picture you posted, you seem to be using an Arduino simulator. In this forum, members generally use real Arduino and real circuits and many do not trust simulators. If at any time your code does not work as expected, they will probably blame the simulator and tell you to try the code on a real Arduino.

HugoFerreiraPinto:
Can someone give me some pointers on how to achieve this, please?

I'd like to help, but I read that 5 times and still don't understand what it is you want to do, sorry!

What i want to do is that every time i press the pushbutton the new sequence would add to the previous.

For how long?

You seem to be wanting a limitless number of additional to the sequence but you are very specific about what these sequences should do.

All sequences must either be generated algorithmically, or stored in memory somewhere.

Also what do you want to happen when you do not press the button? Should it cycle the length of sequence so far, should it stop on the last pattern or should it go blank?

One simple way if you are not fussed about the pattern is to use the random number generator. Use the seed function with a constant at the start of the sequence, so that the sequence is always the same, until it comes to the new extended bit of the sequence.

This is how I interpreted the OP's wish:

When a button is pressed, led #0 lights. Every 500ms, that single lit led moves on to the next position in line (#1, #2...). After led #9 has been lit for 500ms it goes out and no LEDs are lit until the next button press. This is what the sketch does now.

In the new version, the OP would like the button to be monitored continuously during the led movement. If the button is pressed again while the lit led is moving, led #0 is lit again and a second lit led follows the first down the line. And so on. Consequently, if the button is held down for ~5s, all LEDs would be lit, and if the button was released for ~5s, all LEDs would go out.

If course, I could have misinterpreted also!

Yes that is also a valid interpretation as to what he said.

As we both know one of the biggest problems with beginners is that they know what they want to happen but only put into words a very limited and incomplete sub set of what they want assuming that "everyone will know what I mean".

In industry these are called "use cases" and it is difficult to get them right when any non trivial degree of combinations of events are possible. As I have said before I have worked in access control and there was a lot of use cases about when a door should open, but as the options increased many options were not / can not be considered.

Many combination of things turned out to be simply contradictory. Like what happens with a master token when the door requires a "buddy" ( two valid tokens need to be presented ) door. It either stays as master token, in which case the door is no longer a buddy door, or the door stays a buddy door and the master token is no longer a master token. Either option destroys the concept of one of the definitions you started with.

PaulRB:

  1. Your for-loop containing a delay() is what is called "blocking code" because it will not allow other actions to be performed until it is finished. Other actions include testing if a button is pressed. You will need to re-write the code to remove the blocking parts. In the programming questions forum section, there is a sticky post which explains how to do this.

Hi and thank you for your help. Code re-wrote (poorly) without delay()... the sequence seems slugish when leds transition... still no solution for second time the pushbutton is pressed in this code. Could you give me more hints please?

unsigned long currentMillis = 0;

int ledInterval = 500;
unsigned long previousLedMillis = 0;
int ledOn = 2; //initial pin number of 1st led to be ON

const int numLeds = 10;

const int buttonPin = 12;
const int buttonInterval = 300;
unsigned long previousButtonMillis = 0;
byte buttonState = HIGH;

void setup() {
  pinMode(buttonPin, INPUT);
  
  for (int thisPin = 2; thisPin <= numLeds+1; thisPin++) {
    pinMode(thisPin, OUTPUT);
  }
}

void loop() {
  currentMillis = millis();
  readButton();
  ledSequence();
}

void readButton() {
 buttonState = HIGH;
 if (currentMillis - previousButtonMillis >= buttonInterval) {
   if (digitalRead(buttonPin) == LOW) { 
     previousButtonMillis += buttonInterval;
     buttonState = LOW;
   }
 }
}

void ledSequence(){
  if (buttonState == LOW){
    digitalWrite(ledOn, HIGH);
    if (currentMillis - previousLedMillis >= ledInterval) {
      previousLedMillis += ledInterval;
      digitalWrite(ledOn, LOW);
      ledOn++;
    }
  }
}

PaulRB:
2. Looking at the picture you posted, you seem to be using an Arduino simulator. In this forum, members generally use real Arduino and real circuits and many do not trust simulators. If at any time your code does not work as expected, they will probably blame the simulator and tell you to try the code on a real Arduino.

I have the Uno, Mega, Nano and Micro for testing purposes.

hannah_mackinlay:
I'd like to help, but I read that 5 times and still don't understand what it is you want to do, sorry!

Each time i press the pushbutton a led lit "animation" (like a one way larson scanner) should start on bottom led and end on the upmost led. If during that animation i click the pushbutton again, it should end the current animation and start a new one simultaneously.

Grumpy_Mike:
For how long?

How long i press the pushbutton? - could be instantly, but that's not what i'm searching to achieve.
How long is the sequence? till the upmost led is unlit unless we push the button again

Grumpy_Mike:
You seem to be wanting a limitless number of additional to the sequence but you are very specific about what these sequences should do.

The sequence should do exactly what it does. But i want to be able to add another sequence upon the push of a button even if there is a current sequence going on. "Add" means the example i gave: finish current sequence while adding a new one.

Grumpy_Mike:
Also what do you want to happen when you do not press the button? Should it cycle the length of sequence so far, should it stop on the last pattern or should it go blank?

Nothing happens if the button isn't pressed. Upon pressing the button for the 1st time, if we do not press the button, the sequence would end in the upper led.

Grumpy_Mike:
One simple way if you are not fussed about the pattern is to use the random number generator. Use the seed function with a constant at the start of the sequence, so that the sequence is always the same, until it comes to the new extended bit of the sequence.

I only want this pattern

PaulRB:
This is how I interpreted the OP's wish:

When a button is pressed, led #0 lights. Every 500ms, that single lit led moves on to the next position in line (#1, #2...). After led #9 has been lit for 500ms it goes out and no LEDs are lit until the next button press. This is what the sketch does now.

In the new version, the OP would like the button to be monitored continuously during the led movement. If the button is pressed again while the lit led is moving, led #0 is lit again and a second lit led follows the first down the line. And so on. Consequently, if the button is held down for ~5s, all LEDs would be lit, and if the button was released for ~5s, all LEDs would go out.

Excelent!

Grumpy_Mike:
As we both know one of the biggest problems with beginners is that they know what they want to happen but only put into words a very limited and incomplete sub set of what they want assuming that "everyone will know what I mean".

Really tried my best showcasing, tried to explain what i got, what i want, made an example... but you made some serious points on your questions wich i've made to myself in order to find a solution, so thanks!

Really tried my best showcasing, tried to explain what i got

Yes I know you have. What I was trying to illustrate is that it is hard to specify what you want. Thanks for clarifying. You will get better as time goes on but we all make this sort of mistakes so don’t feel bad.

As to your code what you need to do with that button is to not detect IF is is BEING pressed but has it JUST been pressed. So to do that you must remember in a variable the last state of the switch. Then in your if statement you must test if the last time you looked at this button is NOT the same as this time.

You can see an example of this sort of code in the IDE basic examples called state change detection. Then you can count how many times the button has been pressed.

Grumpy_Mike:
assuming that "everyone will know what I mean".

Talking of which,

HugoFerreiraPinto:
(like a one way larson scanner)

.... what's a larson scanner?

Good point, this is one for the oldies.

Knight Rider was a old TV show with a talking autonomous car. The producer of the show was Glen A. Larson. The car had a row of LEDs on the front grill of the car that ran left to right and then right to left.

For some reason this was thought to be a “thing” when the Arduino came along and it was a popular beginners project.

I was in my 20s then, and know the series. But remembering the series is no reason for anyone to know it as a "Larson scanner" though. If I was to think of it with a name I'd have thought of it as a "Kitt scanner", or "Knight Rider scanner".

Side note: I now have the theme tune buzzing round my head....

But I still can't picture what HFP is trying to do.

for (int thisPin = 2; thisPin <= numLeds+1; thisPin++) {
      digitalWrite(thisPin, HIGH);
      delay(interval);
      digitalWrite(thisPin, LOW)

This sort of code will produce a fixed pattern only, there is no simple way to extend or add anything to this.

What you need to do is to have your pattern defined in a variable with each bit in that variable representing a zero or a or one, defining the state of one LED.
An int variable type has 16 bits so is good for up to 16 LEDs.

Let’s call the pattern variable pat, to start off pat = 1
The next step in the pattern pat would equal two, the next step four then eight and so on. To move the pattern from one state to the other you simply shift the variable to the left one place using th shift left operator <<

The main loop therefore would write high or low to each LED in turn *. Then it would shift the variable one place to the left and repeat. It would do this ten times ** until the pattern reaches the top LED.

When a button press is detected two things should happen. First you reset the count up to 10 which indicates the end of displaying the pattern, and second you add another logic one in the least significant bit of your pattern variable pat. Now you can not use an equal operator as that would destroy the pattern that is already being shown so you have to add it by using the inclusive OR operator |

pat |= 1;
  • You will need an array with all the pin numbers connected to the LEDs.
    ** use a while loop

Good progress, the code without delay() looks good. This is how I would approach the next step. This code would be inserted to execute when ledInterval has elapsed:

for (int thisPin = numLeds+1; thisPin > 2; thisPin--)
  digitalWrite(thisPin, digitalRead(thisPin-1));
digitalWrite(2, LOW);

This should move all the led states on by one position and set the led #0 to off. It works because when a digital pin is set to OUTPUT, you can use digitalRead() to get the value that was previously written to it.

I don't think you need all that complex button edge detection and debouncing code in this case. You can simply set pin 2 HIGH when you see the button is pressed.

I will try both aproaches... and add a third one i thought today.

I didn´t implement so maybe it has some errors but i think it could work as well:

const bool initialMask[10] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //the first sequence when button is pushed

bool currentMask [10]; // stores current array for any time given (i think it should initialize all with zeros)

if (button){
  currentMask[] += initialMask[]; //i think i could get rid that initialMask just doing currentMask[0] = 1; right?
}

if ( time... < 500){
  for (int i = 0; i < 10; i++){
    digitalWrite(i, LOW);
  }
  for (int i = 9; i >= 0; i--){ //inverted cause i need to iterate i+1 below
    digitalWrite(i+2, currentMask[i]);  
    if (currentMask[i] == 1) {
      currentMask[i] = 0;
      currentMask[i+1] = 1; //this is below
    }
  }
}

Basically i want the led "array" to refresh (as a whole) with the virtual array every 500 ms.

edit: Reading it again and without the initialMask, this looks like PaulRB solution... that digitalWrite(thisPin, digitalRead(thisPin-1)); blew my mind!

Nevertheless i came here super confused and now i have three solutions :slight_smile: You guys are awesome!
Will try this all on Monday.
Happy Easter!