[SORTED] - Novice question - Changing pin number in sketch

Hello there.

I've been sitting for hours now trying to figure out how to do this within coding and tried to look at other examples of code to learn or figure out but the explanations I have found haven't quite gotten me to an understand of how to achieve this. What I want to do (just getting back into Arduino with some silly projects as challenges) is to turn on one LED in a set of 10 whilst switching off the previous one. The logic:

Program starts
All LED OFF
digitalRead button "momentary button"
When button reads HIGH AND led1 = 0
led1 ON "it must stay on"
When button reads HIGH and led1 = 1 "its ON"
led1 OFF and led2 ON
When button reads HIGH and led1=0, do nothing,
When button reads HIGH and led2=1
led2 OFF and led3 ON

What I am thinking is using a led condition statement to compare the digitalRead with the LED array - the led condition statement will hold the index number of which LED is ON. The if statement will then find that index number of the ON LED, turning off that led and turning on the next led in that array. Then put the index number of the LED that was just turn ON in the led condition statement.

I know I can do this with a shift register, but I'd like to learn how to do this without a shiftregister using basically 10 pins as output, changing between the pins within the sketch.

I have looked at the example of setting up a LED array which will then make a chase light - but I cannot figure out how to adapt the code to not check on time but check a digitalRead. Make sense?

Any help will be greatly appreciated - even a sketch that already does it. Next I'll learn how to do it with a shift register.

What I am thinking is using a led condition statement to compare the digitalRead with the LED array - the led condition statement will hold the index number of which LED is ON. The if statement will then find that index number of the ON LED, turning off that led and turning on the next led in that array. Then put the index number of the LED that was just turn ON in the led condition statement.

This seems overly complicated. It takes next to no time to turn all 10 LED pins off, whether they were on or not. Just turn them all off, then turn the appropriate one on.

Maybe you want to look up my blinkenlight projects http://www.blinkenlight.net. My pages contain lots of simple (and not so simple) examples on how to blink LEDs.

PaulS:

What I am thinking is using a led condition statement to compare the digitalRead with the LED array - the led condition statement will hold the index number of which LED is ON. The if statement will then find that index number of the ON LED, turning off that led and turning on the next led in that array. Then put the index number of the LED that was just turn ON in the led condition statement.

This seems overly complicated. It takes next to no time to turn all 10 LED pins off, whether they were on or not. Just turn them all off, then turn the appropriate one on.

Interesting thought....didn't think about that. How will I then keep track of which LED was on? The same led condition statement I suppose....thanks PaulS.

@Udo Klein. Thank you for the link to your Blinken light project, will read eagerly and learn. 8)

How will I then keep track of which LED was on?

Why do you need to?

for(byte b=0; b<10; b++)
{
   digitalWrite(ledPin[b], LOW);
}

will turn off every pin defined in the array, without caring whether the pin was on, off, or out to lunch.

If you really have a reason to care, use an array of booleans. Set the proper position in the array to true when you turn a pin on, and set it to false when you turn the pin off. This way can be error prone, unless you twiddle the array only, then set the pin state based on the array.

PaulS:

How will I then keep track of which LED was on?

Why do you need to?

for(byte b=0; b<10; b++)

{
   digitalWrite(ledPin[b], LOW);
}



will turn off every pin defined in the array, without caring whether the pin was on, off, or out to lunch.

If you really have a reason to care, use an array of booleans. Set the proper position in the array to true when you turn a pin on, and set it to false when you turn the pin off. This way can be error prone, unless you twiddle the array only, then set the pin state based on the array.

Hey PaulS. That bit I have done regarding switching off the LED's, however at the moment I'm struggling switching on each LED after the other in the array. I have done the LED array chase effect tutorial before but now using the button to switch on each LED one after the other instead - I feel stupid again, just like when I picked up Arduino a year ago for the first time - one needs to do this at least once a week to keep the motions flowing in the brain.

Thanks for the help.

Well there we go. It does what I want it to do in a crude way for now. What I want to do now is remove the delay(500) somehow. I want the button to be read, but when the condition is reached, the read will stop until the button is released - but for now I used the delay function.

What does it do?
All 10 LED's are LOW when you start the system. When I press the button (momentary button) the first LED in the array is set to HIGH. When I press the button again, the next LED is set to HIGH. However, what also happens is all the LED conditions are set to LOW before the next LED in the array is set to HIGH.

What I want to add to it now as well is direction so that either the array starts from the beginning, or it moves backwards, switching each LED to LOW in sequence.

Then I can see about doing this with a shift register.

Thank you for the assistance thus far, I hope I can ask for more on this thread for this project concept line.

byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
int buttonPin = 2;
int x=0;

void setup()
{
                              //Here we setup the pins and there uses. First we
                              //set the buttonPin as an input, next we set that pin
                              //as HIGH cause we will read the pin to register
                              //a LOW signal. Next we use a For loop to set 
                              //all the ledPin's as output
  
  pinMode(buttonPin,INPUT);
  digitalWrite(buttonPin,HIGH);
  for(int x=0; x<10; x++)
  {
    pinMode(ledPin[x],OUTPUT);
  }
}

void loop()
                              //we start the loop by reading the state of the button
{
 buttonState=digitalRead(buttonPin);  
   
                              //now we will initiate the if function that will check the state of the buttonPin
                              //if the buttonPins' state is LOW then the led switching program will run.
                              //First we switch off all the LED's in the array
   if(buttonState==LOW)
   {
     for(int x=0; x<10; x++)
      {
        digitalWrite(ledPin[x],LOW);
                              //Now we switch on the relative LED. If x=0 (first index number) then its pin 3
      }
     digitalWrite(ledPin[x],HIGH);
                              //Now we change the value or x to the next in the array with simple math
     x=x+1;
                              //We delay the function otherwise it will switch on all the LED cause of the processing
                              //speed of the microcontroller. As long as I am pressing the button the INPUT state will
                              //qualify the LOW condition and the program runs again. I can run through the LED array
                              //by just pressing and holding the button.
     delay(500);
    }
}

Look at the blink without delay example. Basically what you need to do is separate the action required (turn all the pins off, then turn one back on) from when to perform the action (is it time to do something?).

PaulS:
Look at the blink without delay example. Basically what you need to do is separate the action required (turn all the pins off, then turn one back on) from when to perform the action (is it time to do something?).

I've looked at the code to get an understanding of how it works logically and I have a few questions:

The "previousMillis" variable is set to "0" in the beginning. Then, in the "void loop" previousMillis is deducted from currentMillis and compared to the interval time of 1000. Right, simple: 1001millis has passed, minus 0 = 1001milliseconds which is larger than interval. So then we go into the condition checking: is the LED ON or OFF. If OFF, switch it ON, if ON, switch it OFF.

However just before that, we made previousMillis equal to currentMillis (in code: previousMillis = currentMillis) and currentMillis was measured to be 1001, meaning previousMillis now has the value of 1001. When the loop starts again and it deducts previousMillis from currentMillis, does it take the new value of 1001 or the original value of "0"? If it takes the original value of "0" then the code makes sense, however I was of the understanding that previousMillis now has the new assigned value until you change it again sometime? Meaning currentMillis of 1001 minus the new previousMillis value of 1001 equals 0 and that is not larger than the interval. The loop runs again and now currentMillis equals 1002, then you get the difference of 1. Need a better understanding of what happens to the value of the variable when you assigned it a different value as before void setup.

P.S. Hope that explanation makes sense.

The code looks like this:

 unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval)
  {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // Do something
  }

The first time through the loop function, currentMillis will be a very small value. currentMillis - 0 will still be a small value, so nothing happens. After 999 milliseconds, previosMillis is still 0, and nothing has happened. Finally, currentMillis takes on a value of 1001. 1001 - 0 is 1001, which is greater than 1000. So, previousMillis is assigned the value in currentMillis. That is previousMillis is assigned the value of 1001. The rest of the body of the if statement is also executed, and loop ends.

Next time, currentMillis is assigned a value of 1001. 1001 - 1001 = 0, so nothing happens. 999 milliseconds later, currentMillis is 2000. 2000 - 1001 = 999, so nothing happens. A millisecond later, currentMillis is 2001. 2001 - 1001 = 1000, so nothing happens. A millisecond later, currentMillis is 2002. 2002 - 1001 = 1001, which is greater than 1000, so previousMillis is assigned the value in currentMillis, 2002, the rest of the code in the if statement is executed, and the process repeats.

Now, one thing is obvious. That is, the if statement should be using >=, not >, so that the action occurs when currentMillis is 1000, 2000, 3000, etc., rather than 1001, 2002, 3003, etc.

If it takes the original value of "0" then the code makes sense

It does not, and if you read what I wrote above, it should be obvious why not.

PaulS, that does make sense but it also raises a question :roll_eyes: . Do I understand correctly when I say, currentMillis is a variable, and its value will be increasing as long as the program is running? It starts at 0 and then increases, when the LED has blinked 3 times its value will be 5000 (3 ON's and 2 OFF's). The absolute values don't bother me, its the question of memory? If the memory has a cap, won't the program, if run long enough, stop running cause currentMillis doesn't have any more space to store the new number? Or am I being an idiot - which you may state cause I have been many many times before in more things than programming microcontrollers? XD

If the memory has a cap, won't the program, if run long enough, stop running cause currentMillis doesn't have any more space to store the new number?

No. There is a fixed number of bits reserved to hold the value returned by millis() - 32 bits or 4 bytes. What will happen, after 49+ days, is that the value in the variable will reach 0xFFFF. One millisecond later, the value will be 0x0000, due to rollover.

But, because of the way data is stored, currentMillis - previousMillis will be performed correctly, even when previousMillis is 0xFFFE and currentMillis is 0x0002.

Or am I being an idiot

Of course not. You are seriously trying to understand a complex topic.

Thank you so much PaulS. When I read that line

"No. There is a fixed number of bits reserved to hold the value returned by millis() - 32 bits or 4 bytes. What will happen, after 49+ days, is that the value in the variable will reach 0xFFFF. One millisecond later, the value will be 0x0000, due to rollover."

I got the warm funny feeling, the same kinda feeling when you realize the potential that lies before you. Microcontrollers are cooooool! Just need to understand them more.

Appreciate the help PaulS. On to the next bit in my project - turning the array around, plus removing the delay on the switch - then on to shift registers.