How to exit a nested if statement

Hi there

I am almost embarrassed to ask this question as it seems like the type of thing i'll feel a fool for missing

I am using an arduino uno r3 to test some accelerations using a gy-521/mpu6050 accelerometer. I am using Jeff Rowberg's code just modified. I am also trying to incorporate a micro SD card to record the results as a separate module. The part i'm having a problem with is stopping the arduino. So far I've just been hitting the reset button and copying and pasting the serial monitor into excel, but i would rather it was recorded as a text file first.

I have made a very simple stop button program shown below;

unsigned long time;
const int button_in=3;
int button_state=0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(button_in, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

button_state = digitalRead(button_in);

if (button_state==HIGH){;

Serial.print("Time: ");
time = millis();

Serial.println(time/1000.0,3);
delay(10);}
else {

exit(0);


}
}

and also using the SD example from arduino.

Below is Jff Rowbergs original code;

My problem is that i cant completely stop the serial monitor. Only display "error opening file" when i press the button, and when i release it, it goes back to measuring acceleration. I want it to completely stop, save the information to the SD card, close and save the file to the SD card and then i can just close the serial monitor.

Accelerometer wired as in below link

SD card wiring

Stop button

https://www.arduino.cc/en/uploads/Tutorial/PushButton.jpghttps://www.arduino.cc/en/uploads/Tutorial/PushButton.jpg

I'm not used to this forum so if i have missed out any information please say.

Many Thanks

Ross

Couldnt post both the bits of code so here they are as attachments...

Modified Acc Code.txt (15.5 KB)

Original Acc Code.txt (15.9 KB)

Use a flag (boolean variable) to indicate whether the button has been pushed.

Thanks for the reply!

managed to get it to work for the moment by moving the exit function outside the next if statement.Does this just do the same as the reset button on the actual board? Could you point me in the direction of a tutorial on how to include a boolean for a button press into if statements please? Tried the arduino site for booleans and i was unsure how to include it in this specific code. Thanks

The attached text file has characters that make it difficult to read, but from your description it sounds like your program has two states: gathering data and reporting data.

After you write the data you could go back to gathering it and report again with another button press. Or you could do nothing but exiting doesn't make much sense on an Arduino.

Check out the following framework, it might work for your application.

// possible program states
const int GATHER_DATA = 0;
const int REPORT_DATA = 1;

int programState = GATHER_DATA;  // current program state

int button_state = LOW;

void setup() {

  // setup code stays the same

}

void loop() {

  if ( button_state == HIGH )
  {
    // time to write data
    programState = REPORT_DATA;
  }

  // act on program state
  switch ( programState )
  {
    case GATHER_DATA:

      // code to read sensors

      break;

    case REPORT_DATA:

      // open file, write to file, close file

      // reset state to gathering data - could add an IDLE state if desired
      programState = GATHER_DATA;
      
      break;

    default:
      break;

  }

}

[quote author=Blue Eyes date=1510767914 link=msg=3487963]
Or you could do nothing but exiting doesn't make much sense on an Arduino.[/quote]
Neither does going to all the trouble of setting up an interrupt-driven system and then forcing your loop() function to wait in a 'while' loop until an interrupt occurs.

I suspect if it is necessary to "exit a nested if statement" it is because the code is poorly designed.

Why don't the IFs run to a natural conclusion?

...R

Because I'm crap at programming! The use of exit was to get the program working enough to get some results. The idea was to get the program to stop amd save the results to a txt file. I'm now trying to improve so as an OP said, stop the program and be able to start it again. The original code as stated was Jeff Rowbergs. Now I've bodged in an SD card and a push button to stop/ maybe in the future, pause the system after saving the results. As it's an 'interrupt driven system' what options do the interrupt allow?

Ross46:
so as an OP said,

In this Thread you are the OP (Original Poster).

Because I'm crap at programming!

Don't write yourself off before you even start.

The logic of a series of IF statements just needs careful thought. When you know what needs to be done the programming will be easy.

...R

I would also use a state machine approach. Here’s a barebones outline. It include just enough stuff to compile without errors. Doesn’t include all the setup() stuff you need for your hardware, ISR, etc.

You didn’t say how your button is wired. But, if one terminal is connected to PIN 3 and the other to +5, then it’s wrong. Connect it between PIN 3 and ground and use INPUT_PULLUP when you set the pin mode. The logic will be reversed -- PIN 3 will read LOW when button is pushed. But, that’s the right way to do it.

Things you’ll need to read up on:

#include<SD.h>

enum States {initialize, logging, paused};
States currentState = initialize;

uint8_t lastButtonState;
const uint8_t button_in = 3;
volatile bool mpuInterrupt = false;
bool dmpReady = false;
File myFile;

void setup() {
  Serial.begin(57600);
  //
  // Setup your hardware, interrupts, etc. here
  //

  // Start the SD system, but don't open a file yet. Will do that in initialize state
  if(!SD.begin(4)) {
    Serial.println("SD initialization failed");
    while(1) {}
  }

  pinMode(button_in, INPUT_PULLUP);
  lastButtonState = digitalRead(button_in);

}

void loop() {
  uint8_t currentButtonState = digitalRead(button_in);

  switch (currentState) {
    case initialize:
      myFile = SD.open("Use a unique filename here every time", FILE_WRITE);
      currentState = logging;
      break;

    case logging:
      if (dmpReady) {
        mpuInterrupt = false;
        //
        // process sensor data here, log to file, print to Serial, etc.
        //
      }

      if (currentButtonState != lastButtonState) {
        if (currentButtonState == LOW) {
          currentState = paused;
          //
          // close the SD card file here, print results summary, etc.
          //
        }
      }
      break;

    case paused:
      // Don't do anything unless button is pushed again
      if (currentButtonState != lastButtonState) {
        if (currentButtonState == LOW) {
          currentState = initialize;
        }
      }
      break;

    default:
      break;
  }

  lastButtonState = currentButtonState;

  // You can do any other processing you want here because you're not stuck in a while loop waiting for an interrupt
}

Ah, on my old motorcycle forum we used OP as 'overhead poster', the poster above you. And I can get along with matlab fine, that's just commands for maths and I understand that. My problem is trying to change code that I didnt write, with libraries that have other commands etc. I've resorted to basics and writing out the if statements on paper, and I'm back to where I started after messing up the 'I've got it working' code. Now I'm trying to look up how I can get this code to;

Run the program as usual, giving the accelerations.
Pause the program when pressing a button.
Save the results.
Restart the data collection
Repeat as necessary

Looking at doing this through commands in the serial monitor or through external buttons. I think the serial monitor would be more useful

Thanks for your help

Ross46:
Run the program as usual, giving the accelerations.
Pause the program when pressing a button.
Save the results.
Restart the data collection
Repeat as necessary

The outline I just posted handles all those tasks.

I wrote some demo code to better explain post #5. It's only meant to show how the two states work, I cannot compile it because I don't have the libraries. It may not work correctly because I'm making some assumptions on how the MPU library works. Before writing to the file I added a seek to end, assuming you will want to append new data when you push the button. The button press may need to be debounced.

BTW, I wouldn't open the file in setup, since it may not get closed later.

// ================================================================
// ===          MAIN PROGRAM LOOP           ===
// ================================================================

const int DATA_TO_SERIAL = 0;  // ** Run the program as usual, giving the accelerations.
const int DATA_TO_FILE = 1;    // ** Pause the program when pressing a button.  Save the results.

int  programState = DATA_TO_SERIAL;  // ** initial program state
bool dataAvailable = false;         // ** true if data is available to write

void loop() {

  time = micros();
  button_state = digitalRead(button_in);

  if ( button_state == HIGH ) programSate = DATA_TO_FILE; // ** next read goes to file

  // if programming failed, don't try to do anything
  //if (!dmpReady) return;
  if (!dmpReady) while (1); // ** can move this to setup

  dataAvailable = chedkForData(); // set flag

  // ** if data is available print it to serial or file
  if ( dataAvailable )
  {
    // ** get data from buffer
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetAccel(&aa, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
    mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

    // ** act on program state
    switch ( programState )
    {

      // ** Run the program as usual, giving the accelerations.
      case DATA_TO_SERIAL:

#ifdef OUTPUT_READABLE_REALACCEL
        // display real acceleration, adjusted to remove gravity
        Serial.print("areal\t");
        Serial.print(time / 1000000.0, 6);
        Serial.print("\t");
        Serial.print(aaReal.x);
        Serial.print("\t");
        Serial.print(aaReal.y);
        Serial.print("\t");
        Serial.println(aaReal.z);
#endif

#ifdef OUTPUT_READABLE_WORLDACCEL
        // display initial world-frame acceleration, adjusted to remove gravity
        // and rotated based on known orientation from quaternion
        Serial.print("aWorld\t");
        Serial.print(time / 1000000.0, 6);
        Serial.print("\t");
        Serial.print(aaWorld.x);
        Serial.print("\t");
        Serial.print(aaWorld.y);
        Serial.print("\t");
        Serial.println(aaWorld.z);
#endif
        break;

      case DATA_TO_FILE: // ** Pause the program when pressing a button.  Save the results.

        // ** open file
        myFile = SD.open("test1.txt", FILE_WRITE);

        if (myFile)
        {

          // ** position at end of file to append new data
          myFile.seek(myFile.size());

#ifdef OUTPUT_READABLE_REALACCEL
          myFile.print("areal\t");
          myFile.print(time / 1000000.0, 6);
          myFile.print("\t");
          myFile.print(aaReal.x);
          myFile.print("\t");
          myFile.print(aaReal.y);
          myFile.print("\t");
          myFile.println(aaReal.z);

#endif
#ifdef OUTPUT_READABLE_WORLDACCEL
          myFile.print("aWorld\t");
          myFile.print(time / 1000000.0, 6);
          myFile.print("\t");
          myFile.print(aaWorld.x);
          myFile.print("\t");
          myFile.print(aaWorld.y);
          myFile.print("\t");
          myFile.println(aaWorld.z);
#endif

          // ** close file
          myFile.close();

        } //if

        programState = DATA_TO_SERIAL;  // ** Run the program as usual, giving the accelerations.

        break;

      default:
        break;

    } // switch

  } // if

  // blink LED to indicate activity
  blinkState = !blinkState;
  digitalWrite(LED_PIN, blinkState);
}


// ** look for valid data
bool chedkForData()
{
  bool retVal = false;

  // ** if there is data waiting
  if ( mpuInterrupt || (fifoCount >= packetSize) )
  {
    retVal = true;  // ** signal data is available

    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
      // reset so we can continue cleanly
      mpu.resetFIFO();
      Serial.println(F("FIFO overflow!"));

      retVal = false;  // ** no data after all?

      // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {

      // wait for correct available data length, should be a VERY short wait
      while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

      // read a packet from FIFO
      mpu.getFIFOBytes(fifoBuffer, packetSize);

      // track FIFO count here in case there is > 1 packet available
      // (this lets us immediately read more without waiting for an interrupt)
      fifoCount -= packetSize;

    } // else

  } // if

  return (retVal);

}