Making something happen only once when a button is held down

Hi,

Very new to programming, so apologies in advance if I'm asking something that's blindlingly obvious or has been asked many times before, or also if I haven't formatted something properly. Just trying to learn.

Basically I have a button and when that button is pressed an LED has to flash three times in quick succession and then stop. This has to happen only once, no matter if the button is pressed and released or pressed and held.
When the button is pressed and released this happens fine, but when its pressed and held the LED just keeps flashing.

I'm not sure yet how to resolve this, whether it involves using a bool or a previous state variable, or something else entirely.

This is the code I am currently using:

// set constants for trigger and output/firing pin
const int triggerPin = 2;  // button on pin 2
const int ledPin = 13; // led on pin 13
const int a = 150;  //delay time

// variable for the state of the trigger
int triggerState = 0;


void setup() {

  pinMode(triggerPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);

}

void loop() {
  // read the state of the trigger input
  triggerState = digitalRead(triggerPin);

  // check if the trigger is pressed. If it is, the triggerState is LOW
  if (triggerState == LOW) {
    //led light
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);

  } else {
    digitalWrite(ledPin, LOW);
  }


}

I'm sure this is really simple stuff that I'm asking, but like I say i'm very new to this and i'm trying to learn, so any help would be much appreciated.

Thank you :slight_smile:

Welcome to the forum

You need to detect when the button becomes pressed rather than when it is pressed
See the StateChangeDetection example in the IDE

1 Like
const int triggerPin = 2;  // button on pin 2
const int ledPin = 13; // led on pin 13
const int a = 150;  //delay time
bool triggerState = false;// variable for the state of the trigger

void setup() {
  pinMode(triggerPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (!triggerState && digitalRead(triggerPin) == LOW) {
    triggerState = true;

    //led light
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
  } else     digitalWrite(ledPin, LOW);
}

Hi @kolaha,

sure you wanted to set triggerstate to false again after the last delay(a); Otherwise it is just a "one-shot-trigger" ... :wink:

/*
  Forum: https://forum.arduino.cc/t/making-something-happen-only-once-when-a-button-is-held-down/1308686/2
  Wokwi: https://wokwi.com/projects/411030595132389377

*/

const int triggerPin = 2;  // button on pin 2
const int ledPin = 13; // led on pin 13
const int a = 150;  //delay time
bool triggerState = false;// variable for the state of the trigger

void setup() {
  pinMode(triggerPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (!triggerState && digitalRead(triggerPin) == LOW) {
    triggerState = true;

    //led light
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
    triggerState = false;
  } else     digitalWrite(ledPin, LOW);
}

See here: https://wokwi.com/projects/411030595132389377

Greetings
ec2021

1 Like

in description stay no "repeat" word. it should fire only once.
(your sketch continue blinking while button pressed, that is against requirement)

1 Like

You should be aware that the solution posted here is a "quick and dirty" solution.

As @UKHeliBob mentioned (and surely @kolaha does also!) you better have a look at

https://www.arduino.cc/en/Tutorial/BuiltInExamples/StateChangeDetection

https://arduinogetstarted.com/tutorials/arduino-button-debounce

There are simple and more sophisticated methods you can find in the web.

It is worth to study and test them!

This is a little bit more "complex" but

Measure Time between Button Presses

Good luck and have fun!
ec2021

1 Like

You are right. (I should have known that you don't do a simple mistake like that, my bad ...) :wink:

@dmm78
But let's ask the TO whether it should fire again when the button is pressed again after being released ... or does one have to reset the controller for a new action?

P.S.:

If the sketch may repeat blinking once again after the button was released first this one should do:

/*
  Forum: https://forum.arduino.cc/t/making-something-happen-only-once-when-a-button-is-held-down/1308686/2
  Wokwi: https://wokwi.com/projects/411032188691180545

*/

const int triggerPin = 2;  // button on pin 2
const int ledPin = 13; // led on pin 13
const int a = 150;  //delay time
bool triggerState = false;// variable for the state of the trigger

void setup() {
  pinMode(triggerPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (!triggerState && digitalRead(triggerPin) == LOW) {
    triggerState = true;
    //led light
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
  } else {
     digitalWrite(ledPin, LOW);
  }   
 if (triggerState && digitalRead(triggerPin)) {
  triggerState = false;
  delay(30);  // Simple debouncing
 }
}

To be tested on Wokwi:

https://wokwi.com/projects/411032188691180545

Hi,

Thanks for responding so quick.

I uploaded what you sent but I still have the same issue.

I've done a very quick, crap video to try to show what's going on but I don't seem to be allowed to upload it.

copy link to video hosting

To post images etc. you need trust level 1, you can get there by:

  • Entering at least 5 topics
  • Reading at least 30 posts
  • Spend a total of 10 minutes reading posts

Users at trust level 1 can...

  • Use all core Discourse functions; all new user restrictions are removed
  • Send PMs
  • Upload images and attachments

Ok, I'll check these out. Thank you for your help, much appreciated

I see. Thank you

Thanks for all your answers and help, I'll let you know how I get on.

This worked, thank you so much!

I will check out the links about state changing etc tomorrow, but if I may grab a few moments more of your time, just so I know I'm interpreting this correctly...


bool triggerState = false;// variable for the state of the trigger


This is creating a bool called 'triggerstate' and setting its value to 'false'.


void loop() {
  if (!triggerState && digitalRead(triggerPin) == LOW) {
    triggerState = true;
    //led light
   

This then says something like - if triggerstate is NOT false AND triggerpin is low, then triggerstate is actually true, therefore light the led


 if (triggerState && digitalRead(triggerPin)) {
  triggerState = false;
  delay(30);  // Simple debouncing

and finally, if triggerstate AND triggerpin are both the same, then reset triggerstate back to false.

And this is what then allows the led bit of the loop to happen only once regardless of how long the button is held?

I realise I've probably stated this in overly simplistic terms, but it's easier for me to get my head round if I code in 'plain English', if you get what I mean.

Anyway, thanks again for your help and for getting me towards where I need to be very quickly. Much appreciated!

Probably. I am i transit and can't read the code carefully just now.

But… you can. Put your finger on the code and march yourself through it 1000000000 times slower than the Arduino board will do. Make a list of the variables that inform the logic and keep it up to date so your "printing" and your other actions will be proper, like the if statement tests.

Reading code gets easier, I have often said no good writer of anything is not also widely read.

Little processor boards like the Arduino low end products are very simple. They just execute the code line by line - there is no magic behind any curtain, or there does not have to be, not at least when it comes to things like handling a button so you only get one action per press.

a7

Then a look at the IDE example codes is very instructive. See StateChangeDetection and BlinkWithoutDelay examples.

It's essential to differentiate

  • assigment (variable = 5) and comparison (variable == 5)
  • variable (triggerPin) and a function that returns a value (digitalRead(triggerPin))

In your code analysis you mentioned

If triggerstate is NOT false AND triggerpin is low, then triggerstate is actually true, therefore light the led

Correctly it should read

if triggerstate is NOT false AND the digital state of triggerpin is low, then set triggerstate to true and light the led

Then

if triggerstate AND triggerpin are both the same, then reset triggerstate back to false

This should read

if triggerstate equals true AND digital state of triggerpin equals HIGH then set triggerstate to false

Hope that brings you further!

Have fun!
ec2021

Hi again,

Thanks for everybody's help last week it's much appreciated!

I've come up against a further hurdle that I hope you may be able to help with.
Let me just say that I only get Sunday's to work on this, so trying to code whilst learning to code, research and fault find all in one day is not proving easy!
Sorry if this post is quite long but I'm trying to give you as much info as I can.

The code posted last week worked perfectly, but the additions I thought I had done correctly won't compile.
As per last week, I have a trigger which flashes an LED three times in quick succession when the trigger is pulled, regardless whether its pulled and held or just quickly blipped.
What I have tried to add is a mode switch; when the switch is in one position the aforementioned happens. When it is in its second position the LED only flashes once, again regardless of whether the trigger is blipped or held. At some point the LED will be replaced with a solenoid, but to make sure the code is working properly I'm just using a light for the moment.

This is my new code -

const int triggerPin = 2;   // trigger on pin 2
const int modePin = 3;   // toggle switch w/PULLUP - single flash when switch off (pin 3 @ HIGH), three flashes when switch on (pin 3 @ LOW), 
const int ledPin = 13;    // led on pin 13
const int a = 100;    //delay time
bool triggerState = false;    // variable for the state of the trigger
bool modeState = false;   // variable for the state of the mode selector


void setup() {
  pinMode(triggerPin, INPUT_PULLUP); // sets pin 2 to input with pullup resistor engaged
  pinMode(modePin, INPUT_PULLUP); //sets pin 3 to input with pullup resistor engaged
  pinMode(ledPin, OUTPUT);  //sets pin 13 to output
}

void loop() {
  if ((!triggerState && digitalRead(triggerPin) == LOW) && (!modeState && digitalRead(modePin == LOW)); {  // if trigger is pulled and mode switch is on
    triggerState = true;   // trigger is on
    modeState = true;  // mode switch is on
    //led light x 3
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
    delay(a);
    digitalWrite(ledPin, HIGH);
    delay(a);
  } else {
    digitalWrite(ledPin, LOW);
  }

/* modeState = true; // mode switch is on - this wasnt in the last code but I've added because a second bool
   has been used.
   Do I need to make it this - 
   triggerState = false; // trigger is off
    modeState = true; // mode switch is on
    digitalWrite(ledPin, LOW); // LED off
    delay(30);  // Simple debouncing
   because the modeState bool is still true so it has to do something as a result?
 */
  if (triggerState && digitalRead(triggerPin)); {  // if trigger is released and mode switch is on
    triggerState = false; // trigger is off
    modeState = true; // mode switch is on
    delay(30);  // Simple debouncing
  }


  if ((!triggerState && digitalRead(triggerPin) == LOW) && (modeState && digitalRead(modePin == HIGH)); {  // if trigger is pulled and mode switch is off
    triggerState = true;  // trigger is on
    modeState = false;  // mode switch is off
    //led light x 1
    digitalWrite(ledPin, HIGH);
    delay(a);
    digitalWrite(ledPin, LOW);
  } else {
    digitalWrite(ledPin, LOW);
  }

  if ((triggerState && digitalRead(triggerPin) && (modeState && digitalRead(modePin == LOW)); {  // if trigger is released and mode switch is of
    triggerState = false; // trigger is off
    modeState = false; // mode switch is off
    delay(30);  // Simple debouncing
  }
}

Not sure if I've got the use of the second bool in the 'if' statements correct, but I don't know cos I cant compile it.
I get the following error message when I try -

Arduino: 1.8.19 (Mac OS X), Board: "Arduino Uno"

/Users/taramcnamee/Documents/Arduino/New_trigger_test_2/New_trigger_test_2.ino: In function 'void loop()':
New_trigger_test_2:23:105: error: expected primary-expression before '{' token
   if ((!triggerState && digitalRead(triggerPin) == LOW) && (!modeState && digitalRead(modePin == LOW)); {  // if trigger is pulled and mode switch is on
                                                                                                         ^
New_trigger_test_2:23:105: error: expected ')' before '{' token
New_trigger_test_2:57:105: error: expected primary-expression before '{' token
   if ((!triggerState && digitalRead(triggerPin) == LOW) && (modeState && digitalRead(modePin == HIGH)); {  // if trigger is pulled and mode switch is off
                                                                                                         ^
New_trigger_test_2:57:105: error: expected ')' before '{' token
exit status 1
expected primary-expression before '{' token

It seems to suggest I'm missing either ')' or '}', but for the life of me I can't see where.
I'm sure other errors will pop up when this one is solved :man_facepalming: but I need to get past this one first.

Thank you guys, I apologise for disturbing your Sunday.

The issue is )); { should be )) {.

Check all your if statements carefully and correct them.

Take a look at this line

if ((!triggerState && digitalRead(triggerPin) == LOW) && (modeState && digitalRead(modePin == HIGH)); {  // if trigger is pulled and mode switch is off
  • Compare the number of opening and closing brackets. Do they match ?
  • The only code that is conditional on the result of the test is the semicolon delete it

The same goes for similar tests later in the sketch

1 Like