Adding an on/off button with an existing sketch

I've finally gotten my 11 year-old son interested in the Arduino I bought him a few months back for his birthday because has a great application--a project in school to build a model of a nebula. We've been building one out of fuzzy stuff and inserting LED's. We've successfully made four LED randomly flicker using the sketch below.

We also have a push button attached we've used in previous projects to turn LED's on and off after each push. Our problem is we're now trying to add the on/off button part of the first sketch to the random flickering sketch and it's not going well. Any help would be appreciated. I'm going to post three sketches. First, the twinkle sketch, which works great:

/*
 * randomly flickering LEDs
 */

int ledPin[] = {
  13, 9, 10, 11};              // pwm pins only
int ledState[5];                 // last state of each led
long randNumber;

void setup() {
  for (int i=0; i<=4; i++){      // set each led pin as an output
    pinMode(ledPin[i], OUTPUT);
  }
  randomSeed(analogRead(0));     // seed the rnd generator with noise from unused pin

  for (int i=0; i<=4; i++){      // init each led with a random value
    ledState[i] = random(20, 201);
  }
}

void loop(){
  for (int i=0; i<=4; i++){                  // for each led:
    analogWrite(ledPin[i], ledState[i]);     // set the pwm value of that pin determined previously
    randNumber = random(-40, 41);            // generate new random number and add that to the current value
    ledState[i] += randNumber;               // that range can be tweaked to change the intensity of the flickering
    if (ledState[i] > 200) {                 // clamp the limits of the pwm values so it remains within
      ledState[i] = 200;                     // a pleasing range as well as the pwm range
    }
    if (ledState[i] < 10) {
      ledState[i] = 10;
    }
  }
  delay(100);    // the delay between changes
}

Here's the button sketch we've also gotten to work:

/* 
 Debounce
 
 Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
 press), the output pin is toggled from LOW to HIGH or HIGH to LOW.  There's
 a minimum delay between toggles to debounce the circuit (i.e. to ignore
 noise).  
 
 The circuit:
 * LED attached from pin 13 to ground
 * pushbutton attached from pin 2 to +5V
 * 10K resistor attached from pin 2 to ground
 
 * Note: On most Arduino boards, there is already an LED on the board
 connected to pin 13, so you don't need any extra components for this example.
 
 
 created 21 November 2006
 by David A. Mellis
 modified 3 Jul 2009
 by Limor Fried
 
 
 http://www.arduino.cc/en/Tutorial/Debounce
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPingreen =  13;      // the number of the LED pin
const int ledPinred =  9;      // the number of the LED pin
const int ledPinblue =  11;      // the number of the LED pin
const int ledPinyellow =  10;      // the number of the LED pin

// Variables will change:
int ledState = LOW;         // the current state of the output pin
int lastButtonState = LOW;   // the previous reading from the input pin
int lastReading= LOW;

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPingreen, OUTPUT);
  pinMode(ledPinred, OUTPUT);
  pinMode(ledPinblue, OUTPUT);
  pinMode(ledPinyellow, OUTPUT);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastReading) {
    // reset the debouncing timer
    lastDebounceTime = millis();
    // save the reading.  Next time through the loop,
    // it'll be lastReading:
    lastReading = reading;
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so accept the button state change:
  
    // toggle the LED if the state of the button changes from LOW to HIGH:
    if (lastButtonState == LOW && reading == HIGH) {
      if (ledState == HIGH) {
        ledState = LOW;
      } else {
        ledState = HIGH;
      }
      digitalWrite(ledPingreen, ledState);
      digitalWrite(ledPinred, ledState);
      digitalWrite(ledPinblue, ledState);
      digitalWrite(ledPinyellow, ledState);
    }
    lastButtonState = reading;
  }
}

I seem to be exceeding the 9500 character limit, so I'll put in the next post the code after unsuccessfully trying to insert the button code and put it into the random flickering code.

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

Here's the code after unsuccessfully trying to insert the button code and put it into the random flickering code:

/*
 * randomly flickering LEDs
 */
const int buttonPin = 2;     // the number of the pushbutton pin
int ledPin[] = {
  13, 9, 10, 11};              // pwm pins only
int ledState[5];                 // last state of each led
long randNumber;

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
    pinMode(buttonPin, INPUT);
  for (int i=0; i<=4; i++){      // set each led pin as an output
    pinMode(ledPin[i], OUTPUT);
  }
  randomSeed(analogRead(0));     // seed the rnd generator with noise from unused pin

  for (int i=0; i<=4; i++){      // init each led with a random value
    ledState[i] = random(20, 201);
  }
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastReading) {
    // reset the debouncing timer
    lastDebounceTime = millis();
    // save the reading.  Next time through the loop,
    // it'll be lastReading:
    lastReading = reading;
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so accept the button state change:
  
    // toggle the LED if the state of the button changes from LOW to HIGH:
    if (lastButtonState == LOW && reading == HIGH) {
      if (ledState == HIGH) {
        ledState = LOW;
      } else {
        ledState = HIGH;
      }
      digitalWrite(ledPingreen, ledState);
      digitalWrite(ledPinred, ledState);
      digitalWrite(ledPinblue, ledState);
      digitalWrite(ledPinyellow, ledState);
    }
    lastButtonState = reading;
  }
}


void loop(){
  for (int i=0; i<=4; i++){                  // for each led:
    analogWrite(ledPin[i], ledState[i]);     // set the pwm value of that pin determined previously
    randNumber = random(-40, 41);            // generate new random number and add that to the current value
    ledState[i] += randNumber;               // that range can be tweaked to change the intensity of the flickering
    if (ledState[i] > 200) {                 // clamp the limits of the pwm values so it remains within
      ledState[i] = 200;                     // a pleasing range as well as the pwm range
    }
    if (ledState[i] < 10) {
      ledState[i] = 10;
    }
  }
  delay(100);    // the delay between changes
}

Here are the errors we're getting. My son is only 11 and I'm 51. We're both new to this so we're both struggling. I'm assuming we're not accounting for the difference between the way the button turns on the LED's from LOW to HIGH in the button sketch and the way the random flickering is handled in the other sketch. Any advice would be appreciated. Thanks.

random_flickering_with_button.cpp: In function 'void loop()':
random_flickering_with_button:35: error: 'lastReading' was not declared in this scope
random_flickering_with_button:48: error: 'lastButtonState' was not declared in this scope
random_flickering_with_button:49: error: ISO C++ forbids comparison between pointer and integer
random_flickering_with_button:50: error: incompatible types in assignment of 'int' to 'int [5]'
random_flickering_with_button:52: error: incompatible types in assignment of 'int' to 'int [5]'
random_flickering_with_button:54: error: 'ledPingreen' was not declared in this scope
random_flickering_with_button:55: error: 'ledPinred' was not declared in this scope
random_flickering_with_button:56: error: 'ledPinblue' was not declared in this scope
random_flickering_with_button:57: error: 'ledPinyellow' was not declared in this scope
random_flickering_with_button:59: error: 'lastButtonState' was not declared in this scope
random_flickering_with_button.cpp: In function 'void loop()':
random_flickering_with_button:64: error: redefinition of 'void loop()'
random_flickering_with_button:26: error: 'void loop()' previously defined here

Moderator edit:
</mark> <mark>[code]</mark> <mark>

</mark> <mark>[/code]</mark> <mark>
tags added.

I did some editing

/*
 * randomly flickering LEDs
 */
const int buttonPin = 2;     // the number of the pushbutton pin
int ledPin[] = {
  13, 9, 10, 11};              // pwm pins only
int ledState[5];                 // last state of each led
int lastReading = 0; // -----> added this as you forgot to initialize it
int lastButtonState = LOW; // -----> added this as you forgot to initialize it

long randNumber;

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
    pinMode(buttonPin, INPUT);
  for (int i=0; i<=4; i++){      // set each led pin as an output
    pinMode(ledPin[i], OUTPUT); // -----> changed from ledPin to ledPin[i]
  }
  randomSeed(analogRead(0));     // seed the rnd generator with noise from unused pin

  for (int i=0; i<=4; i++){      // init each led with a random value
    ledState[i] = random(20, 201); // -----> changed from ledPin to ledPin[i]
  }
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastReading) {
    // reset the debouncing timer
    lastDebounceTime = millis();
    // save the reading.  Next time through the loop,
    // it'll be lastReading:
    lastReading = reading;
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so accept the button state change:
  
    // toggle the LED if the state of the button changes from LOW to HIGH:
    if (lastButtonState == LOW && reading == HIGH) {
      if (ledState[1] == HIGH) { //which one do you mean? I just randomly chose ledState[1] ---> you probably want a for loop here
        ledState[1] = LOW;
      } else {
        ledState[1] = HIGH;
      }
      //digitalWrite(ledPingreen, ledState); //declare the variables
      //digitalWrite(ledPinred, ledState);
      //digitalWrite(ledPinblue, ledState);
      //digitalWrite(ledPinyellow, ledState);
    }
    lastButtonState = reading;
  }

// you cant have 2 "loop" functions. put everything in one
  for (int i=0; i<=4; i++){                  // for each led:
    analogWrite(ledPin[i], ledState[i]);     // set the pwm value of that pin determined previously -----> its an ARRAY tell it which index you need
    randNumber = random(-40, 41);            // generate new random number and add that to the current value
    ledState[i] += randNumber;               // that range can be tweaked to change the intensity of the flickering
    if (ledState[i] > 200) {                 // clamp the limits of the pwm values so it remains within
      ledState[i] = 200;                     // a pleasing range as well as the pwm range
    }
    if (ledState[i] < 10) {
      ledState[i] = 10;
    }
  }
  delay(100);    // the delay between changes
}

basically there are three problems

a) you need to declare each and every variable. you need to assign a value to it before you use it
b) you cant assume that the compiler knows which index of an array you are interested in. if you use a value from an array dont forget to add the index ( ... this thing: ). Make sure you understand arrays
c) arduino can only have on "loop" function. put everything there.
your code should compile fine, the way I edited it. I did not check it for functionality though.
Cheers
p.

read this. its for java, but the principle applies to c as well.

and take a quick look at this: http://arduino.cc/en/Reference/Array

Thanks fkeel. I appreciate you cleaning up my code and the explanations. You're right, it does compile without an error. The button still doesn't work, as I'm sure you know, so we're moving through the clues you provided trying to figure out the solution. This may be too beyond us at this point and we're running out of time.

If we can't get the code fixed in time, I'm wondering if there's an alternative way for a button to control this. Perhaps just put it between the battery and the Arduino?

Thanks for your help. If you think it should be working with the code you fixed, please let us know and we'll try to make sure all the pins are in the right places, etc.

Thanks again!

to be honest, I did not look at the functionality of what it does.

I think you might be better off writing code from scratch.

If you tell me what exactly you want the code to do I can give you some more pointers.

ok, I think I know what you want to do. I played with it for a bit. This will work, assuming the button code is still ok.

make sure you understand the code though.

const int buttonPin = 2;     // the number of the pushbutton pin
int ledPin[] = {
  13, 9, 10, 11};              // pwm pins only
int ledState[5];                 // last state of each led
int lastReading = 0; // -----> added this as you forgot to initialize it
int lastButtonState = LOW; // -----> added this as you forgot to initialize it

///////////////////////////
// this is a variable which decides whether to blinklights or not
boolean blinkLEDs = true; 
///////////////////////////

long randNumber;
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  for (int i=0; i<=4; i++){      // set each led pin as an output
    pinMode(ledPin[i], OUTPUT); // -----> changed from ledPin to ledPin[i]
  }
  randomSeed(analogRead(0));     // seed the rnd generator with noise from unused pin

  for (int i=0; i<=4; i++){      // init each led with a random value
    ledState[i] = random(20, 201); // -----> changed from ledPin to ledPin[i]
  }
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);
  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastReading) {
    // reset the debouncing timer
    lastDebounceTime = millis();
    // save the reading.  Next time through the loop,
    // it'll be lastReading:
    lastReading = reading;
  } 
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so accept the button state change:

    // toggle the LED if the state of the button changes from LOW to HIGH:
    if (lastButtonState == LOW && reading == HIGH) {  
      ////////////////////////
      ///// if blinkLEDs is true, the following code will set it to false
      ////// if blinkLEDS is flase it will be set to true.
      ////// so everytime you push the button, it will switch state
      ///////////////////////
      if (blinkLEDs == true){
        blinkLEDS = false;
      }
      else {
        blinkLEDs = true;
      }
    }
    lastButtonState = reading;
  }

  ////////////
  //if blinkLEDs is true, awesomeNebulaEffect will happen
  if (blinkLEDs == true) {
    doAwesomeNebulaEffect(); // this calls the function "doAwseomNebulaEffect"
  }
  ///////////////
  // THis is where the loop ends
}


//////////////////////
// this is a function. its called from within the loop, but the code is outside of the loop
// here we declare the function which makes the nabula effect
void doAwesomeNebulaEffect () {
  for (int i=0; i<=4; i++){                  // for each led:
    analogWrite(ledPin[i], ledState[i]);     // set the pwm value of that pin determined previously -----> its an ARRAY tell it which index you need
    randNumber = random(-40, 41);            // generate new random number and add that to the current value
    ledState[i] += randNumber;               // that range can be tweaked to change the intensity of the flickering
    if (ledState[i] > 200) {                 // clamp the limits of the pwm values so it remains within
      ledState[i] = 200;                     // a pleasing range as well as the pwm range
    }
    if (ledState[i] < 10) {
      ledState[i] = 10;
    }
  }




}

Thanks! My son is very excited and appreciative. We'll give it a try. I'll make sure I take him through the code.

Hmmm. We're getting an error:

sketch_dec14b.cpp: In function 'void loop()':
sketch_dec14b:58: error: 'blinkLEDS' was not declared in this scope

If it helps, the button code was taken from the second sketch I posted and worked great with in that one. When I tried to move it over to the twinkle one, that's where the problems seemed to start.

Sorry, I really wasn't looking for someone to write the code for us, but under the circumstances, I can't tell you how much we appreciate it!

bobmcinnis:
sketch_dec14b:58: error: 'blinkLEDS' was not declared in this scope

Note the case difference between the error message and what's declared.

what Arrch said :smiley:

also: I did not test it. it should work in principle, but it probably wont as I am a horrible coder (I am sloppy with the details, so chances are high there are more little bugs in there.) also. I never tested it.

so the principle is correct. but you need to work on the details ... and in order to do that, you need to understand the principle... so in the end... its still down to you to write your code :smiley:

also, you want to understand it, so you can edit it later.

I just found it easyer to do it, than to explain how to do it.

Aha! We noticed the uppercase "S" and it worked! THANKS SO MUCH!!!!

One more question. Upon the button press, the lights stop twinkling but still remain on. Would there happen to be an easy change to a variable to make them turn off altogether instead of stopping twinkling?

Honestly, I think he's happy the way it is, but if there's a variable we can change in the code to have the button turn the lights off, we'd love to give it a try?

Thanks!

edit: after the if statement where you call the nebula function, use digitalWrite to set all pins to LOW if blinkLEDs is false

post some videos :smiley:

Thank you!!! This'll help us explore the code. We really appreciate all your help.

Thanks for that last edit. It worked with

if (blinkLEDs == false)
{
digitalWrite(ledPin[1] ,LOW);
digitalWrite(ledPin[2] ,LOW);
digitalWrite(ledPin[3] ,LOW);
digitalWrite(ledPin[0] ,LOW);

Yay! We'll definitely post a video :slight_smile:

fkeel,

We completed the nebula project a couple of nights ago and yesterday my 11-year-old son showed it to his class. No grade yet, but my guess is he'll get an A. Certainly the kids and the teacher gasped when he pushed the button. Thanks so much for the help. Here's a YouTube video of it as promised:

Thanks again for all the help. He was so happy with it and jumpstarted his interest in learning the code. We're actually thinking we'll make a larger one to put in the fireplace. Much cooler than a fire!

Bob

Nice :slight_smile:

Thanks for sharing

Thank you for the help. We couldn't have done it without you!

I just wanted you to know my son got a 100 for his grade on this project. I appreciate your help on this. It looks like he's getting hooked on Arduino!

Bob