Intermittent Serial Input Data

Hello, I have a NEO6M GPS (uses UART) and a BMP180 (uses I2C) and am trying to get data from both in order. I have combined two sketches which were for the GPS and the BMP but in serial monitor, I see intermittent data. I tried adding delays, for/while commands, string combinations etc. but no solution so far. I'm attaching the code I used and the output I get. Thank you.

multi_test.ino (1.6 KB)

multi_error_2.jpg

while(gps.available()>0){
        Serial.write(gps.read());
    }

    Serial.print("relative altitude: ");
    if (a >= 0.0) Serial.print(" ");
    Serial.print(a,1);
    Serial.print(" meters, ");
    Serial.println();
    Serial.println();

in above, you only read data if it's available but you always process (i.e. print something).

why not simply

if (0 == gps.available())
    return;

Thank you for your reply gcjr! Yea, I added some more conditions and it is working fine now. But there is another issue, when the gps is not available (!gps.available()), bmp sends data continuously until the gps is available again. So, how can I make it send one data only between the gps sessions?

Here is the working code;

#include <SoftwareSerial.h>
SoftwareSerial gps(4,5);
#include <SFE_BMP180.h>
#include <Wire.h>
SFE_BMP180 pressure;

double baseline;

void setup()
{
  Serial.begin(9600);
  gps.begin(9600);

  if (pressure.begin())
    Serial.println("BMP180 init success");
  else
  { Serial.println("BMP180 init fail (disconnected?)\n\n");}

 

  baseline = getPressure();
  
  Serial.print("baseline pressure is measured as: ");
  Serial.print(baseline);
  Serial.println(" mb");  
}

void loop()
{
  
 if(gps.available()>0) {
  while(gps.available()>0){ Serial.write(gps.read());}
 }
 else {
  double a,P;
  P = getPressure();
  
  Serial.println();
  Serial.println();
  Serial.print("relative altitude: ");
  if (a >= 0.0) Serial.print(" "); 
  Serial.print(pressure.altitude(P,baseline),2);
  Serial.print(" meters, ");
  Serial.println();
  Serial.println();
   
  }
 
  }
  


double getPressure()
{
  char status;
  double T,P,p0,a;
  status = pressure.startTemperature();
  if (status != 0)
  {
    delay(status);
    status = pressure.getTemperature(T);
    if (status != 0)
    {
      status = pressure.startPressure(3);
      if (status != 0)
      {
        delay(status);

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          return(P);
        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");
}

multi_ok.jpg

This

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

functions the same as

 while(gps.available()>0){ Serial.write(gps.read());}

There is no need to duplicate the conditional test that the while statement performs at the beginning of the code block.

aarg:
This

 if(gps.available()>0) {

while(gps.available()>0){ Serial.write(gps.read());}
}



functions the same as


while(gps.available()>0){ Serial.write(gps.read());}




There is no need to duplicate the conditional test that the while statement performs at the beginning of the code block.

Hi aarg, thanks for the reply. I know that, and it is just right. But somehow, the program did not work as it should until I used that if statement, which made me ask you about it here. Furthermore, it works now! That's typical of programming, isn't it :slight_smile: It might require much deeper knowledge about microcontrollers, C etc. So, it is beyond me for now :slight_smile:

I knew that the if statement alone would not work since the serial channel opens and closes several times during the data transmitting of a package (which comes once a second from the GPS), and if I used the if statement, I would get the first a few lines (maybe less) of the data only. Nevertheless, while statement may not work as well when the time gap between those serial channel openings get too long (according to my experiences, I am not an expert). I do not know how an adjustment I should make here... As a half-engineer, if it should work, and if it works somehow, then no problem for me :slight_smile: But as a quarter-mathematician, I need to know what is behind all this...

I made a huge research on my problems but could find almost nothing. So, I felt like I am the only one who lives these problems. And I humbly ask you to give any information you know about this topic to help people who deal with this. Thank you :slight_smile:

yusufbudakli:
I knew that the if statement alone would not work since the serial channel opens and closes several times during the data transmitting of a package (which comes once a second from the GPS), and if I used the if statement, I would get the first a few lines (maybe less) of the data only.

the code does not receive data only while available() is called. Lower level firmware/hardware captures data when it is present. available() indicates whether data is available to read from the capture buffer.

gcjr:
the code does not receive data only while available() is called. Lower level firmware/hardware captures data when it is present. available() indicates whether data is available to read from the capture buffer.

So, how much data can that buffer contain? I think that is why the GPS data comes partly. But, while the "capture buffer" is transmitting what it has, then how can it receive new data from the sensor? Is not it half duplex communication between the buffer and sensor or between the buffer and processor?

There are buffers for Serial data for incoming and outgoing data. They are 64 bytes each. I assume the same is true of SoftwareSerial.

If the outgoing buffer is full, your program will block until there is some space. Since you are printing a fair bit, it would be a good idea to increase the baud rate.

Delays don't help either and there are several in your getPressure function.

To get less data from the bmp, look at the blink without delay example in the IDE and use millis and read it less frequently.

wildbill:
There are buffers for Serial data for incoming and outgoing data. They are 64 bytes each. I assume the same is true of SoftwareSerial.

If the outgoing buffer is full, your program will block until there is some space. Since you are printing a fair bit, it would be a good idea to increase the baud rate.

Delays don't help either and there are several in your getPressure function.

To get less data from the bmp, look at the blink without delay example in the IDE and use millis and read it less frequently.

Hello wildbill, thanks for your reply and the information. I tried what you said, it is okay but has an issue. The GPS data intervals are not constant and when I use the millis function, it causes intermittent data again because of I cannot adjust the millis interval dynamically. The program works correct for several seconds, not more (issue can be seen in the image attached). I need a program that is fully dependent to the GPS, so, I think I can never achieve what I want by makeshift... I also tried interrupt function but it did not work at all, no GPS data seemed on serial monitor and I don't know why.

Here is the code that works, but is a makeshift;

#include <SoftwareSerial.h>
#include <SFE_BMP180.h>
#include <Wire.h>
SFE_BMP180 pressure;
SoftwareSerial gps(2,3);

double baseline;

unsigned long previousMillis = 0;
const long interval = 1000;

void setup()
{
  Serial.begin(115200);
  gps.begin(9600);

  if (pressure.begin())
    Serial.println("BMP180 init success");
  else
  { Serial.println("BMP180 init fail (disconnected?)\n\n");
    }

 

  baseline = getPressure();
  
  Serial.print("baseline pressure is measured as: ");
  Serial.print(baseline);
  Serial.println(" mb");  
}

void loop()
{
  
  while(gps.available()>0){Serial.write(gps.read());}
  
  if (0 == gps.available()) {
  double a,P;
  unsigned long currentMillis = millis();
  P = getPressure();

  if (currentMillis - previousMillis >= interval) {
    
    previousMillis = currentMillis;

    Serial.println();
  Serial.println();
  Serial.print("relative altitude: ");
  if (a >= 0.0) Serial.print(" "); 
  Serial.print(pressure.altitude(P,baseline),2); //the second parameter adjusts the number of decimal digit
  Serial.print(" meters, ");
  Serial.println();
  Serial.println();
    
                                                  }
                          }
}
  


double getPressure()
{
  char status;
  double T,P,p0,a;
  status = pressure.startTemperature();
  if (status != 0)
  {
    delay(status);
    status = pressure.getTemperature(T);
    if (status != 0)
    {
      status = pressure.startPressure(3);
        if (status != 0)
      {
        delay(status);

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          return(P);
        }
        else Serial.println("error retrieving pressure measurement\n");
      }
      else Serial.println("error starting pressure measurement\n");
    }
    else Serial.println("error retrieving temperature measurement\n");
  }
  else Serial.println("error starting temperature measurement\n");
}

multi_error_3.jpg

yusuf

there are various issues with your code. suggest you look at the following

  • in your code there's no need to test for 0 == gps.available(). if gps is available, read it. if not just test if the time is expired

  • gps.read() will read whatever is transmitted, regardless if it's a hex or ascii value. and Serial.write will do the same, meaning a value of 0 is 0x30 (see ascii

  • not sure where the value of "a" is set

  • the nested if statements in getPressure() is awkward.

  • in getPressure() you call delay() with the value of status. status is likely to be 0 or 1.

also bear in mind that at 9600 bps, i takes ~1 msec per character. loop() runs many times within a msec and it is unlikely that that you will receive more than 1 character each time loop() runs.

#include <SoftwareSerial.h>
#include <SFE_BMP180.h>
#include <Wire.h>
SFE_BMP180 pressure;
SoftwareSerial gps(2,3);


double baseline;
unsigned long previousMillis = 0;
const long interval = 1000;

void setup()
{
    Serial.begin(115200);
    gps.begin(9600);

    if (pressure.begin())
        Serial.println("BMP180 init success");
    else
        Serial.println("BMP180 init fail (disconnected?)\n\n");

    baseline = getPressure();
    Serial.print("baseline pressure is measured as: ");
    Serial.print(baseline);
    Serial.println(" mb");
}

void loop()
{
    if (gps.available())  {
        Serial.println (gps.read());
    }

    double a,P;
    unsigned long currentMillis = millis();

    P = getPressure();

    if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;

        Serial.print("relative altitude: ");
        if (a >= 0.0)
            Serial.print(" ");

        Serial.println (pressure.altitude(P,baseline),2);
    }
}

double getPressure()
{
    double T,P;

    if (0 == pressure.startTemperature())  {
        Serial.println("error starting temperature measurement\n");
        return 0;
    }

    if (0 == pressure.getTemperature(T))  {
        Serial.println("error retrieving temperature measurement\n");
        return 0;
    }

    if (0 == pressure.startPressure(3))  {
        Serial.println("error starting pressure measurement\n");
        return 0;
    }

    if (0 == pressure.getPressure(P,T))  {
        Serial.println("error retrieving pressure measurement\n");
        return 0;
    }

    return(P);
}

gcjr:
yusuf

there are various issues with your code. suggest you look at the following

  • in your code there's no need to test for 0 == gps.available(). if gps is available, read it. if not just test if the time is expired

  • gps.read() will read whatever is transmitted, regardless if it's a hex or ascii value. and Serial.write will do the same, meaning a value of 0 is 0x30 (see ascii

  • not sure where the value of "a" is set

  • the nested if statements in getPressure() is awkward.

  • in getPressure() you call delay() with the value of status. status is likely to be 0 or 1.

also bear in mind that at 9600 bps, i takes ~1 msec per character. loop() runs many times within a msec and it is unlikely that that you will receive more than 1 character each time loop() runs.

#include <SoftwareSerial.h>

#include <SFE_BMP180.h>
#include <Wire.h>
SFE_BMP180 pressure;
SoftwareSerial gps(2,3);

double baseline;
unsigned long previousMillis = 0;
const long interval = 1000;

void setup()
{
    Serial.begin(115200);
    gps.begin(9600);

if (pressure.begin())
        Serial.println("BMP180 init success");
    else
        Serial.println("BMP180 init fail (disconnected?)\n\n");

baseline = getPressure();
    Serial.print("baseline pressure is measured as: ");
    Serial.print(baseline);
    Serial.println(" mb");
}

void loop()
{
    if (gps.available())  {
        Serial.println (gps.read());
    }

double a,P;
    unsigned long currentMillis = millis();

P = getPressure();

if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;

Serial.print("relative altitude: ");
        if (a >= 0.0)
            Serial.print(" ");

Serial.println (pressure.altitude(P,baseline),2);
    }
}

double getPressure()
{
    double T,P;

if (0 == pressure.startTemperature())  {
        Serial.println("error starting temperature measurement\n");
        return 0;
    }

if (0 == pressure.getTemperature(T))  {
        Serial.println("error retrieving temperature measurement\n");
        return 0;
    }

if (0 == pressure.startPressure(3))  {
        Serial.println("error starting pressure measurement\n");
        return 0;
    }

if (0 == pressure.getPressure(P,T))  {
        Serial.println("error retrieving pressure measurement\n");
        return 0;
    }

return(P);
}

Thank you gcjr, I appreciate. I know that there were some logically wrong parts in the code but why I did it is because of the code itself which did not do what it is supposed to do... Or, I might be just a bit tired :slight_smile: Now I have something that works quite good, not perfect though, and I will stop here because I have much more to do and to deal with... I am adding my code here so that new newbies can find what they need quicker. I made some editing and it looks okay for now. Nevertheless, if anything is wrong or can be better, please let me know and I will try to get it better. Thank you for all your helps and understandings :slight_smile:

#include <SoftwareSerial.h>
#include <Adafruit_BMP085.h>
#include <Wire.h>

Adafruit_BMP085 bmp;
SoftwareSerial gps(2,3);

unsigned long previousMillis = 0;
const long interval = 1000;

#define BuzzerPin  11


void setup()
{
  gps.begin(9600);
  
  pinMode(BuzzerPin, OUTPUT);
  digitalWrite(BuzzerPin, LOW);

  if (bmp.begin()) {
    Serial.println("BMP180 initialization successfull");
    digitalWrite(BuzzerPin, HIGH);
    delay(100);
    digitalWrite(BuzzerPin, LOW);
    delay(100);
    digitalWrite(BuzzerPin, HIGH);
    delay(100);
    digitalWrite(BuzzerPin, LOW);
                    }
  else {
  Serial.println("Could not find a valid BMP180 sensor, check wiring!");
  digitalWrite(BuzzerPin, HIGH);
  delay(500);
  digitalWrite(BuzzerPin, LOW);
       }

  Serial.begin(9600);
}

void loop()
{
  Serial.flush();
  while(gps.available()>0){Serial.write(gps.read());}
  
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    
    previousMillis = currentMillis;

    Serial.println();
    Serial.println();
    Serial.print("Altitude = ");
    Serial.print(bmp.readAltitude());
    Serial.println(" meters");
    Serial.println();
    Serial.println();
    
                                                  }
}
  Serial.flush();

Why? What do you think it does?

aarg:

  Serial.flush();

Why? What do you think it does?

Actually I used it to clean the buffer so that I can get clean data but I think I should put it after the GPS reading. Anyway, it was working great yesterday but does not work today again. I cannot understand how it did work yesterday and does not today! It started to be annoying... I just want to get all data GPS sends and one data BMP sends every second. Should it be this hard? I have looked almost every code of Arduino that I thought might help, I am in this for a week...