DEBOUNCE

Hello friends,

I’m trying to insert a routine of sending SMS working with Debounce.

I want an SMS is sent only after 5 seconds the level sensor (called dig pin 4) is triggered.

After researches, I saw that the best way to do this is through Debounce, but the way I’m doing, are being sent SMS and not only constant after 5 seconds of cranking the sensor could indicate me where I am wrong?

#include <SoftwareSerial.h> //Biblioteca NewSofSerial, usada para comunicação serial.

SoftwareSerial mySerial(2, 3); //RX, TX

//ligar pino 1 (placa GSM) no pino 3 ARDUINO 
int powerkey =  5;
int statuspin = 6;
int pinState = 0;

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 4;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 5000;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(powerkey, OUTPUT); 
  pinMode(statuspin, INPUT); 
  mySerial.begin(9600);               // the GPRS baud rate   
  Serial.begin(9600);   

  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 
  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 

  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);     
}

void loop() {

  pinState = digitalRead(statuspin);
  if(pinState==LOW){
    digitalWrite(powerkey, HIGH);   // set the LED on
    delay(2000);
    digitalWrite(powerkey, LOW); 
  }  

  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }

  // set the LED using the state of the button:
  digitalWrite(ledPin, buttonState);

  mySerial.println("AT+CMGF=1");
  Serial.println("Enviando Mensagem...");
  delay(1000);
  mySerial.println("AT+CMGS=\"+031xxxxxxxx\"");
  delay(2000);
  mySerial.print("Nível do tanque atingido");
  delay(2000);
  mySerial.write(26);//Equivalente a CTRL+Z, para fazer somente um envio de SMS.

  Serial.println("Mensagem Enviada");


  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
}

Please enclose your code into [ code ] tags. Your error depends on misplaced parentheses and it would be much easier to detect with proper indentation. Your check of debounceDelay only sets buttonState, but doesn't affect the SMS send routine which is executed anyway:

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }

  // set the LED using the state of the button:
  digitalWrite(ledPin, buttonState);

  // here a message is sent whether buttonState changed or not
  mySerial.println("AT+CMGF=1"); 
  // so a message will be sent every time loop() executes

You obviously need to add a control that the button state changed (after debounce) before sending the SMS.

@RSALVINO: Please edit your post, select the code, and put it between [code][/code] tags.

You can do that by hitting the # button above the posting area.

How to use this forum

Already changed corrections in post, sorry I’ll be more careful next time.
Spatula, thanks for your guidance, I will test and post here if it worked or not.
Thank you!

hello Spatula,

I made the change that you suggested but still the same problem, the SMS is sent continuously, not respecting the 5 seconds of cranking sensor that established in the code.

The following modification:

#include <SoftwareSerial.h> //Biblioteca NewSofSerial, usada para comunicação serial.

SoftwareSerial mySerial(2, 3); //RX, TX

//ligar pino 1 (placa GSM) no pino 3 ARDUINO 
int powerkey =  5;
int statuspin = 6;
int pinState = 0;

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 4;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 5000;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(powerkey, OUTPUT); 
  pinMode(statuspin, INPUT); 
  mySerial.begin(9600);               // the GPRS baud rate   
  Serial.begin(9600);   

  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 
  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 

  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);     
}

void loop() {

  pinState = digitalRead(statuspin);
  if(pinState==LOW){
    digitalWrite(powerkey, HIGH);   // set the LED on
    delay(2000);
    digitalWrite(powerkey, LOW); 
  }  

  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
  }

  // set the LED using the state of the button:
  digitalWrite(ledPin, buttonState);

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:

  Serial.println("Enviando Mensagem...");
  delay(1000);
  mySerial.println("AT+CMGS=\"+031xxxxxxxx\"");
  delay(2000);
  mySerial.print("Nível do tanque atingido");
  delay(2000);
  mySerial.write(26);//Equivalente a CTRL+Z, para fazer somente um envio de SMS.

  Serial.println("Mensagem Enviada");
}

This is how I deal with button presses -

int button_counter = 0;
int button_timer = 500;
boolean button_down = false;

setup() {

  pinMode(3,INPUT);
  digitalWrite(3,HIGH);

}

loop() {

  ++button_counter; 

  if (button_counter > button_timer) {
    //check button state
    button_counter = 0;
    if ((digitalRead(3)==LOW) && (!button_down)) {
      button_down = true;
      //perform some action once when button initially pressed
      
    } else {
      //button released
      button_down = false;
    }
  } 
}

Kind of a double protection with the button press check every 500 clock cycles or so and then a block on causing the action to perform twice while the button is down with the button_down set to true. As soon as you release the button it can check again at the next button_counter > 500. Probably not the most perfect way to handle debounce however it works for me.

Hi, to be honest I don't see how the logic really changed, because sending the SMS still happens without a previous control. Let's go through the main steps.

First I would define a variable, let's call it mustSendSMS, which if true will start the instructions for sending the SMS:

// in the global section, before setup()
boolean mustSendSMS = false;
// then, in loop()
  if (mustSendSMS)
  { // the following code remains unchanged
    Serial.println("Enviando Mensagem...");
    delay(1000);
    mySerial.println("AT+CMGS=\"+031xxxxxxxx\"");
    delay(2000);
    mySerial.print("Nível do tanque atingido");
    delay(2000);
    mySerial.write(26);//Equivalente a CTRL+Z, para fazer somente um envio de SMS.

    Serial.println("Mensagem Enviada");
  }

Now we need to define when mustSendSMS becomes true, otherwise the SMS will never be sent. The choice is pretty obvious:

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
    // added: instruct to send the SMS
    mustSendSMS = true;
  }

Finally, we need to reset mustSendSMS to false, otherwise it will never stop. We just append one instruction to the code modified above.

    Serial.println("Mensagem Enviada");
    // reset the flag so the message is sent only once
    mustSendSMS = false;
  }

This should be all.

Spatula Hello, I found your solution very interesting. Tonight I will test and post here if it worked. Thank you all for your help!

Hello Spatula, did the tests with the suggested changes, but still with the same problem, messages are sent repetidamentes, regardless of the drive’s sensor.

Here adaptations made ??to the code:

:

#include <SoftwareSerial.h> //Biblioteca NewSofSerial, usada para comunicação serial.

SoftwareSerial mySerial(2, 3); //RX, TX

//ligar pino 1 (placa GSM) no pino 3 ARDUINO 
int powerkey =  5;
int statuspin = 6;
int pinState = 0;

boolean mustSendSMS = false;

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 4;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(powerkey, OUTPUT); 
  pinMode(statuspin, INPUT); 
  mySerial.begin(9600);               // the GPRS baud rate   
  Serial.begin(9600);   

  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 
  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 

  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);     
}

void loop() {

  pinState = digitalRead(statuspin);
  if(pinState==LOW){
    digitalWrite(powerkey, HIGH);   // set the LED on
    delay(2000);
    digitalWrite(powerkey, LOW); 
  }  

    mustSendSMS = true;

  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;



  }
  if (mustSendSMS)
  {
    // set the LED using the state of the button:
    digitalWrite(ledPin, buttonState);

    mySerial.println("AT+CMGF=1");
    Serial.println("Enviando Mensagem...");
    delay(1000);
    mySerial.println("AT+CMGS=\"+031xxxxxxxx\"");
    delay(2000);
    mySerial.print("Nível do tanque atingido");
    delay(2000);
    mySerial.write(26);//Equivalente a CTRL+Z, para fazer somente um envio de SMS.

    Serial.println("Mensagem Enviada");
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
  mustSendSMS = false;

}

You set mustSendSMS to true and to false on every pass through loop. That is wrong. You should set it to true only when there IS a need to send an SMS, and you should only set it to false when you actually send an SMS.

Hello PaulS, I did what you recommended but I’m struggling to put it in the code, can you help me?
Below is my code:

:
#include <SoftwareSerial.h> //Biblioteca NewSofSerial, usada para comunicação serial.

SoftwareSerial mySerial(2, 3); //RX, TX

//ligar pino 1 (placa GSM) no pino 3 ARDUINO 
int powerkey =  5;
int statuspin = 6;
int pinState = 0;

boolean mustSendSMS = false;

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 4;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 5000;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(powerkey, OUTPUT); 
  pinMode(statuspin, INPUT); 
  mySerial.begin(9600);               // the GPRS baud rate   
  Serial.begin(9600);   

  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 
  mySerial.println("AT");
  delay(500);  // the GPRS baud rate 

  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);     
}

void loop() {

  pinState = digitalRead(statuspin);
  if(pinState==LOW){
    digitalWrite(powerkey, HIGH);   // set the LED on
    delay(2000);
    digitalWrite(powerkey, LOW); 
  }  

  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  if (mustSendSMS)
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
    mustSendSMS = true;


  }

  {
    // set the LED using the state of the button:
    digitalWrite(ledPin, buttonState);

    mySerial.println("AT+CMGF=1");
    Serial.println("Enviando Mensagem...");
    delay(1000);
    mySerial.println("AT+CMGS=\"+031xxxxxxxx\"");
    delay(2000);
    mySerial.print("Nível do tanque atingido");
    delay(2000);
    mySerial.write(26);//Equivalente a CTRL+Z, para fazer somente um envio de SMS.

    Serial.println("Mensagem Enviada");
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;
  mustSendSMS = false;

}
  if (mustSendSMS)

There are no curly braces following this statement, so it is difficult to see that YOU understand the statement(s) that will be affected by this statement.

I can tell you, though, that it is in the wrong place.

You need to understand what you are trying to do. There are things that trigger sending an SMS. Those things can happen more than once, but you only want to send an SMS once. So, you need one flag that gets set true when the even occurs. That flag can be set true many times.

You need another flag that defines whether an SMS has been sent. That flag is initially false. It is set to true when the SMS has been sent. It is set to false when some kind of reset happens.

Then, the code to send the SMS is called only inside an if block that depends on both flags. If the flags are needToSendSMS and smsSent, then the code might look like:

if(needToSendSMS && !smsSent)
{
   sendSMS();
   smsSent = true;
}

This, of course, requires that you create a function to call, and that the function does nothing but send the SMS.

It also requires that you pay attention to when to reset needToSendSMS to false. At the end of loop is NOT the right answer.

Finally, it requires that you set smsSent back to false at some point. Where to do that in your code is not clear, since there doesn't seem to be any kind of reset code. Under what circumstances, other than resetting the Arduino, should the device resume being prepared to send an SMS?