Issue with boolean flag being reset

Howdy,

I’m having an issue with my code on a boolean flag getting reset for an unknow reason. I’m gathering data from a MPU9250 and writing to a SD drive. I first press a button to start gathering which sets gatherFlag to true. If I press the button again, it sets gatherFlag to false. When I press the button the first time to turn gatherFlag on, it turns on and gathers data for one loop. However, gatherFlag becomes false at the end of the loop. There is no code to set gatherFlag other than in the button routine. To make it more confusing, I put some debug text at the top of the loop to check if gatherFlag is true, if so, print a message to Serial. Just by putting this code in, the code now works properly. I commented the debug text out, and it stopped working again. Any help would be appreciated.

Thanks,

Amphey

#include "MPU9250.h"
#include <SD.h>
#include <SPI.h>

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;
int dummy;
File file;
char strBuff[10];
//char valueString[100];
const int buttonPin = 9;
const int ledPin = 7;
int buttonState = 0;
bool gatherFlag;
char fileName[13];
int fnCounter = 10;
char fnToString[10];

void setup() {
  // serial to display data
  Serial.begin(115200);
  while(!Serial) {}

  // start communication with IMU 
  status = IMU.begin();
  if (status < 0) {
    dummy = IMU.calibrateGyro();
    Serial.println("IMU Bad");
    Serial.println("Check");
    Serial.print("Status: ");
    Serial.println(status);
    while(1) {}
  }
  // Set up and start communication with the SD card.
    if (!SD.begin(4)) {
    Serial.println("Int SD Bad");
    return;
  }

  Serial.println("Int SD Good");
//  Serial.println("Creating File...");
//  file = SD.open("data03.txt", FILE_WRITE);
//  if (!file){
//    Serial.println("Fil cr f");
//  }
//  file.close();

  //set up button pin.
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);

}

void loop() {
  //DEBUG TEXT
    if (true == gatherFlag){
      Serial.println("Top, TOP Gather ON");
    }
  
  // Read the button state (pressed or not pressed)
  buttonState = digitalRead(buttonPin);
  if (buttonState){
    delay(5); //Account for bounce
    buttonState = digitalRead(buttonPin);
    delay(1000);
    if (buttonState){
      Serial.println("Button ON");
      if (!gatherFlag){
        gatherFlag = true;  //Set the gathering flag on
        digitalWrite(ledPin, HIGH);  //Turn on the LED
        itoa(fnCounter++, fnToString, 8);  //Create the next file name
        strcpy(fileName, "data");
        strcat(fileName, fnToString);
        strcat(fileName, ".txt");
        file = SD.open(fileName, FILE_WRITE);  //Create the new file
        Serial.println(fileName);
      }  
      else {
        gatherFlag = false;  //Set the gathering flag off
        digitalWrite(ledPin, LOW);  //Turn off the LED
        file.close();  //Close the current file as we are done gathering data
      }  
    }
  }


    //DEBUG TEXT
    Serial.println(freeRam());
    if (true == gatherFlag){
      Serial.println("Top Gather ON");
    }

  //If the gather flag is on, start gathering data and print to console  
  if (true == gatherFlag){
    // read the sensor
    IMU.readSensor();
    // display the data
    Serial.print("AX:");
    Serial.print(IMU.getAccelX_mss(),6);
    Serial.print("\t");
    Serial.print("AY:");
    Serial.print(IMU.getAccelY_mss(),6);
    Serial.print("\t");
    Serial.print("AZ");
    Serial.print(IMU.getAccelZ_mss(),6);
    Serial.print("\t");
    Serial.print("GX:");
    Serial.print(IMU.getGyroX_rads(),6);
    Serial.print("\t");
    Serial.print("GY:");
    Serial.print(IMU.getGyroY_rads(),6);
    Serial.print("\t");
    Serial.print("GZ:");
    Serial.print(IMU.getGyroZ_rads(),6);
    Serial.print("\t");
    Serial.print("MX:");
    Serial.print(IMU.getMagX_uT(),6);
    Serial.print("\t");
    Serial.print("MY:");
    Serial.print(IMU.getMagY_uT(),6);
    Serial.print("\t");
    Serial.print("MZ:");
    Serial.print(IMU.getMagZ_uT(),6);
    Serial.print("\t");
    Serial.println(IMU.getTemperature_C(),6);

    //DEBUG TEXT
    Serial.println(freeRam());
    
    //Check to see if the file is open and valid
    if (!file)
      Serial.println("FFOW");

    // Output to file.
    file.print("AX:");
    dtostrf(IMU.getAccelX_mss(),10,6,strBuff);
    file.print(strBuff);
    file.print("\t");
    file.print("AY:");
    dtostrf(IMU.getAccelY_mss(),10,6,strBuff);
    file.print(strBuff);
    file.print("\t");
    file.print("AZ:");
    dtostrf(IMU.getAccelZ_mss(),10,6,strBuff);
    file.print(strBuff);
    file.print("\t");
    file.print("GX:");
    dtostrf(IMU.getGyroX_rads(),10,6,strBuff);
    file.print(strBuff);  
    file.print("\t");
    file.print("GY:");
    dtostrf(IMU.getGyroY_rads(),10,6,strBuff);
    file.print(strBuff);
    file.print("\t");
    file.print("GZ:");
    dtostrf(IMU.getGyroZ_rads(),10,6,strBuff);
    file.print(strBuff);
    file.print("\t");
    file.print("MX:");
    dtostrf(IMU.getMagX_uT(),10,6,strBuff);
    file.print(strBuff);  
    file.print("\t");
    file.print("MY:");
    dtostrf(IMU.getMagY_uT(),10,6,strBuff);
    file.print(strBuff);
    file.print("\t");
    file.print("MZ:");
    dtostrf(IMU.getMagZ_uT(),10,6,strBuff);
    file.print(strBuff);
    file.print("\t");
    file.print("T:");
    file.println(IMU.getTemperature_C(),6);
    file.println();

  
    
    //DEBUG TEXT
      if (gatherFlag == true)
    Serial.println("GF ON");
  else
    Serial.println("GF NOT ON");
  }

  //Delay between gathers
  delay(1000);
}

//Get the free RAM on the Nano
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

This is problematic:

Amphey:

char strBuff[10];

...

dtostrf(IMU.getAccelX_mss(),10,6,strBuff);
    file.print(strBuff);

The width parameter of dtostrf is the minimum width of the produced string. You only sized strBuff to 10 elements, so that leaves no room for the null terminator. That can result in some undefined behavior.

Awesome, looks like that worked. Do you only need one byte for the null terminator?

Thanks for your help!

Amphey

Do you only need one byte for the null terminator?

The NULL is a character. So, you need room for one more character. No more. No less.

Endless headaches have been caused over the years by not accounting for that null terminator. I know I've had my share.

I find it confusing that dtostrf has a minimum width. I'd expect the width to be a maximum, to ensure that it never writes past the end of the buffer. The maximum length parameter is something provided by many C++ cstring functions. I'm not aware of any of the similar standard C++ number to text conversion functions that allow a minimum width to be specified.