Why does the variable `char c`produce a long string of characters?

I am playing around with an Adafruit Ultimate GPS, and I'm testing their excellent example code. But I don't understand how this section of the code works:

void loop()                     // run over and over again
{
  char c = GPS.read();
  // if you want to debug, this is a good time to do it!
  if ((c) && (GPSECHO))
    Serial.write(c);

A char is supposed to be one, single character, isn't it? But the code above will spit out the entire, raw NMEA-message, and correctly too. Is the loop function simply creating a new variable c and writing out one single character of the total message the GPS-module dumps to my arduino?

And if that is the case, what is the appropriate way of producing a string object of the GPS-message that can be stored and subjected to further processing? The Adafruit library has a couple of nifty parsing functions, but I need to treat my data somewhat differently from what they are doing, and want to make my own parser. Besides, that's more fun...

The minature bit of code you posted appears to read one character form the GPS and send it to the Serial monitor, so you would expect a 'stream' of characters to be printed in loop() .......

But you do! loop() loops, by the hidden mechanism that calls it over and over, so that code looks like it prints one character per. Loop.

Check out "serial input basics" here

a7

1 Like

void loop() // run over and over again

Maybe that has something to do with it?
You read a character, print it, and repeat.

Or check out www.snippets-r-us.com

how do you know if there is something available to read?

is there a GPS.available()?

The read() method returns 0 (zero) when there is no character and for a few other reasons

a7

1 Like

Nope. Zero (0) is a valid byte. read() returns -1 when there are no characters in the buffer.


Read this in a hurry, jumped to a conclusion:


char Adafruit_GPS::read(void) {
  static uint32_t firstChar = 0; // first character received in current sentence
  uint32_t tStart = millis();    // as close as we can get to time char was sent
  char c = 0;

  if (paused || noComms)
    return c;

#if (defined(__AVR__) || defined(ESP8266)) && defined(USE_SW_SERIAL)
  if (gpsSwSerial) {
    if (!gpsSwSerial->available())
      return c;
    c = gpsSwSerial->read();
  }
#endif

a7

How dare they (Adafruit) call this function read() and return a char only.

Serial.write((char)0); produces something looking like a space, in wokwi simulation. On a real Arduino Serial Monitor (1.8.19) shows nothing.

So all is explainable and fine. Thanks, @alto777 .

Actually, I was referring to read() in general as a function of the Stream class. It returns an 'int':

class Stream : public Print
{
  protected:
    unsigned long _timeout;      // number of milliseconds to wait for the next char before aborting timed read
    unsigned long _startMillis;  // used for timeout measurement
    int timedRead();    // read stream with timeout
    int timedPeek();    // peek stream with timeout
    int peekNextDigit(LookaheadMode lookahead, bool detectDecimal); // returns the next numeric digit in the stream or -1 if timeout

  public:
    virtual int available() = 0;
    virtual int read() = 0;
    virtual int peek() = 0;

Interesting. Your code avoids doing anything when read() signals the absence of a character (by returning 0, also known as false) and using that in the if statement.

I can't explain why the wokwi would be different to real life, but want to. :expressionless:

The wokwi has been so faithful!

a7

SerialMonitor is different to real life as well, perhaps
:grin:

Thanks, that explains a lot! :grinning:

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