GPS NEO 6M - delay data writing

Good morning everyone!
I am working with an arduino mega 2560 board and various sensors to monitor the environment, among them I also have a gps, model Neo 6M.
All the sensors write their data to a csv file on the sd card.

This is the code I have implemented:

#include <Wire.h>
#include <MPU6050_tockn.h>
#include <SoftwareSerial.h>
#include <SdsDustSensor.h>
#include <SPI.h>
#include <SD.h>
#include <TinyGPS.h>

//define per il misuratore dB
#define SoundSensorPin A3  //this pin read the analog voltage from the sound level meter
#define VREF  5.0  //voltage on AREF pin,default:operating voltage

//variabili per sensore CO2,NH3,NO2
const int S_analog = 1023.0;
int co, nh3;
float no2;

//variabili per sensore accelerometro/giroscopio
const int MPU = 0x68;  // I2C address of the MPU-6050
float AccX, AccY, AccZ, Tmp, AngX, AngY, AngZ;
float temp;
MPU6050 mpu6050(Wire);
unsigned long t1, dt;

//variabili per senosre GPS
float lat, lon;
TinyGPS gps;  // create gps object

//variabili per sensore PM10 PM2.5
int rxPin = 16;
int txPin = 17;
SdsDustSensor sds(Serial2);

//variabili per SD Card
File file;
const int chipSelect = 53;

//variabili per misuratore dB
float voltageValue, dbValue;

void setup() {
  //Serial.begin(9600);  // comune a tutti
  Serial.begin(9600);

  // acc/giroscopio
  Wire.begin();
  mpu6050.begin();
  //fase di calibrazione per il giroscopio
  mpu6050.calcGyroOffsets(true);

  // gps
  Serial.println("The GPS Received Signal:");
  Serial3.begin(9600);  // connect gps sensor

  // pm10 pm2.5
  sds.begin();
  Serial2.begin(9600);

}

void loop() {
  MICS6814();
  Accelerometro_Giroscopio();
  GPS();
  //PM10_PM25();
  Sound();
  SD_Card();

  //delay(1000);
}

void MICS6814() {
  co = map(analogRead(A2), 0, S_analog, 1, 1000);           //monossido di carbonio
  nh3 = map(analogRead(A1), 0, S_analog, 1, 500);           //ammoniaca
  no2 = map(analogRead(A0), 0, S_analog, 5, 1000) / 100.0;  //diossido di azoto

  //stampo i dati sul monossido di carbonio registrato
  //Serial.print("CO: ");
  //Serial.print(co);
  //Serial.print(",");
  //Serial.print(" ppm\t ");

  //stampo i dati sull'ammoniaca registrata
  //Serial.print("NH3: ");
  //Serial.print(nh3);
  //Serial.print(",");
  //Serial.print(" ppm\t ");

  //stampo i dati sul diossido di azoto registrato
  //Serial.print("NO2: ");
  //Serial.print(no2);
  //Serial.print(",");
  //Serial.println("");
  //Serial.print(" ppm\n");

  //delay(1000);
}

void Accelerometro_Giroscopio() {

  mpu6050.update();
  dt = millis() - t1;
  if (dt > 200) {
    t1 = millis();
    AccX = mpu6050.getAccX();
    AccY = mpu6050.getAccY();
    AccZ = mpu6050.getAccZ();
    // angoli calcolati dal sw interno del sensore, non sono direttamente quelli misurati dal sensore
    AngX = mpu6050.getAngleX();
    //Serial.println(AngX);
    AngY = mpu6050.getAngleY();
    //Serial.println(AngY);
    AngZ = mpu6050.getAngleZ();
    //Serial.println(AngZ);
    temp = mpu6050.getTemp();
  }
  //delay(1000);
}

void GPS() {

  while (Serial3.available()) {  // check for gps data
    //Serial.print("A");
    if (gps.encode(Serial3.read()))  // encode gps data
    {
      //Serial.print("B");
      gps.f_get_position(&lat, &lon);  // get latitude and longitude

      //Latitude
      // Serial.print("Latitude: ");
      // Serial.print(lat,6);

      // Serial.print(",");

      // //Longitude
      // Serial.print("Longitude: ");
      // Serial.println(lon,6);
    }
  }
  //delay(1000);
}

/*
void PM10_PM25() {
  PmResult pm = sds.readPm();

  //if (pm.isOk()) {
    // stampo PM2.5
    //Serial.print("PM2.5 = ");
    //Serial.print(pm.pm25);

   //stampo PM10
    //Serial.print(" PM10 = \n");
    //Serial.print(pm.pm10);
    //Serial.print("\n");
  //}

  //delay(1000);
}*/

void Sound() {
  voltageValue = analogRead(SoundSensorPin) / 1024.0 * VREF;
  dbValue = voltageValue * 50.0;  //convert voltage to decibel value

  //delay(1000);
}

void SD_Card() {

  if (!SD.begin(chipSelect)) {
    Serial.println("Errore");
    return;
  }

  PmResult pm = sds.readPm();
  file = SD.open("datalog.csv", FILE_WRITE);

  if (file) {
    // faccio questo per eviatre che nel csv mi vengano stampati dei valori sballati del pm10 e pm2.5....
    if (pm.isOk()) {
      file.print(no2);
      file.print(";");
      file.print(nh3);
      file.print(";");
      file.print(co);
      file.print(";");
      file.print(pm.pm10);
      file.print(";");
      file.print(pm.pm25);
      file.print(";");
      file.print(lat,5);
      file.print(";");
      file.print(lon,5);
      file.print(";");
      file.print(AccX);
      file.print(";");
      file.print(AccY);
      file.print(";");
      file.print(AccZ);
      file.print(";");
      file.print(AngX);
      file.print(";");
      file.print(AngY);
      file.print(";");
      file.print(AngZ);
      file.print(";");
      file.print(temp);
      file.print(";");
      file.print(dbValue);
      file.println();

    }

    file.close();
    
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }

  //delay(500);
}

I would like all the sensors to write to the sd card every 1 or 2 seconds.
If I put 'delay(1000)' at the end of the functions, the gps does NOT write anything to the csv file, the other sensors instead write the data correctly.
Does anyone know why?
Thank you very much.

This problem is not easy to resolve. It really needs a complete understanding of how gps.encode works in detail. In particular, how it responds to overflow of the Serial3 buffer.

You need to have an accurate measure of how much time it takes to service each of the connected devices. That's not hard to measure.

The other sensors can be interrogated at any time and your sketch can access their values without a problem as they are simply always available to be read. But GPS isn't like that. You have to start "listening" to it from before its output phase starts and the serial buffer must be initially empty. When the sketch you are using calls gps.encode, the GPS could be in the middle of its output phase so you miss the data you want.

I would always get the GPS data BEFORE reading the other sensors. You need to be in control of exactly when you call gps.encode in relation to the GPS output phase.

I can use this code within each individual function to calculate the time required for each sensor:

void FUNCTION() {
 uint32_t StartmS = millis();
----- do something------
  Serial.print("function() takes ");
  Serial.print(millis() - StartmS);
  Serial.println("mS");
}

is that OK?

Yep, that's the idea. Get into the habit of making your print statements as brief as possible. Just print the duration value without the "function() takes ". You know what it means. All these things take significant time.

The GPS output phase takes about 500ms at 9600 baud rate. Your aim is to start reading the output from its beginning and use the remaining 500ms to read the other sensors and process the data and write to the file. Then the GPS output starts again. Can you read the sensors and write the data inside 500ms?

then, calculating the time required for each sensor, I can tell you that:
the gps takes 1/2 ms (sometimes even 0 ms)
mics6814 sensor : 1/2 ms
accelerometer sensor : 2/3 ms
microphone sensor : 13ms
sensor for writing to sd card : 30/32ms

You might read a sentence in that time from the GPS, but only if the entire sentence is in the buffer, which wont happen all the time.

But how do you know that the GPS sentence read (in 0.5mS ???) actually contains any useful information such as an updated location ?

The gps receiver sends out a single character in 1ms.

HillmanImp was correct in post #4 when he said:

The GPS output phase takes about 500ms at 9600 baud rate.

Looks like it takes very little time to read the sensors and only writing to the sd card is significant, but not much.

We know the GPS puts out at about 1 byte per ms, so when it has a fix there will be about 500 bytes taking 500ms. JohnLincoln's oscilliscope screenshot above is proof of that.

Try inserting the following piece of code at the end of your setup section. It will continuously send the GPS bytes to your monitor. Activate the timestamp in the monitor to get an idea of how long it takes.

while (true){
if (Serial3.available()>0) Serial.write(Serial3.read());
}

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