Toggle swtich + BlinkWithoutDelay

For makers who have purchased an Adafruit Starter Pack, get help with the tutorials here!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
skyline513
 
Posts: 9
Joined: Mon May 20, 2013 1:49 pm

Toggle swtich + BlinkWithoutDelay

Post by skyline513 »

Hello World!

First post. A short introduction and request for suggestions. I bought the starter pack and lots of extras a short time ago to get back into electronics and to complete a bicycle project. I've built may high-end audio components in years past (mic pre-amps, compressor/limiters, etc.) and have completely re-wired cars to support large AV systems, so I'm pretty grounded in the physical realm but I'm falling short on the less tangible coding side of things. I took a couple programming classes in college but the professor's third (or fourth) language was English. That's not inherently bad but it resulted in more time spent learning her accent and syntax than time spent understanding if/else, etc. I'll close this intro by thanking everyone at Adafruit and this community- I've learned more in two weeks of lurking than I did in two quarters of higher education. And I didn't have to go into debt! :)

The question I'm looking for suggestions on:
I understand the coding to blink an LED without using the delay function. I understand the coding to use a momentary switch (in this case, the Adafruit single key membrane switch) as a push on / push off toggle switch. But what are some ways to combine the two without confusing Arduino? The physical electronics part of me says "Forget it...use a 555 timer and use the simple switch code." But I know I can do it with coding. The goal is to start out with the LED off, and the push button toggles the blinking on and off.

OK, a second question popped up:
With the membrane switch, is it possible to have the integrated LED blink at the same time as the blinking LED referred to in the above question? I like the visual indication of the button being pressed, but additional feedback indicating the other LED is blinking would be neat.

THANK YOU!

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: Toggle swtich + BlinkWithoutDelay

Post by adafruit_support_mike »

If you understand blinkWithoutDelay, you're most of the way there. You just need to put it inside another conditional and use the switch to control a "should I be blinking?" flag:

Code: Select all

boolean BLINK = false;
byte    SWITCH = 0;

void loop () {
    if ( justPressedButton() ) {
        BLINK = (BLINK) ? false : true;
    }
    if (BLINK) {
        //  blinkWithoutDelay code goes here
    }
}

skyline513
 
Posts: 9
Joined: Mon May 20, 2013 1:49 pm

Re: Toggle swtich + BlinkWithoutDelay

Post by skyline513 »

Thank you, Mike. I may have taken the example too literally. The code checks out OK but the button won't change the LED state. In your example, is ' justPressedButton() ' the toggle function which reads the input from pin 2? Also, are we using 'blink' as a conditional, or is it referring to an actual function/class? I noticed in the IDE "boolean" and "blink" are both orange...

I'll post up the new code I wrote and see how far off I was

Code: Select all

const int inPin = 2;	//the number of the input pin
const int ledPin = 13;	//the number of the output pin

boolean blink = false;	//not sure what this is for!

int ledState = LOW;	//initial state of the output pin, sets 'ledPin'
int buttonReading;	//current reading from input
int previous = LOW;	//initial reading of the input pin

long time = 0;			//the last time the output pin was toggled
long debounce = 200;		//debounce time
long previousMillis = 0;	//variable to store when LED was last updated
long interval = 100;		//interval at which the LED will blink



//**********************************************************

void setup()
{
pinMode (ledPin, OUTPUT);
pinMode (inPin, INPUT);
}



//**********************************************************

void loop()
{
	buttonReading = digitalRead(inPin);
	if ((buttonReading = HIGH && previous == LOW && millis() - time > debounce) )
	{
		blink = (blink) ? false : true;
	}
		if (blink)
		{		
			unsigned long currentMillis = millis();
			if (currentMillis - previousMillis > interval)
			{
				previousMillis = millis();
				if (ledState == LOW)
					ledState = HIGH;
				else
					ledState = LOW;
				digitalWrite (ledPin, ledState);
			}
		}
	time = millis();
	previous = buttonReading;

}

User avatar
adafruit_support_bill
 
Posts: 88087
Joined: Sat Feb 07, 2009 10:11 am

Re: Toggle swtich + BlinkWithoutDelay

Post by adafruit_support_bill »

Code: Select all

   if ((buttonReading = HIGH && previous == LOW && millis() - time > debounce) )
This line is a problem. First off, operator precedence in C++ can be confusing. With that many operators in one expression, it is wise to use parentheses to make the intended order of operations clear (to both you and the compiler).

Secondly, the first operator in that expression "=" is probably not the one you intended to use. That operator has the lowest precedence and will assign the value of the rest of the expression to 'buttonReading'. What you most likely intended to use was the compare operator "==".

Code: Select all

   if ((buttonReading == HIGH) && (previous == LOW) && ((millis() - time) > debounce) )

skyline513
 
Posts: 9
Joined: Mon May 20, 2013 1:49 pm

Re: Toggle swtich + BlinkWithoutDelay

Post by skyline513 »

You are correct, Bill. The '=' was intended to be comparison operator per the switch tutorial. Silly typo. It has been corrected in the sketch but still didn't get the intended effect on the LED. Nerts. I'll mull it over for a couple days before posting up again.

skyline513
 
Posts: 9
Joined: Mon May 20, 2013 1:49 pm

Re: Toggle swtich + BlinkWithoutDelay

Post by skyline513 »

Now that I understand how edge detection works, I'm getting much closer. At first pushing the button didn't change the LED state but then as soon as I added the debounce code, it started to come together. As for the blink rate, that's thrown together. I didn't want to add the BlinkWithoutDelay code until I nailed the toggle.

The first problem I noticed early on with this new method was buttonPushCounter started off at 0, for obvious reasons. But that caused the LED to start flashing right away, which isn't ideal for the intended application. Changing the initial value of buttonPushCounter to 1 kept the LED off until the button was pressed, thereby giving an even number and satisfying "buttonPushCounter % 2 == 0" towards the end.

For whatever reason, though, I'm getting "random" button presses that result in the LED state staying HIGH. I performed three test sets of 101 button presses and recorded which button press the HIGH state occurred instead of the LOW state. Keep in mind the buttonPushCounter now starts at 1, not 0:

Set 1 - 7 25 35 39 41 43 45 61 67 69 75 91 93 95 97 99
Set 2 - 15 23 53 61 79
Set 3 - 9 17 23 31 41 45 47 51 59 67 85 91 93 95 97 99

Thoughts?

The code is based largely on Tom Igoe's Button State Change Detection tutorial.

Code: Select all

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 1;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
long time = 0;
long debounce = 50;        // debounce time

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
}


void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if ((buttonState != lastButtonState) && (millis() - time > debounce)) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // went from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("off");
    }
    
    time = millis();
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;

  if (buttonPushCounter % 2 == 0) {
         if ((millis () & 250) < 50)
          digitalWrite(13, HIGH);
         else
          digitalWrite(13, LOW);
  }
 
}

skyline513
 
Posts: 9
Joined: Mon May 20, 2013 1:49 pm

Re: Toggle swtich + BlinkWithoutDelay

Post by skyline513 »

Here's the code with the blinkWithoutDelay worked in. Still getting "random" HIGH states on button push instead of LOW or blinking...

Code: Select all

// Constants won't change:
const int  buttonPin = 2;    // the pin the pushbutton is attached to
const int ledPin = 13;       // the pin the LED is attached to

// Variables will change:
int buttonPushCounter = 1; // counter for the number of button presses
int buttonState = 0;           // current state of the button
int ledState = LOW;           // variable used to control state of LED
int lastButtonState = 0;      // previous state of the button
long previousMillis = 0;      // where we'll store time when LED was last updated
long time = 0;                   //
long interval = 100;           // interval at which LED blinks in ms
long debounce = 50;          // button debounce time

void setup() {
  pinMode(buttonPin, INPUT);      // initialize the button pin as a input:
  pinMode(ledPin, OUTPUT);        // initialize the LED as an output:
  Serial.begin(9600);                   // initialize serial communication:
}


void loop()
{
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if ((buttonState != lastButtonState) && (millis() - time > debounce)) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // went from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }
    else {
      Serial.println("off");   // if the current state is LOW then the button went from on to off:
    }
    
    time = millis();
  }

  lastButtonState = buttonState;      // save the current buttonState as the lastButtonState for next time through the loop

  if (buttonPushCounter % 2 == 0) {
         unsigned long currentMillis = millis();
         if(currentMillis - previousMillis > interval){
           previousMillis = currentMillis;
           if (ledState == LOW)
             ledState = HIGH;
           else
             ledState = LOW;
           digitalWrite(ledPin, ledState);
           }//closes if
  }//closes if
}//closes void loop

User avatar
adafruit_support_bill
 
Posts: 88087
Joined: Sat Feb 07, 2009 10:11 am

Re: Toggle swtich + BlinkWithoutDelay

Post by adafruit_support_bill »

I think you want the lastButtonState assignment to be inside the 'if'. If it is just a bounce, you don't want to treat it as a state change.

skyline513
 
Posts: 9
Joined: Mon May 20, 2013 1:49 pm

Re: Toggle swtich + BlinkWithoutDelay

Post by skyline513 »

I appreciate the idea, Bill. It's probably best from a housekeeping standpoint but I tried moving the lastButtonState assignment around and the results didn't change. I did discover what is causing the LED to stay on, though!

Of course, it wasn't random at all. Glad I put quotations around 'random' in my previous posts... After breaking down every line of code into plain English, I started to suspect the flaw was being caused by when the 'off' button press was taking place. To test this, I took the variable 'interval' and bumped it up to 1 second. This was long enough for me to react to the different states. When the program starts, the LED is dark as it should be. When you hit the momentary switch, the LED begins to flash at the 1 second interval. If you time it correctly, you can get the 'off' button press to *always* turn off the LED. Similarly, you can time your 'off' button presses to when the LED is on and *always* keep the LED lit. The program is taking whatever state the LED is currently in and freezing it, which isn't correct.

Now....how do I get the 'off' button press to actually turn the LED off regardless of it's current HIGH or LOW state?? I'm going to add an 'else' condition to the 'if (buttonPushCounter % 2 == 0)' and see what happens....

skyline513
 
Posts: 9
Joined: Mon May 20, 2013 1:49 pm

Re: Toggle swtich + BlinkWithoutDelay

Post by skyline513 »

I think I got it! The last 'else' statement was missing. Once that was added, no matter what state the LED is in, the blinkWithoutDelay function stops. Would someone mind testing functionality to verify it is working correctly??

Code: Select all

// Constants won't change:
const int  buttonPin = 2;    // the pin the pushbutton is attached to
const int ledPin = 13;       // the pin the LED is attached to

// Variables will change:
int buttonPushCounter = 1;      // counter for the number of button presses
int buttonState = 0;            // current state of the button
int ledState = LOW;             // variable used to control state of LED
int lastButtonState = 0;        // previous state of the button
long previousMillis = 0;        // where we'll store the timestamp of when LED was last updated
long timeStamp = 0;                  // timestamp
long interval = 1000;           // interval at which LED blinks in ms
long debounce = 50;             // button debounce time

void setup() {
  pinMode(buttonPin, INPUT);      // initialize the button pin as a input:
  pinMode(ledPin, OUTPUT);        // initialize the LED as an output:
  Serial.begin(9600);             // initialize serial communication:
}


void loop()
{
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if ((buttonState != lastButtonState) && (millis() - timeStamp > debounce)) {
   
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current buttonState *is* HIGH, then the button has been pressed and we need to record it
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }
    else {
      // if the current buttonState is LOW then the button was released:
      Serial.println("off");   
    }
    lastButtonState = buttonState;  // save the current buttonState as the lastButtonState for next time through the loop    
    timeStamp = millis();
  }

  if (buttonPushCounter % 2 == 0) {
      unsigned long currentMillis = millis();
         if(currentMillis - previousMillis > interval){
           previousMillis = currentMillis;
           if (ledState == LOW) {
             ledState = HIGH;
           }
           else {
             ledState = LOW;
           }
           digitalWrite(ledPin, ledState);
         }//closes if
  }//closes if
  else {
    digitalWrite (ledPin, LOW);
  }//closes else

  
  
}//closes void loop

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Starter Pack”