Using debounce button as on/off button to trigger BMP280 to read altitude

It has limited application but in some situations, it is good to know. Usually it's safer to use the full length variables in case someone tries to increase the range without paying attention to the data type.

I agree, debounce is not needed.
The OP is possibly over thinking the project.

Tom... :grinning: :+1: :coffee::australia:

That's my fault, I suggested it in a previous post. I guess I was thinking more along the lines of NASA mission control rather than dynamite plunger at the time.

Hi @mikami2020

Joking aside though, whether or not to use debounced buttons really depends on your system and how you intend to launch the rocket.

If you just need the button to zero the barometer before launch then debouncing it might be beneficial.

Since we seem to be wallowing in this mess, why? How many times do you need to zero it? Do you need to reverse the action? (no).

How does it, "depend on your system", exactly? Can you give an example of a launch situation where debounce is necessary (restricted to arming the BMP, or the launch itself)?

But you have no reversible actions yet, like APU on/off. Not that you've mentioned. A debounce prepares a switch for a subsequent detection. All your actions are one time events.

Oh yes, definitely. I am just starting to learn about the multiple subjects of Arduino projects from drawing diagrams, connecting wires and writing the code, hopefully in my future posts, I could provide more concise information when I ask my questions. Thanks for the feedbacks :grinning_face_with_smiling_eyes:

Thanks for the advice. I opened the examples and tried to understand them. I also found this guy Paul McWhorter on Youtube teaching how to use a push button as toggle switch.

Thank you MartinL for your assistance. Your example codes have always been helpful to me and my project. I will give it a try and see. Thanks!

We will eventually be switching over to the nano, but the mega is what we have for now.

Thanks aarg for all the inputs. They are all very informational. I am still trying to digest some of the information that you provided due to my unfamiliarity with programming and electrical engineering. It will probably take me some time to get familiar with these whole subjects :sweat_smile:
I intended to also add an ABORT command in the state machine, so if I decided not to launch, I just press the button again to stop the BMP sampling. Would the debounce button be helpful in that situation? (Like one press to sample and move the phrase to LAUNCH and press again to ABORT if I decide no go.)

Abort should have its own button which reacts on the very first press, without debouncing. Also distinguish between Abort button and Aborted state.

For duplicate use of the same button see the StateChangeDetection example.

Hello MartinL,

So I am now using these codes below and I am now able to move the phrase from ARMED to LAUNCH.

case ARMED:

      buttonNew = digitalRead(buttonPin);
      if (buttonOld == 0 && buttonNew == 1) {
        if (ledState == 0) {
          digitalWrite(ledPin, HIGH);
          ledState = 1;
          launchInput = true;
          Serial.println("ARMED");
          bmp280.getAltitude(launchSiteAltitude);
          Serial.print(launchSiteAltitude);
          Serial.println(F("m"));
        }
        else {
          digitalWrite(ledPin, LOW);
          ledState = 0;
          launchInput = false;
        }
      }
      buttonOld = buttonNew;
      delay(dt);

      if (launchInput == true)
      {
        stateMachine = LAUNCH;
      }
      break;

However, I seemed to have run into problem with getting the BMP to sample the launchSiteAltitude.
Function

bmp280.getAltitude(launchSiteAltitude);

didn't seem to have gotten or recorded an altitude reading when I check the serial monitor.
In the serial monitor, after I press the button, it displayed "ARMED" and "0.00m" for the altitude, and then an endless display of "LAUNCH". I didn't think it has sampled and recorded the starting altitude right, because the altitude from the serial monitor before I pressed the button read -1.89 meters, not 0 meter.
I added Serial.println("DEPLOY"); in the beginning of the DEPLOY phrase to check and see if my code has moved from LAUNCH to DEPLOY, but DEPLOY was not displayed in the serial monitor, so I assumed that the code didn't go pass the LAUCH phrase. Is it because I didn't get the altitude reading needed to trigger the formula?

altitude = bmp280.getAltitude(currentAltitude) - launchSiteAltitude;

Can you help me take a look at this please? Below is the current codes.

#include <Servo.h>                                // Include the Servo.h library
#include <BMP280_DEV.h>                           // Include the BMP280_DEV.h library

int ledState = 0;             //starting state of LED
int ledPin = 13;              //the number of the LED pin
int buttonPin = 2;            //the number of the button pin
int buttonNew;                //new button state
int buttonOld = 1;            //old button state
int dt = 100;                 //delay time

int servoPin1 = 9;            // the number of servo pin 1
int servoPin2 = 10;           // the number of servo pin 2
int servoPin3 = 11;           // the number of servo pin 3
int servoPos = 0;             //the starting servo position
Servo Myservo1;               //define servo 1
Servo Myservo2;               //define servo 2
Servo Myservo3;               //define servo 3

float temperature, pressure, altitude;            // Create the temperature, pressure and altitude variables
BMP280_DEV bmp280;

enum stateMachine { DISARMED,
                    ARMED,
                    LAUNCH,
                    DEPLOY,
                    ABORT
                  } stateMachine = DISARMED;

bool armedInput = false, launchInput = false, abortInput = false;
bool servosActivated = false;
float currentAltitude;
float launchSiteAltitude;
float threshold = 1.0f;   // Altitude above launch site in meters

void initializeBarometer()
{
  bmp280.begin();                                 // Default initialisation, place the BMP280 into SLEEP_MODE
  //bmp280.setPresOversampling(OVERSAMPLING_X4);    // Set the pressure oversampling to X4
  //bmp280.setTempOversampling(OVERSAMPLING_X1);    // Set the temperature oversampling to X1
  //bmp280.setIIRFilter(IIR_FILTER_4);              // Set the IIR filter to setting 4
  bmp280.setTimeStandby(TIME_STANDBY_500MS);     // Set the standby time to 0.5 seconds
  bmp280.startNormalConversion();   // Start BMP280 continuous conversion in NORMAL_MODE

}

void initializeServos()
{
  Myservo1.attach(servoPin1);
  Myservo2.attach(servoPin2);
  Myservo3.attach(servoPin3);

}

void initializeButton()
{
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

}



void activateServos ()
{
  Myservo1.write(90);
  Myservo2.write(90);
  Myservo3.write(90);

}

void setup()
{
  initializeBarometer();      //done
  initializeServos();         //done
  Myservo1.write(0);
  Myservo2.write(0);
  Myservo3.write(0);
  initializeButton(); //done

  Serial.begin(115200);       // Initialise the serial port
}

void loop()
{


  if (bmp280.getMeasurements(temperature, pressure, altitude))    // Check if the measurement is complete
  {
    Serial.print(temperature);                    // Display the results
    Serial.print(F("*C   "));
    Serial.print(pressure);
    Serial.print(F("hPa   "));
    Serial.print(altitude);
    Serial.println(F("m"));
  }



  switch (stateMachine)
  {
    case DISARMED:

      stateMachine = ARMED;
      break;

    case ARMED:

      buttonNew = digitalRead(buttonPin);
      if (buttonOld == 0 && buttonNew == 1) {
        if (ledState == 0) {
          digitalWrite(ledPin, HIGH);
          ledState = 1;
          launchInput = true;
          Serial.println("ARMED");
          bmp280.getAltitude(launchSiteAltitude);
          Serial.print(launchSiteAltitude);
          Serial.println(F("m"));
        }
        else {
          digitalWrite(ledPin, LOW);
          ledState = 0;
          launchInput = false;
        }
      }
      buttonOld = buttonNew;
      delay(dt);

      if (launchInput == true)
      {
        stateMachine = LAUNCH;
      }
      break;


    case LAUNCH:
      Serial.println("LAUNCH");
      altitude = bmp280.getAltitude(currentAltitude) - launchSiteAltitude;
      if (altitude > threshold)
      {
        stateMachine = DEPLOY;
      }
      break;


    case DEPLOY:
      Serial.println("DEPLOY");
      if (servosActivated == false)
      {
        activateServos();
        servosActivated = true;
      }
      break;
      
    case ABORT:
      // Add abort code here...
      break;
    default:
      break;
  }
}

Thanks again! :pray: :sweat_smile:

Separate "states" and "transitions". What should be printed or executed only once goes into the transition section of the preceding state, when the state variable is changed to the new state.

I see. This is a good idea.
Could you provide me with a short example on how a transition section may look like?
Thanks again for the input :grinning_face_with_smiling_eyes:

Some admittedly crude pseudocode, but...

case WAITFOREVENT :
  if (the event happens) {
  do something;            // transition section
  state = NEXTSTATE;   // transition section
  }
  break;

What is important to understand, the "do something" may include initialization for NEXTEVENT, for example resetting variables used in NEXTEVENT. Not in WAITFOREVENT. That is what confuses people, I think.

In this case it can be both or either, responding to the event, and/or preparing for the next state.

It is always good to reveal your complete goals at the beginning. If I had, I wouldn't have bothered to weigh in on debouncing.

1 Like

With regard to debounce, a (very) crude approach is to detect the initial transition and just wait a period way longer than the anticipated debounce time.

So if the resulting action necessarily lasts longer than that time, the crudest form of debounce is inherent.

I have changed part of my code from what I originally posted yesterday to the following. I think it is kind of like the "crude" approach you mentioned :sweat_smile: I used a delay time, it seemed to be working okay for my purpose for now.
As a beginner of programming, the other methods involving the millis function or unsigned variables are still difficult for me to grasp :pensive: hopefully I will understand them better as I continue to learn

I see, thanks! I fixed up to organize my codes to look like the example you just provided. Do you mean the codes should look something like this (see below) instead of what I had before?
And as for the debounce button issue, could you suggest an alternative way to trigger the BMP280 to sample a reading for the launch site altitude?
Thanks again for your input :pray: :sweat_smile:

case ARMED:

      buttonNew = digitalRead(buttonPin);
      if (buttonOld == 0 && buttonNew == 1) {
        if (ledState == 0) {
          digitalWrite(ledPin, HIGH);
          ledState = 1;
          launchInput = true;
        }
        else {
          digitalWrite(ledPin, LOW);
          ledState = 0;
          launchInput = false;
        }
      }
      buttonOld = buttonNew;
      delay(100);

      if (launchInput == true)
      {
        bmp280.getAltitude(launchSiteAltitude);
        Serial.println("ARMED");
        Serial.print(launchSiteAltitude);
        Serial.println(F("m"));
        stateMachine = LAUNCH;
      }
      break;


    case LAUNCH:

      altitude = bmp280.getAltitude(currentAltitude) - launchSiteAltitude;
      if (altitude > threshold)
      {
        Serial.println("LAUNCH");
        stateMachine = DEPLOY;
      }
      break;

These statements should only depend on the button state, not on ledState. As soon as the button is pressed the state machine should advance to LAUNCH. Where LAUNCH should be the action taken to reach the LAUNCHED state.