Beginner- reading and decoding serial GPS data

Hi all,

I'm working on a copy of the "Frustromantic Box" (http://newbrightidea.com/?p=63) and I'm running into trouble getting useful GPS data out of the module.

I've got a bit of test code my friend found (I can't find the original source):

#define bit9600Delay 84
#define halfBit9600Delay 42
#define bit4800Delay 188
#define halfBit4800Delay 94
...
char SWread()
{
  byte val = 0;
  while (digitalRead(rx)); //wait for start bit
  if (digitalRead(rx) == LOW) {
    delayMicroseconds(halfBit9600Delay);
    for (int offset = 0; offset < 8; offset++) {
      delayMicroseconds(bit9600Delay);
      val |= digitalRead(rx) << offset;
    }
    //wait for stop bit + extra
    delayMicroseconds(bit9600Delay);
    delayMicroseconds(bit9600Delay);
    return val;
  }
}

I don't have much information to give other than:

  1. GPS light is almost always steady on (manual says this means it's searching). Occasionally it will blink (position lock). I've got nothing but the sky above me, so I don't know why it wouldn't find a signal, I'll just assume that it is.

  2. I'm pretty sure the GPS is outputting at 9600 baud, 8 data bits, 0 stop, no parity. However, this little sample code above only shows stuff when I set it to listen at 4800 baud... I've played around with the two delay statements near the end, trying neither, one, or both to see if I've got the stop or parity bit wrong, but to no avail.

  3. The output from this sample code looks quite irregular (it doesn't parse NMEA, but the raw stuff doesn't look valid). In hex, I'm getting stuff like FFFFFF93 FFFFFF98 26 2F 6 16 2C D 19 2C 19 6C 19 78 but it repeats forever (not the same string) without any regular structure.

  4. All I know from the frustromantic code is that the gps library isn't reading valid NMEA data.

Not much to go on, I'm afraid, but maybe there's a chance somebody recognizes what problem causes nasty output like this?

Thanks!

FFFFFFB3 63 FFFFFFE5 FFFFFFFE 64 34 FFFFFF87 73 FFFFFF9B FFFFFF97 19 2C 19 30 19 70 19 6C 1A 30 19 6C 1A 6C 33 30 33 75 FFFFFFB3 FFFFFF83 FFFFFF96 19 6C 19 6C 19 2C 19 6C 19 6C FFFFFF99

I'm getting stuff like FFFFFF93 FFFFFF98 26 2F 6 16 2C D 19 2C 19 6C

Can't help with details of your hardware, but I think I can explain the output you see:

Are you printing with something like Serial.print(ch. HEX) where ch is a (signed) char?

What happens is that the char is "promoted" to a long int by sign extension, so any char whose most significant bit is '1' shows up with the six spurious 'f' things in front.

Solution: Either declare the array as unsigned char (Arduino byte):

   byte ch[] = {'\x12', '\x98', '\x3'};
   int i;
  
   for (i = 0; i < sizeof(ch); i++) {
     Serial.print("   ch[");
     Serial.print(i);     Serial.print("] = ");
     Serial.println(ch[i], HEX);
   }

Or
Cast the char to unsigned char or byte in the function call:

   char ch[] = {'\x12', '\x98', '\x3'};
   int i;
  
   for (i = 0; i < sizeof(ch); i++) {
     Serial.print("   ch[");
     Serial.print(i);     Serial.print("] = ");
     Serial.println((byte)ch[i], HEX);
   }

Output for either:

  ch[0] = 12
  ch[1] = 98
  ch[2] = 3

On the other hand, with char and no cast:

   char ch[] = {'\x12', '\x98', '\x3'};
   int i;
   for (i = 0; i < sizeof(ch); i++) {
     Serial.print("   ch[");
     Serial.print(i);     Serial.print("] = ");
     Serial.println(ch[i],HEX);

Output

   ch[0] = 12
   ch[1] = FFFFFF98
   ch[2] = 3

Bottom line: If you are going to print eight-bit data items that are not ASCII printing chars, print them as byte data types, not char.

If this doesn't help (or it doesn't make sense), then post the exact code that actually creates those output numbers. (That is: Show the variable declarations and the print statement.)

Regards,

Dave

It looks like in SWread, the data is treated as a byte, and when I print it, I treat it as hex:

Serial.print(SWread(),HEX);

I once tried printing as char, and I got a bunch of unrecognizable letters.

In the Frustromantic code, it looks like this:

...
    if (nss.available())   //nss is an instance of NewSoftSerial
    {
      Serial.print("hey"); //added for debugging
      int c = nss.read();
      Serial.print(c);     //added for debugging
      if (gps.encode(c))   //gps is an instance of TinyGPS
      {
        ...

Weirdly, in this code, it won't even pass the nss.available() stage.
I'm pretty sure I've got the RX/TX pins correct (though I don't see anything about stop or parity bits).

Anyway, thanks for your help. Do you know of any other code that might decode NMEA data over a serial connection and work pretty much out-of-the-box?