Using a button for lamp pattern change with millis!

Okay so i started with Arduino not to long ago so please point out if i am doing things out of order!

Hey btw..

So i did this code in one assignment but i now need to use it so that i make two new patters upon the click of a button that needs to use millis.
The code below is making 12 lamps blink in one nice patter. However i need to make it so that when i push a button, the pinout won't matter, i can change between three different patterns.

I need to have millis and i need to have 12 lamps! I figured that i would need to use if else however i am so unsure that i fear not doing anything good with it, but i have managed.
I would appreciate any tips that anyone could give me, even if they are plain insults to my noob code.
Thanks!

int ledPin1 = 1;
int ledPin2 = 2;
int ledPin3 = 3;
int ledPin4 = 4;
int ledPin5 = 5;
int ledPin6 = 6;
int ledPin7 = 7;
int ledPin8 = 8;
int ledPin9 = 9;
int ledPin10 = 10;
int ledPin11= 11;
int ledPin12 = 12;
// Variables will change:
int ledState = LOW; // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
long previousMillis = 0; // will store last time LED was updated

// constants won't change:
const long interval = 1000; // interval at which to blink (milliseconds)

void setup() {
// set the digital pin as output:
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
pinMode(ledPin4, OUTPUT);
pinMode(ledPin5, OUTPUT);
pinMode(ledPin6, OUTPUT);
pinMode(ledPin7, OUTPUT);
pinMode(ledPin8, OUTPUT);
pinMode(ledPin9, OUTPUT);
pinMode(ledPin10, OUTPUT);
pinMode(ledPin11, OUTPUT);
pinMode(ledPin12, OUTPUT);

}

void loop() {

unsigned long currentMillis = millis();

if (currentMillis - previousMillis >= interval) {

previousMillis = currentMillis;

if (ledState == LOW) {
ledState = HIGH;
} else
{
ledState = LOW;
}

digitalWrite(ledPin1, HIGH);
delay(100);
digitalWrite(ledPin2, LOW);
delay(100);
digitalWrite(ledPin3, HIGH);
delay(100);
digitalWrite(ledPin4, LOW);
delay(100);
digitalWrite(ledPin5, HIGH);
delay(100);
digitalWrite(ledPin6, LOW);
delay(100);
digitalWrite(ledPin7, HIGH);
delay(100);
digitalWrite(ledPin8, LOW);
delay(100);
digitalWrite(ledPin9, HIGH);
delay(100);
digitalWrite(ledPin10, LOW);
delay(100);
digitalWrite(ledPin11, HIGH);
delay(100);
digitalWrite(ledPin12, LOW);
delay(100);
digitalWrite(ledPin1, HIGH);
delay(100);
digitalWrite(ledPin2, LOW);
delay(100);
digitalWrite(ledPin3, HIGH);
delay(100);
digitalWrite(ledPin4, LOW);
delay(100);
digitalWrite(ledPin5, HIGH);
delay(100);
digitalWrite(ledPin6, LOW);
delay(100);
digitalWrite(ledPin7, HIGH);
delay(100);
digitalWrite(ledPin8, LOW);
delay(100);
digitalWrite(ledPin9, HIGH);
delay(100);
digitalWrite(ledPin10, LOW);
delay(100);
digitalWrite(ledPin11, HIGH);
delay(100);
digitalWrite(ledPin12, LOW);
delay(100);
}
}

You need to wire up a button and just put some print statements so that you can prove you are seeing when the button is pressed.

Regarding your existing pattern, what you are doing seems strange.
You run through all twelve LEDs putting alternate LEDs High and LOW, which is fine but then you write exactly the same pattern to them a second time e.g.
you write
digitalWrite(ledPin1, HIGH);
then later you write
digitalWrite(ledPin1, HIGH);

You also have a variable ledState whose value you change but never use anywhere.

Finally you have 24 delay(100) statements which is 2400 milliseconds of delay.
This is longer than your 'interval' so each time round the loop currentMillis - previousMillis is always going to be bigger than interval.

Before you start adding new patterns change the existing code so that you use an array to hold the pattern and a for loop to turn the leds on or off. In other words instead of having 12 lines turning individual leds on/off you should have just one line within for loop turning all the leds on/off depending upon the values in the pattern array.

Once that is working you can add an extra dimension to your array and easily store several patterns and swap between them.

The extra sum of HIGH/LOW was to alternate.. it was a code that i made that i wanted to change into something else.

I have gotten this far yet i still need to use array which i have no clue of using as of right now...

int buttonPin = 0;
unsigned long previousMillis = 0;

int ledPin1 = 1;
int ledPin2 = 2;
int ledPin3 = 3;
int ledPin4 = 4;
int ledPin5 = 5;
int ledPin6 = 6;
int ledPin7 = 7;
int ledPin8 = 8;
int ledPin9 = 9;
int ledPin10 = 10;
int ledPin11 = 11;
int ledPin12 = 12;

long interval = 1000;

int buttonState = 0;

void setup() {

pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
pinMode(buttonPin, INPUT);
}

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

if (currentMillis - previousMillis >= interval) {

previousMillis = currentMillis;

buttonState = digitalRead(buttonPin);

if (buttonState == 0) {

digitalWrite(ledPin1, HIGH);

} else if
(buttonState == 1)

digitalWrite(ledPin2, HIGH);
} else {

(buttonState == 2);

digitalWrite(ledPin3, HIGH);

}

}

//Only using three lamps atm because i want to use array..

Nope. Think about what you want to do.
Don't try to use the button to control your leds yet, just use print statements to show you can read the state of the button.

What does using an array have to do with only using three leds, using an array makes using more led easier.

Here is clue for how you could use a for loop to improve your setup function;

void setup()
{    
    for(int pin=1;pin<=12;++pin)
    {
        pinMode(pin, OUTPUT);
    }
    pinMode(buttonPin, INPUT);
}

Now lookup arrays and figure out how to store the patterns you want in an array.

Okay so i've remade it all.

This time trying to read and try to learn from what you wrote.

It seem ok but the thing is that i am unsure of it will light all 12 up or not, if it will do anything and if it's actually connected to the button... sigh. I don't have a board atm so guess that i'll have to try it out later. Will also try to add more then two ways of patterns.. in other words on or off which i believe it is on as or right now.

buttonState and if else statements are also gone.. wonder if it actually will do anything at all..

int pins[]= {1,2,3,4,5,6,7,8,9,10,11,12};
int buttonState = 0;
int buttonPin = 0;
unsigned long previousMillis = 0;
long interval = 1000;

void setup()

{
for (int pins; pins<=12;++pins)
{
pinMode(pins, OUTPUT);

}
pinMode(buttonPin, INPUT);

}

void loop()
{

long MS = millis();
if(MS - previousMillis >= interval) {
previousMillis = MS;
buttonPin = digitalRead(buttonPin);
}

for(int i=0; i<i;++i){
digitalWrite(pins*, HIGH);*

  • delay(200);*
  • }*
  • for(int i=0; i<i;++i){*
    _ digitalWrite(pins*, LOW);_
    _
    }_
    _
    }_
    _
    [/td]_
    _
    [/tr]_
    _
    [/table]*_

Rather than re-writing your code, I'll just give you a couple of suggestions and some things to contemplate... Mostly stuff for you to think about...

You can't read a pushbutton during the delay() so you need to replace all of the delays with millis() timers. (Most of the time your loop is "paused" waiting for a delay.)

You need some variables to keep track the on/off state of each LED. You can make 12 variables, or an array. Or, the "best way" would be to use an int where each of the 16-bits represents one of the LEDs (and just ignoring 4-bits).*

Make a "tight loop" that checks the current time and reads the button. Include some if-statements so you only "do something" when the time is up, or when you push a button.

I really think you need to write a [u]function()[/u] to handle the LED sequence. A function is sort-of like a little "sub-program" that goes-off an does something and then comes back to the main loop().

Functions keep the code in your main loop "cleaner" because the if-statement simply calls (runs) the function whenever the if-condition is true. delay() and millis() are actually functions, but you'd have to dig-into the Arduino IDE code to find the code for them. The code for you custom functions will usually be in your INO file, although it's possible to write you own "library" which would be a separate file.


  • Using the bits is something you can play with now, or you can just think about it for the future... The basic concept is pretty simple but most people aren't used to working with binary numbers. Everything in the computer is stored in binary so this stuff is "easy for the computer". :wink:

...So let's say we have a byte (an 8-bit variable) named LEDstate. And, let's say we have 8 LEDs. Each bit represents the state of one LED like this:

LEDstate = 00000000 All LEDs off
LEDstate = 00000001 First LED on
LEDstate = 00000010 Second LED on
LEDstate = 00000011 First & 2nd LEDs on

Of course if we print-out the variable (in the "usual way") we'd see the regular decimal value and we'd see that this is a simple counter:

LEDstate = 00000000 = Decimal 0
LEDstate = 00000001 = Decimal 1
LEDstate = 00000010 = Decimal 2
LEDstate = 00000011 = Decimal 3

A counter makes a lousy LED effect, but with bitwise operations we can read, write, invert individual bits, we can [u]bit shift[/u] (either direction) which makes an easy chase-effect so you can do this:

00000001
00000010
00000100
00001000... etc.

Or things like this:
00000011
00000110
00001100
00011000... etc.

Or, there is something called a Johnson counter. I'll just show you a 4-bit Johnson counter:
0000
0001
0011
0111
1111
1110
1100
1000
0000... etc.

So... Using bit shifting (or other bitwise manipulation) it takes very-little code in a loop to do LED patterns. And, one variable can hold the state of all LEDs.

It takes a couple more lines of code to set-up the starting pattern, and usually you want to loop the most-significant bit back-round to the least significant bit for a continuous chase pattern, etc. (In the case of the Johnson counter you invert before sending the MSB back-round to the LSB.)

And, it takes a little more code to "read the bits" and write-out to the individual LEDs, but that code can be used over-and-over. Again, that should probably a function.

I have an effect with one light (or one "channel") connected to each output pin like you, and I have another effect with 48 serially-addressed LEDs (controlled with 3 just output-pins). In both cases I use the same bit-pattern method, with a different output-functions for the different connections. (The 48-LED data is stored in two type-long variables... Actually, it's an audio-activated "stereo" effect so it's handy to store the data/state in 2-different variables.)

When we're playing around with bits, most of the time we don't care about the decimal value. We are just looking at "bit patterns" and "bit states", but it's important to understand that it's just an ordinary variable that we are looking-at and manipulating in a different way.

...And just to make things more "interesting", most programmers work with hexadecimal rather than binary. It's a lot easier (for humans) to read a 4-digit hex number than a 16-bit binary number. And, you can learn to convert between hex and binary in your head, so the programmer can see a hex number (of any size) and immediatley visualize the bit pattern. It takes a calculator to convert between decimal and binary because each nibble (4-bits) converts exactly to one hex digit.

I'm a little rusty, but I remember some of the "easy" patterns/conversions like hex 5 & A. So for example:

0000 0000 (binary) = 0 (decimal) = 0 (hex)
0101 0101 (binary) = 85 (decimal) = 55 (hex)
1010 1010 (binary) = 170 (decimal) = AA (hex)
1111 1111 (binary) = 255 (decimal) = FF (hex)
1111 0101 (binary) = 245 (decimal) = F5 (hex)

Or with 32-bits:
0000 0000 0000 0000 (binary) = 0 (decimal) = 0 (hex)
0101 0101 0101 0101 (binary) = 21,845 (decimal) = 5555 (hex)
1010 1010 1010 1010 (binary) = 43,690 (decimal) = AAAA (hex)
1111 1111 1111 1111 (binary) = 65,535 (decimal) = FFFF (hex)
1111 1111 1010 1010 (binary) = 65,450 (decimal) = FFAA (hex)

I added spaces in the binary numbers to make it more readable and to help show how the 4-bit pattern gets converted to (or from) a hex digit. For the decimal calculations I used the Windows calculator in Programmer mode. (The calculator shows binary, decimal, hex, and octal.)

The thing is that no matter what i still need to use millis. I would be happy if i didn't have to but i do...

Lexianlex:
The thing is that no matter what i still need to use millis. I would be happy if i didn't have to but i do...

You don't have to use millis, but it is often better than using delay.
If you want your sketch to do one thing at a time in a sequence then delay can be fine.
If you want your sketch to seem to do things simultaneously or in parallel then you cannot use delay.

What you do need to do is to look carefully at your code, think if what you have written really does what you want, and don't be afraid of scattering lots of print statements through it so that you can see what it is actually doing.

What did you think this would actually do
for(int i=0; i<i;++i)

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

You are currently using the "Quote" device instead of the </> device.

Thanks.. Tom... :slight_smile:

@Lexianlex you are obviously a beginner. You might find the book "The C Programming Language" by Kernigan and Ritchie helpful to understand the language and its syntax. It is available online;
http://www.dipmat.univpm.it/~demeio/public/the_c_programming_language_2.pdf

The Arduino IDE uses C++ but C is esentially a subset.

For your program I don't want to write it for you, what would be the point in that, by try starting from this and adding some print statements into it;

void setup()
{
  for (int pin; pin<=12;++pins)
  {
    pinMode(pin, OUTPUT);
  }
}

void loop()
{
    // Turn on each LED one at a time with a short delay between each
    for(int pin=1; pin<=12;++i)
    {
        digitalWrite(pin, HIGH);
        delay(200);
    }

    // After all the LEDs are turned on wait for a few seconds
    delay(5000);

    // Turn off all the LEDs quickly
    for(int pin=1; pin<=12;++pin)
    {
        digitalWrite(pin, LOW);
    }

    // Wait for a couple of seconds before repeating the loop
    delay(2000);
}

So far this is what i've come up with.
I still cannot figure out how to change from delay on evey button push to millis. So every delays has to become a millis instead so when i push the button again it will not keep on the delay from the other pattern but it will go over to the next one instantly.

int pins[]= {2,3,4,5,6,7,8,9,10,11,12,13};
int Leds = 12; 
int oldButtonState = HIGH; 
int buttonPin = 1; 
unsigned long previousMillis = 0; 
long interval = 1000;
int Pattern = 0;
int counter = 0;

void setup() 
{ 

  
  for (int pins; pins<=13;++pins)
  {
    pinMode(pins, OUTPUT);
  }
  
    pinMode(buttonPin, INPUT_PULLUP); 

}

void loop() 
{

    byte buttonState = digitalRead(buttonPin);

    long MS = millis();

    if(buttonState != oldButtonState)
    {
        
        Pattern++;        
        delay(10);
        oldButtonState == buttonState;
    }


    if(Pattern==1)
    {
        
        if(MS - previousMillis >= interval) 
        {
            previousMillis = MS;
            buttonState = digitalRead(buttonPin); 
        }


        for(int i=0; i<Leds; i++)
        {
            if(buttonState != digitalRead(buttonPin)) {
                buttonState = digitalRead(buttonPin);
                break;
            }
            digitalWrite(pins[i], HIGH);
            delay(50);
        }

        for(int i=0; i<Leds; i++)
        {
            digitalWrite(pins[i], LOW);
        }
        }   
        else if (Pattern==2) {
    
        if(MS - previousMillis >= interval) 
        {
            previousMillis = MS;
            buttonState = digitalRead(buttonPin); 
        }


        for(int i=3; i<Leds; i++)
        {
            if(buttonState != digitalRead(buttonPin)) {
                buttonState = digitalRead(buttonPin);
                break;
            }
            digitalWrite(pins[i], HIGH);
            delay(50);
        }

        for(int i=0; i<Leds; i++)
        {
            digitalWrite(pins[i], LOW);
        }
        }        
        else (Pattern==3); {
    
        if(MS - previousMillis >= interval) 
        {
            previousMillis = MS;
            buttonState = digitalRead(buttonPin); 
        }


        for(int i=5; i<Leds; i++)
        {
            if(buttonState != digitalRead(buttonPin)) {
                buttonState = digitalRead(buttonPin);
                break;
            }
            digitalWrite(pins[i], HIGH);
            delay(50);
        }

        for(int i=0; i<Leds; i++)
        {
            digitalWrite(pins[i], LOW);
        }        }        }

If you clean up that mess of brackets and indentation you will see much better what's going on. Now it's impossible to follow.

For your millis() problem, you probably need to implement some form of finite state machine where each state is a next step in your pattern, and the millis() timing governs the stepping through the states.

Finally, beware of using pins 0 and 1 for buttons or so, as those are in use for the Serial communications as well. Better use A0-A5 first. Pin 13 is also preferably avoided as it is connected to the internal LED (on the Uno and derivatives at least, which you appear to be using).

Forget about millis for now. Just take the code I posted add in some print statements and make sure you understand how that code works.

You can then add an array (I can help) so that instead of just tuning on all the leds you can set a pattern.
Then another dimension can be added so that you have two or more patterns.
Then a button can be added to swap between patterns.

Just build your code up one step at a time.
At the moment you are trying to do too much without understanding what is going on.