2

So i have been experimenting with TinkerCad, waiting for my arduino to arrive. Currently I have a loop of ledlights and i want to start and stop the loop by pressing a button.

Currently i am able to start my loop via the button, but not able to stop the loop with the same button press. Does this have something to do with the debouncing?

const int button = 10;
const int led1 = 8;
const int led2 = 4;
const int led3 = 3;
const int timedelay = 250;

boolean buttonstate = false;  

void setup()
  {

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(button, INPUT);
}

void loop() {

if(digitalRead(button)==HIGH)  // check if button is pushed
   buttonstate = !buttonstate;    //reverse buttonstate value

   if(buttonstate==true)
  {  
    digitalWrite(led1, HIGH);
    delay(timedelay); 
    digitalWrite(led1, LOW);
    delay(timedelay); 
    digitalWrite(led2, HIGH);
    delay(timedelay);
    digitalWrite(led2, LOW);
    delay(timedelay);
    digitalWrite(led3, HIGH);
    delay(timedelay);
    digitalWrite(led2, HIGH);
    delay(timedelay);
    digitalWrite(led1, HIGH); 
    delay(timedelay);
    digitalWrite(led3, LOW);
    delay(timedelay);
    digitalWrite(led2, LOW);
    delay(timedelay);
    digitalWrite(led1, LOW); 
    delay(timedelay);
    digitalWrite(led1, HIGH); }
   else {
        digitalWrite(led1, HIGH);
  }     
}

My circuit setup:

Hello world project

EDIT:

I have adjusted my code, replaced the delay with millis and looking for a change in button state. Still looking for a way to adjust interval_led1 at the end of the loop to make sick ledlight sequences.

const int led1 = 13;
const int led2 = 8;
const int led3 = 5;
const int button = 10;
int ledState_led1 = LOW;             // ledState used to set the LED
int ledState_led2 = LOW;
int ledState_led3 = LOW;


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

long interval_led1 = 500;           // interval at which to blink (milliseconds)
long interval_led2 = 600;
long interval_led3 = 700;

boolean buttonstate = false;


void setup() {

pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(button, INPUT);

}





void loop() {
   // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long currentMillis_led1 = millis();
  unsigned long currentMillis_led2 = millis();
  unsigned long currentMillis_led3 = millis();

  bool current_state = digitalRead(button);
  bool prev_buttonstate= false;

if(current_state==HIGH && current_state != prev_buttonstate)
{  
   buttonstate = !buttonstate;    //reverse buttonstate value
}
prev_buttonstate = current_state;



if(buttonstate==true)
    if (currentMillis_led1 - previousMillis_led1 >= interval_led1) {
    previousMillis_led1 = currentMillis_led1;
    if (ledState_led1 == LOW) {
      ledState_led1 = HIGH;
    } else {
      ledState_led1 = LOW;
    }
    digitalWrite(led1, ledState_led1);
    }

if(buttonstate==true)    
    if (currentMillis_led2 - previousMillis_led2 >= interval_led2) {
    previousMillis_led2 = currentMillis_led2;
    if (ledState_led2 == LOW) {
      ledState_led2 = HIGH;
    } else {
      ledState_led2 = LOW;
    }
    digitalWrite(led2, ledState_led2);
    }

if(buttonstate==true)
    if (currentMillis_led3 - previousMillis_led3 >= interval_led3) {
    previousMillis_led3 = currentMillis_led3;
    if (ledState_led3 == LOW) {
      ledState_led3 = HIGH;
    } else {
      ledState_led3 = LOW;
    }
    digitalWrite(led3, ledState_led3);
    }
}
6
  • Under function loop, put a curly braces after the first first if statement and close where loop() ends. Commented Apr 23, 2020 at 13:59
  • @seccpur, Could you edit my code with the brackets? I have just tried what you said, but i can't get it to work. Sadly i have 0 arduino/c++ experience just a bit of python Commented Apr 23, 2020 at 14:19
  • 1
    Your problem is that the button only gets read at the top of loop. Then for quite some time the code is busy doing those delay calls. Nothing happens during a delay. It just sits on that line waiting for a while. If you want to be able to react to the button at the same time then you can’t use delay to handle the timing. Google “Blink without delay” and do a bit of reading. You need to use the millis() clock for timing instead. Commented Apr 23, 2020 at 14:49
  • Also your circuit is wrong. The resistors on the amber and green LEDs do nothing, because the red wire shorts straight to the LED, as the wires have basically zero resistance. Amazing that neither has burnt out. Your red LED resistor is connected correctly. Model that same layout for the other two. Commented Apr 23, 2020 at 14:59
  • 1
    I knew something was wrong, i saw the message coming up. But wasn't focused on this problem yet. Nothing burned out because TinkerCad is a fully digital platform. There are no physical parts. Commented Apr 23, 2020 at 15:16

2 Answers 2

1

Here your two cases are very different in terms of delay: if(buttonstate==true) is very long to execute because of the multiple delay instructions in it, else is very fast because there is no delay in it.

When buttonstate==True and you press the button (as Delta_G said, the delay() prevent the test to happen most of the time and you should use millis() for instance to do the timing, but let say you are lucky and you pass your first if statement), so buttonstate will flip to false.

As there is no delay in your else instruction, the board will come back in no time to your initial if, which, unfortunately will still be true as you are not fast enough to press this button for only a few microseconds. So buttonstate will flip again and your code will fall in your if(buttonstate==true) which is very long, allowing you to release the button in time before the if(digitalRead(button)==HIGH) is reevaluated.

The solution (apart from timing issues raised by @Delta_G, and hardware issues raised by @TomServo) is to seek for changes of the button state. You thus have to compare to the previous value it had. You can declare another boolean boolean prev_buttonstate = false; and could do something like:

bool current_state = digitalRead(button);
if(current_state==HIGH && current_state != prev_buttonstate)
{  
   buttonstate = !buttonstate;    //reverse buttonstate value
}
prev_buttonstate = current_state;

Hope it helps!

Sign up to request clarification or add additional context in comments.

Comments

1

Your circuit is correct. If you keep pressing the button little longer, the condition will continue to hold good and the state falsely resets again.

To simulate the toggling effect, use a bool variable like so:. You reset the variable when the signal goes low.

  void loop() {
       static bool ready = true;
       if(digitalRead(button)==HIGH && ready)
       {
           ready = false;
            buttonstate = !buttonstate; //reverse buttonstate value
            if(buttonstate){
                  digitalWrite(led1, HIGH);
                  delay(timedelay); 
                  digitalWrite(led1, LOW);
                  delay(timedelay); 
                  /* Etc*/ }
             else {
                  digitalWrite(led1, HIGH);
            }
     }
     else 
     if(digitalRead(button)==LOW && !ready)
     {
         ready = true;
     }     
 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.