How can I make the conditions execute instantly when button is pressed?

I am making a doorbell type device in an office(teacher's faculty) where when you are requesting to get in, you need to click first the button outside to see if the teacher is available, the led in each cubicle will then turn on to notify the teacher, and the rgb outside will turn yellow, indicating the request is pending. if the teacher is available, the teacher will press the button and the rgb light outside will turn green. if not there is a delay, and if the delay is met in this code (10 seconds), the request will automatically rejected, and the rgb outside will turn red. What I want is when I pressed the button the conditions will be executed instantly without any delay, instead it takes a second of holding a button before one of the conditions is executed. I don't know what is causing this.

p.s. I am a novice in programming, I apologize in advance if my coding is not meeting the standards.

Here is the code:

#include <Adafruit_NeoPixel.h>

#define numrgb 2
#define brightshit 255

const byte rgbpin = 9;

Adafruit_NeoPixel rgb = Adafruit_NeoPixel(numrgb, rgbpin);

//first teacher
const byte persprofbtn1 = 2;
const byte persprofbtn2 = 4;
const byte persprofled = 6;

//second teacher
const byte sekanprofbtn1 = 3;
const byte sekanprofbtn2 = 5;
const byte sekanprofled = 7;


const byte buzzerPin = 8;

unsigned long previousTime = 0;

// for the delay which will be used to reject
int timer1 = 0;
int timer2 = 0;

boolean state1 = LOW;
boolean state2 = LOW;

void setup() {
  Serial.begin(9600);
  
  pinMode(persprofbtn1, INPUT);
  pinMode(persprofbtn2, INPUT);
  pinMode(persprofled, OUTPUT);
  
  pinMode(sekanprofbtn1, INPUT);
  pinMode(sekanprofbtn2, INPUT);
  pinMode(sekanprofled, OUTPUT);
  
  rgb.begin();
}

void accepted(char profled, int pnt, int red, int green, int blue) {
  digitalWrite(profled, LOW);
  rgb.setPixelColor(pnt, rgb.Color(red, green, blue));
  rgb.show();
  tone(buzzerPin, 500);
  delay(2000);
  noTone(buzzerPin);
}

void rejected(char profled, int pnt, int red, int green, int blue) {
  digitalWrite(profled, LOW);
  rgb.setPixelColor(pnt, rgb.Color(red, green, blue));
  rgb.show();
  tone(buzzerPin, 50);
  delay(2000);
  noTone(buzzerPin);
}

void setLight(int pnt, int red, int green, int blue) {
  rgb.setPixelColor(pnt, rgb.Color(red, green, blue));
  rgb.show();
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - previousTime >= 1000) {
    previousTime = currentTime;
    
    //first teacher condition
    if (digitalRead(persprofbtn1) == HIGH) {
      state1 = HIGH;
    } else if (digitalRead(persprofbtn2) == HIGH) {
      state1 = LOW;
      accepted(persprofled, 0, 0, 255, 0);
      timer1 = 0;
      setLight(0, 0, 0, 0);
    } else if ((timer1 == 10) && (digitalRead(persprofled) == HIGH)) {
      state1 = LOW;
      rejected(persprofled, 0, 255, 0, 0);
      timer1 = 0;
      setLight(0, 0, 0, 0);
    }
    
    //second teacher condition
    if (digitalRead(sekanprofbtn1) == HIGH) {
      state2 = HIGH;
    } else if (digitalRead(sekanprofbtn2) == HIGH) {
      state2 = LOW;
      accepted(sekanprofled, 1, 0, 255, 0);
      timer2 = 0;
      setLight(1, 0, 0, 0);
    } else if ((timer2 == 10) && (digitalRead(sekanprofled) == HIGH)) {
      state2 = LOW;
      rejected(sekanprofled, 1, 255, 0, 0);
      timer2 = 0;
      setLight(1, 0, 0, 0);
    }
    
    
    //serves as a "switch" to proceed in first teacher conditions
    if (state1 == HIGH) {
      timer1 += 1;
      if (digitalRead(persprofbtn1) == HIGH) {
        digitalWrite(persprofled, HIGH);
      	setLight(0, 255, 255, 0);
      }
    }
    
    //serves as a "switch" to proceed in second teacher conditions
    if (state2 == HIGH) {
      timer2 += 1;
      if (digitalRead(sekanprofbtn1) == HIGH) {
        digitalWrite(sekanprofled, HIGH);
      	setLight(1, 255, 255, 0);
      }
    }
  }
}

The code below this line is executed only once per second, which means the buttons are not read "instantly".

If you want instant response, remove ALL the delays, and take the button reads out of any timed code.

1 Like

As mentioned, using delay( ) in your sketches makes your code unresponsive for this delay time.


Time to look at State Machine programming techniques.

There are several tutorials on this in the Tutorial section of this WEB site.

BTW, use more meaningful comments throughout sketches.

2 Likes

In practice, these delays might be waaaay longer than necessary

  rgb.setPixelColor(pnt, rgb.Color(red, green, blue));
  rgb.show();
  tone(buzzerPin, 50);
  delay(2000);
  noTone(buzzerPin);

I for one am annoyed by a two second beep even just reading the code that would make that happen. :expressionless:

and I can't test it from under the umbrella here, but as @jremington observes, the code is effectively executed once every 1000 milliseconds. It looks like it would work being run at a higher rate, that higher rate will directly influence the response time.

Instead of 1000, try 50, which would make the code get its chance 20 times a second instead of just once and may be all and what you need to make it feel be more responsive.

a7

1 Like

OK I delayed my nap long enough to test my idea and find it works.

There are implications to running the loop code at 20 Hz. You must multiply the constant that you use to count off the 10 seconds.

Everything else works just fine. The tones at 400 milliseconds duration seemed right(er) to me, but it's your picnic.

You are still going to be laggy when a tone is sounding; the direction @LarryD points you is the solution to that.

The three searches often suggested

  arduino blink without delay

and

  arduino two things at once

and

  arduino finite state machine traffic lights

will turn up good places to settle in and poke around.

I might also suggest looking at

  Examples / 02.Digital / StateChangeDetection

on offer in the IDE.

Achieving mastery of those several concepts will not be a waste of time.

a7

1 Like

seems you have 3 states: Idle, Request and Acknowledge

when the outside button is pressed, the Request state is entered, various LEDs activated, and a timestamp captured.

when in the Request state, if one of the teacher buttons is pressed, the state becomes Acknowledge and LEDs change state and presumably a timestamp also captured to reset the system

while in the Request state, the timestamp captured when the request button is pressed it checked to timeout and reset the system

looks this over

const byte PinRequest  = A1;
const byte PinAck      = A2;
const byte PinLedReq   = 13;
const byte PinLedAck   = 12;

enum { Idle, Request, Ack };
int state = Idle;

enum { Off = HIGH, On = LOW };

unsigned long MsecTimeout = 5000;       // short for testing
unsigned long msecLst;

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    switch (state)  {
    case Idle:
        if (digitalRead (PinRequest) == LOW) {
            digitalWrite (PinLedReq, On);
            state   = Request;
            msecLst = msec;
        }
        break;

    case Request:
        if (msec - msecLst >= MsecTimeout)  {
            digitalWrite (PinLedReq, Off);
            digitalWrite (PinLedAck, Off);
            state = Idle;
        }

        if (digitalRead (PinAck) == LOW) {
            digitalWrite (PinLedReq, Off);
            digitalWrite (PinLedAck, On);
            state   = Ack;
            msecLst = msec;
        }
        break;

    case Ack:
        if (msec - msecLst >= MsecTimeout)  {
            digitalWrite (PinLedReq, Off);
            digitalWrite (PinLedAck, Off);
            state = Idle;
        }
        break;
    }
}

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

    pinMode (PinRequest, INPUT_PULLUP);
    pinMode (PinAck,     INPUT_PULLUP);
    pinMode (PinLedReq,  OUTPUT);
    pinMode (PinLedAck,  OUTPUT);
    digitalWrite (PinLedReq, Off);
    digitalWrite (PinLedAck, Off);
}
1 Like

Ohh I might need to learn more about switch-case statements

Thank you to all that replied to my query but it seems like @jremington pointed out the problem to my code. I would try to apply all your suggestions in the future! Thank you everyone!

Don't worry, I plan on removing the buzzer :smile:. The idea for the 1 second delay in the loop so that I can add a delay in every request. I used this because, I cant use the normal delay function since it is uninterruptible.

I see that you have provided for two teacher/cubicles. If you have plans to go beyond two, you should look into exploiting array variables and for loops.

Any code that has variables whose names differ only in an appended digit is signal that array variables may be appropriate.

Whenever you create another by copy/paste/editing a block of code array variables will probably help.

Doing the scaling with array variables means only one place to look for problems and one place to work on modifications or enhancements and will cut down on errors that are easy to make when you are forced to do basically the same thing to multiple blocks of code.

The blocking nature of accept()/reject() responses is not a problem, if my guess of how you plan to deploy this accurate: a board with N request buttons, used by one person to connect with one teacher in her cubicle.

Two quick pints:

You should decide to use pulled up pushbuttons, either with INPUT_PULLP or a real resistor and then pressing would read LOW.

Also

//first teacher
const byte persprofbtn1 = 2;
const byte persprofbtn2 = 4;
const byte persprofled = 6;

I don't know what these names mean other than that they are for btns and an led. In any language button 1 should reflect that it is the request or inquiry and button 2 should reflect that it is the accepting or acknowledgelment.

Both those are done in @gcjr's version.

a7

seems that there are several other problems

  • buttons are typically connected between the pin and ground, the pin configured as INPUT_PULLUP to use the internal pullup resistor which pulls the pin HIGH and when pressed, the button pulls the pin LOW.

  • persprobtn1 sets state1 which makes the following condition true. without anything to delay the processing of loop(), timer1 will quickly increment, easily be > 10 within a few msec. what is the purpose for checking persprobtn1 again?

  • the following condition is almost immediately true because timer1 has incremented >10 probably before persprobtn1 is released.
  • it's not clear to me why setLight(0, 0, 0, 0); is called immediately after accepted(persprofled, 0, 0, 255, 0); or rejected(persprofled, 0, 255, 0, 0);; won't it turn off the LEDs turned on by the other functions

shouldn't the code do:

  • when persprobtn1 is pressed, LEDs can be turned on to alert the teachers, set state1 and reset the timer

  • shouldn't persprofbtn2 be checked only when state1 is true, change the LED settings to acknowledge the person at the door and reset the timer

  • a timer should run when state1` is true, either it turns off all the LEDs either way after a request or the acknowledgement are made

unsigned long msecLst;

void
loop ()
{
    unsigned long currentTime = millis ();

    if (digitalRead (persprofbtn1) == HIGH) {
        state1  = true;
        msecLst = currentTime;      // reset timer

        // set LEDs for request
    }

    if (state1 == HIGH) {
        if (digitalRead (persprofbtn2) == HIGH) {
            msecLst = currentTime;      // reset timer
            // set LEDs for acknowledge
        }

        if (currentTime - msecLst > 10000) {
            state1 = false;
            setLight (0, 0, 0, 0);
        }
    }
}

Whatever odd things turn up in looking close at the code, the minor adjustments proposed by @alto777 in #4 do, in fact, fix the OP's problem and make the code work plausibly for the desired functionality.

a7

i don't see how the timeout is fixed?

If you've changed your code per @jremington's #2 and it is functioning satisfactorily, please post the new code.

TIA

a7

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