Run the function once button is press

So what I'm trying to achieved in this project is that once the button is pushed("push once, not hold press") the function will start looping.
example that LED_PIN, one i push the button the led will light up and once push again it will switch off. So just think of it that the LED_PIN is like the function i want to switch on.

i tried so many way that i can think of but none of them are working.
i don't know what's the proper approached to achieved this.
so am seeking help with you guys hope u can hep me thank you in advance.

const int BUTTON_PIN = 11;  // Connect the Button to pin 7 or change here
const int LED_PIN    = 13;   
// variables will change:
int ledState = LOW;        // tracks the current state of LED
int lastButtonState;        // the previous state of button
int currentButtonState; // the current state of button

int time = 0;
int counter = 0;
int current_time=0;

// relay variable
int Relay[4] = {4,5,8,9};  
  
void Show();
void Show_off();

void setup() {
  Serial.begin(9600);                         // initialize serial
  pinMode(BUTTON_PIN, INPUT);  // set arduino pin to input mode
    for (int i = 0; i < 4; i++) {
    pinMode(Relay[i], OUTPUT);
      // set arduino pin to output mode
  pinMode(LED_PIN,OUTPUT);
  currentButtonState = digitalRead(BUTTON_PIN);
  }
}
  
void loop() {
  lastButtonState    = currentButtonState;                // save the last state
  currentButtonState = digitalRead(BUTTON_PIN);
  Serial.println(currentButtonState);
   // read new state
  
  if(lastButtonState == HIGH && currentButtonState == LOW) {
    Serial.print("The button is pressed: ");
    Show();

  
    // toggle state of LED
    if(ledState == LOW) {
       ledState = HIGH;
        Show(); 
       Serial.println("Turning LED on"); 
    }
    else {
      ledState = LOW; 
      Show_off();
      Serial.println("Turning LED off"); 
    }
 
    // control LED arccoding to the toggled state
    digitalWrite(LED_PIN, ledState);  //turns the LED on or off based on the variable
  }
}




void Show() {
current_time=millis();
if((current_time-time)>=1000){
counter++;
time=current_time;
Serial.println(counter);

switch (counter) {
      case 5 :
           digitalWrite(4, HIGH);
        break;
      case 10 :
          digitalWrite(5, HIGH);
        break;
      case 15 :
          digitalWrite(8, HIGH);
        break;
      case 20 :
           digitalWrite(9, HIGH);
  
        break;
      default:
        // turn all the LEDs off:
        for (int i = 0; i < 4; i++) {
          digitalWrite(Relay[i], LOW);
          if(counter>=25){
  counter = 0;
       
         }
      }
    }
  }
}

void Show_off(){

}

Your button is on the wrong pin.

1 Like
  • How is your switch wired ?

Dangerous, but I will take it.

The body of this if statement

    if(ledState == LOW) {
       ledState = HIGH;
        Show(); 
       Serial.println("Turning LED on"); 
    }

inside your button handling runs once when the button becomes pressed.

But your Show() function is written in such a manner that it needs to be called repeatedly in order to do its thing.

This is good. It is non-blocking code, it just needs to be handled differently.

Instead of calling Show() where you do, just use the ledState later to call either Show() or the other function you haven't written yet.

I hope this is enough for you to see what and where I mean

    // control LED arccoding to the toggled state
    digitalWrite(LED_PIN, ledState);  //turns the LED on or off based on the variable


    // advance either the Show process or the Show_Off process
    if (ledState == HIGH) Show();
    else Show_Off();
  } // end of the loop function

a7

OK, your lucky day. Your code actually has a number of (other) problems, I apologize for posting from under the umbrella the only flaw I saw.

The other code looks plausible, but fails to properly implement both debouncing and state change detection.

The state detection looks only for one edge, but to debounce effectively, both edges have to be observed and handled.

And there is no time allowing for contact bounce.

The latter problem is easily solved in a hack by just making the loop run at only 50 Hz. This means contact bounce is not possible to observe, as you are on;y opening your eyes, as it were, once every 20 milliseconds. Any bounce either did not happen, was in the middle of happening od had long since finshed. All make just reading the switch and using the value you read valid.

The state change is trickier, and with the debouncing done with the hack yours will function OK, but will perhaps not be the model to carry fortward when you need to do real debouncing and real state change detection.

Here's your code fixed up. Ordinarily I'd leave the fun to you, it is only because I mislead you that I post this. If you care to scrutinize it for subtle and not-so-subtle differences to your code, you may learn something. OR maybe not. Or don't.

Play with it here


Wokwi_badge UA OnceButton!


// https://wokwi.com/projects/396896548104172545
// https://forum.arduino.cc/t/run-the-function-once-button-is-press/1255473

const int BUTTON_PIN = 7;  // Connect the Button to pin 7 or change here
const int LED_PIN    = 13; 

// variables will change:
int ledState = LOW;        // tracks the current state of LED
int lastButtonState;        // the previous state of button
int currentButtonState; // the current state of button

int time = 0;
int counter = 0;
int current_time=0;

// relay variable
int Relay[4] = {A0, A1, A2, A3};  
  
void Show();
void Show_off();

void setup() {
  Serial.begin(9600);

  pinMode(BUTTON_PIN, INPUT_PULLUP);
  currentButtonState = digitalRead(BUTTON_PIN);

  for (int i = 0; i < 4; i++)
    pinMode(Relay[i], OUTPUT);

  
  pinMode(LED_PIN,OUTPUT);
}
  
void loop() {
  lastButtonState = currentButtonState;           // save the last state
  currentButtonState = digitalRead(BUTTON_PIN);   // read new state

// if you need to here:  Serial.println(currentButtonState);

  if (lastButtonState == HIGH && currentButtonState == LOW) {
    Serial.print("The button is pressed: ");
//    Show();

  
    // toggle state of LED
    if(ledState == LOW) {
       ledState = HIGH;
//        Show(); 
       Serial.println("Turning LED on"); 
    }
    else {
      ledState = LOW; 
//      Show_off();
      Serial.println("Turning LED off"); 
    }

  }

    // control LED arccoding to the toggled state
    digitalWrite(LED_PIN, ledState);  //turns the LED on or off based on the variable

// run one of the two machines
  if (ledState) Show();
  else Show_Off();

  delay(20);    // poor man's debouncing
}

void Show() {
  current_time=millis();
  if((current_time-time) >= 100) {    // was 1000. life too short

  time=current_time;

  counter++;
  
// if you must here:  Serial.println(counter);

  switch (counter) {
  case 5 :
        digitalWrite(Relay[0], HIGH);
    break;

  case 10 :
      digitalWrite(Relay[1], HIGH);
    break;

  case 15 :
      digitalWrite(Relay[2], HIGH);
    break;

  case 20 :
        digitalWrite(Relay[03], HIGH);
    break;

  default:
    // turn all the LEDs off:
    for (int i = 0; i < 4; i++)
      digitalWrite(Relay[i], LOW);

      if(counter >= 25)
        counter = 0;

    break;
  }
  }
}

void Show_Off(){
  for (int i = 0; i < 4; i++)
    digitalWrite(Relay[i], LOW);

  counter = 0;
}

For state change detection and how the debounce section starts to become part of that, see


Wokwi_badge UA State Change Detection!


You will note that the state change picks up both edges by detecting a difference, not just a transition from LOW to HIGH or vive versa, but from either value to the other. The example still uses the debounce hack, just to leave focus on the state changing detector.

HTH

a7

1 Like

:pleading_face:

OHHHHHHH MYYYYYY GOD. it works :grin: :grin: :grin:. it really is my lucky day.
Thank you very much. I've been searching for weeks to solve this. from what you've said it really proves that i need to work more on understanding how the codes work. another learning. I really appreciate your effort in helping me. thank you very much.

Just keep reading code. It is hard to know when you don't know whether you are reading good code or bad, so try to learn from both.

Usually ppl post decent code on the solutions, and usually noob code is either bad or has nothing you can learn going on. But follow discussions and read read read any code they talking about.

No good writer of anything is not also widely read.

This alternate to your Show() function takes an entirely different approach. I did enjoy seeing how you did it.

# define ON   HIGH
# define OFF  LOW

// time constants
# define T0  128    // off time
# define T1   32    // on time

void Show() {
  static unsigned int wait = T0;
  static unsigned long time;

  static byte oddEven;  // turning on or off
  static int theLED;    // which LED we at now

  if (current_time - time < wait) return;   // not time to change anything yet

  time = current_time;

// turn on or off, set hang time, advnace to next in sequence:

  if (oddEven & 0x1) {
// turn off the LED and advance
    if (relay[theLED])  // if it exists
      digitalWrite(relay[theLED], OFF);
    wait = T0;      
    
    if (++theLED >= NRELAYS) theLED = 0;
  }
  else {
// turn on the relay and advance
    if (relay[theLED])  // if it exists
      digitalWrite(relay[theLED], ON);
    wait = T1;
  }

  oddEven++; 
}

I added an element to the relay array and wrote it so zeros mean there is not actually a pin or relay associated with a step. So writing
// relay variable
int relay[] = {A0, A1, A2, A3, 0};  
const byte NRELAYS = sizeof relay / sizeof *relay;

up top gives me the four real relays and the extra time step your original seemed to want to take with no LED showing.

a7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.