4

My code:

// Pin 13 has a LED connected on most Arduino boards.
// give it a name:
int led = 13;
const int buttonPin = 2;

// the setup routine runs once when you press reset:
void setup() {
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

// the loop routine runs over and over again forever:
void loop() 
{
  bool buttonState = digitalRead(buttonPin);
  while (buttonState == LOW)
  {
   digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
   delay(1000);               // wait for a second
   digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
   delay(1000);               // wait for a second
   }
 if (buttonState == HIGH){
   digitalWrite(led, LOW);}
  }

The last line of code:

if (buttonState == HIGH){
   digitalWrite(led, LOW);}

Is what I tried using to turn the led off from its continuous blinking state. So the point of this project is to make the led's blink with a button, then turn them off with the same button. This has been bugging me for hours and I've done all the work but can't seem to get this last part done. What is being done wrong here?

EDITED for clarification:

The intention is that with each push of the button the LED is toggled between a blinking and a no-blinking state. The state of the LED is not driven by the level (pushed/unpushed) of the button itself, but by the pushing action itself.

3
  • What do you want to happen? Press once to start blinking and again to stop blinking? Blink while the button is pressed? Something else?
    – Mark Smith
    Feb 27, 2017 at 8:28
  • Yes the first thing you said. Press once to start blinking and again to stop blinking
    – Utsav
    Feb 27, 2017 at 8:39
  • can i know how to have a button to trigger blinking of led and another button is to stop the blinking ?
    – XingSheng
    Jul 3, 2019 at 14:33

5 Answers 5

3

It makes sense to make switch-testing fairly independent of blink-control. That's done in the following code, which turns blinking on or off each time a button is pressed. With this code, between button presses the LED either is off or it blinks at about a 2 Hz rate.

enum { LED=13, ButtonPin=2, BounceMS=50, BlinkMS=256 };
unsigned long buttonAt;
bool blinky, bouncy, buttonState;

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(ButtonPin, INPUT_PULLUP);
  blinky = bouncy = buttonState = false;
  buttonAt = millis();
}

void loop() {
  // Detect button changes
  if (bouncy) {
    if (millis() - buttonAt > BounceMS)
      bouncy = false;       // End of debounce period
  } else {
    if (digitalRead(ButtonPin) != buttonState) {
      buttonState = digitalRead(ButtonPin);
      buttonAt = millis();
      bouncy = true;        // Start debounce period
      if (buttonState) {    // Was button just pressed?
        blinky = !blinky;   // Toggle blink-state
      }
    }
  }
  // Control light-blinking
  if (blinky) {
    // Turn LED on for BlinkMS ms, then off for same 
    digitalWrite(LED, (millis() - buttonAt)%(2*BlinkMS) < BlinkMS);
  } else {
    digitalWrite(LED, LOW);
  }
}
3

As the OP explained in a comment, what he is trying to achieve is to have a button alternate between blink and off, not having the button to be pressed to shut down the led.

This can be done in this way:

bool prevButtonState;
bool ledBlinking;

void loop() 
{
    bool buttonState = digitalRead(buttonPin);

    if (prevButtonState && !buttonState)
    { // Pressing edge: there is a transition between high and low
        ledBlinking = !ledBlinking;
    }
    prevButtonState = buttonState;

    if (ledBlinking)
    {
        digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(1000);               // wait for a second
        digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
        delay(1000);               // wait for a second
    }
    else
    {
        digitalWrite(led, LOW);
    }
}

This, however, leads to a very long time between successive checks of the button (since there is a 2s delay between cycles). You can solve this using the millis function:

bool prevButtonState;
bool ledBlinking;
unsigned long prevMillis;

void loop() 
{
    bool buttonState = digitalRead(buttonPin);

    if (prevButtonState && !buttonState)
    { // Pressing edge: there is a transition between high and low
        ledBlinking = !ledBlinking;

        prevMillis = millis() - 1000; // Force a check
    }
    prevButtonState = buttonState;

    if (ledBlinking)
    {
        if ((millis() - prevMillis) >= 1000)
        {
            prevMillis += 1000;
            digitalWrite(led, !digitalRead(led));
        }
    }
    else
    {
        digitalWrite(led, LOW);
    }
}

Next there is the debounce problem, but this becomes OT. Suggestion: use the Bounce2 library to manage the button if you experience bounces

2
  • No, I do want to use the button to swith the led off.. Like a switch and a light bulb.. the only difference is that the lighbulb blinks.
    – Utsav
    Feb 27, 2017 at 10:30
  • In this comment you say that you want one push -> led blink, another push -> led off. This is what my code does. Your code is keep pressed -> led blink, leave unpressed -> led off
    – frarugi87
    Feb 27, 2017 at 10:36
3

EDITED

The Arduino loop() function makes the use of a while loop redundant in this case. Even worse: the way you've implemented that while loop prevents buttonState from being updated, thus getting stuck in the loop.

What you actually need is to use timers to blink the LED, and a 2-state machine driven by HIGH to LOW button transitions.

Try this instead:

#include "Timer.h"

// Pin 13 has a LED connected on most Arduino boards.
// give it a name:
const int led = 13;
const int buttonPin = 2;

// declare state variables as global
bool buttonState = LOW;
bool buttonState_prev = LOW;
bool toggleBlinking;
bool blinkState;

// declare a Timer object so blinking can be done without loosing button presses
Timer timer_b;
int blink_id;

// the setup routine runs once when you press reset:
void setup() {
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);

  // initial state: toggle led each 1000 ms
  blink_id = timer_b.oscillate(led, 1000, HIGH);
  blinkState = true;
  toggleBlinking = false;
}

// the loop routine runs over and over again forever:
void loop() {
  // Update the timer (required)
  timer_b.update();

  // check if button has been pressed (HIGH to LOW),
  // then debounce it and raise toggle flag
  buttonState = digitalRead(buttonPin);
  if ((buttonState != buttonState_prev) && (buttonState_prev == HIGH)) {
    // simple button debounce (confirm press after some ms)
    delay (50);
    buttonState = digitalRead(buttonPin);
    if (buttonState != buttonState_prev) toggleBlinking = true;
  }

  // keep current LED state unless the button has been pushed
  switch (blinkState) {
    case true:
      // if button has been pushed, stop blinking and change LED state
      if (toggleBlinking == true) {
        timer_b.stop (blink_id);
        blinkState = false;
      }
      break;
    case false:
      digitalWrite(led, LOW);
      // if button has been pushed, start blinking and change LED state
      if (toggleBlinking == true) {
        blink_id = timer_b.oscillate(led, 1000, HIGH);
        blinkState = true;
      }
      break;
  }

  buttonState_prev = buttonState;
  toggleBlinking = false;
}

NOTE: You'll need to install the Timer.h library. I'VE TESTED MY CODE AND IT WORKS.

7
  • That's not a deadlock, but otherwise good :-)
    – Mark Smith
    Feb 27, 2017 at 9:22
  • You're right, thanks. I'll edit the answer. Feb 27, 2017 at 9:23
  • Your code just makes the Led's blink once... I understand what you are trying to do here but I wanted so that the led's blink continuously once the button is pressed. But, when the button is pressed again, they stop blinking. Like I said, This makes the led's only blink once then stop blinking without having the button pressed...
    – Utsav
    Feb 27, 2017 at 9:40
  • OK, I'll see your using a pull-up. I'll check it. Feb 27, 2017 at 9:56
  • Yes sorry, I should've given more details :/
    – Utsav
    Feb 27, 2017 at 9:57
2
while (buttonState == LOW)

gets you trapped in an endless loop, once buttonState == LOW.
You have to poll buttonState inside this loop if you ever want to get out of it.
However this is not enough for your purpose. What you really need is a (boolean) variable - let's name it blinking, for instance - which changes its value each time you see a falling edge on buttonState.
Then check this variable's value in an if/else clause like this:

if (blinking == true)
{
   digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
   delay(1000);               // wait for a second
   digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
   delay(1000);               // wait for a second
}
else
{
   digitalWrite(led, LOW);}
}

But with this you will soon face the next problem: The polling speed for your button is very low, because of the very long delays, which keep you about 2 seconds inside the if clause.
Try setting up the blink cycle using a PWM, as described here
Then use the if clause above to set the PWM duty to 50%, and the else clause to set it to 0%.

6
  • So you want me to put If (buttonState == HIGH) inside the while loop?
    – Utsav
    Feb 27, 2017 at 8:41
  • @Utsav That won't help. The buttonState doesn't reflects current state of pin. The digitalRead does.
    – KIIV
    Feb 27, 2017 at 8:49
  • @KIIV so I put another bool buttonState = digitalRead(buttonPin); inside the while loop and then I also cut and pasted the If statement inside the while loop. They still do not produce the outcome :/ i'm sorry I couldn't really implement what you wanted...
    – Utsav
    Feb 27, 2017 at 9:14
  • @Utsav no, you want to update buttonState, not to create new one and shadow the other one from the outside of scope.
    – KIIV
    Feb 27, 2017 at 9:27
  • When I create this new bool variable called 'blinking', do I set the variable with a number? like: bool blinking = 0; or do something else? I am quite confused..
    – Utsav
    Feb 27, 2017 at 9:54
1

try this:

if (key_pressed()) digitalWrite(LED_PIN, (digitalRead(LED_PIN)==ON)?OFF:ON);
else digitalWrite(LED_PIN, OFF);

define ON/OFF based on your led connection.

Edit.

If you want the button too change the mode of led blinking, try this.

    if (btn_pressed())                  //if btn falling edge detected
        btn_status ^= 1;                //flip the last bit. btn_status += 1; works as well
    if (btn_status & 0x01) led1_flp();  //flip led1
    else led1_off();                    //otherwise, turn off led1

    //flip led2
    IO_FLP(LED_PORT, LED2);

the logic is fairly simple: if the button is pressed (active low), toggle btn_status. if btn_status is 1, blink the led1.

basically, press the button, led starts to blink; press the button the 2nd time, led stops to blink;

led2 is always blinking, to show concurrency of the code.

here it goes in action.

enter image description here

the code is written for a pic but basically runs on any mcu.

Not the answer you're looking for? Browse other questions tagged or ask your own question.