Listen Garmin 18x5hz

Hello everybody!

As very often, it’s in extreme cases of nervous brakedown i’m writing these lines?

During last days, I worked with my pretty module garmin in order to getback his NMEA sequence in my terminal.
I tried every hardware configurations, with a max232 then a 74F04 (simpler) to reverse the signal coming from the module and tinyGPS and newSoftserial for the software part.

I’m very close from something good but it’s still a little bit garbage…
I think finally it’s a serialport speed problem
This is “my” code (thanks to dirk):

//Created August 15 2006
//Heather Dewey-Hagborg
//http://www.arduino.cc
//reworked to GPS reader
//Dirk, december 2006

#include <ctype.h>
#include <string.h>

#define bit38400Delay ??
#define halfBit38400Delay ?
#define bit9600Delay 84
#define halfBit9600Delay 42
#define bit4800Delay 188
#define halfBit4800Delay 94

byte rx = 2; //byte
byte tx = 3;
byte SWval;
char dataformat[7] = "$GPRMC";
char messageline[80] = "";
int i= 0;

void setup() {
  pinMode(rx,INPUT);
  pinMode(tx,OUTPUT);
  digitalWrite(tx,HIGH);
  digitalWrite(13,HIGH); //turn on debugging LED
  SWprint('h');  //debugging hello
  SWprint('i');
  SWprint(10); //carriage return
  Serial.begin(38400);  // this is used to echo what is read from the GPS out the USB->SerialDebugMonitor
}

void SWprint(int data)
{
  byte mask;
  //startbit
  digitalWrite(tx,LOW);
  delayMicroseconds(bit4800Delay);
  for (mask = 0x01; mask>0; mask <<= 1) {
    if (data & mask){ // choose bit
      digitalWrite(tx,HIGH); // send 1
    }
    else{
      digitalWrite(tx,LOW); // send 0
    }
    delayMicroseconds(bit4800Delay);
  }
  //stop bit
  digitalWrite(tx, HIGH);
  delayMicroseconds(bit4800Delay);
}

char SWread()
{
  byte val = 0;
  while (digitalRead(rx));
  //wait for start bit
  if (digitalRead(rx) == LOW) {
    delayMicroseconds(halfBit4800Delay);
    for (int offset = 0; offset < 8; offset++) {
      delayMicroseconds(bit4800Delay);
      val |= digitalRead(rx) << offset;
    }
    //wait for stop bit + extra
    delayMicroseconds(bit4800Delay);
    delayMicroseconds(bit4800Delay);
    return val & 0x7f; // return val 

  }
}
void char2string()
{
  i = 0;
  messageline[0] = SWread();
  if (messageline[0] == 36) //string starts with $
  {
    i++;
    messageline[i] = SWread();
    while(messageline[i] != 13 & i<80) //carriage return or max size
    {
      i++;
      messageline[i] = SWread();
    }
    messageline[i+1] = 0; //make end to string
  }
}

void loop()
{
  digitalWrite(13,HIGH);

  //
  // 1st way to print only the $GPRMC message
  //

  //only print string with the right dataformat
   char2string();
  if (strncmp(messageline, dataformat, 6) == 0 & i>4)
  {
   for (int i=0; messageline[i] != '\0'; i++)
   {
        Serial.print(messageline[i], BYTE);
     }
   }

  //
  // 2nd way to print only the $GPRMC message
  //

  //   char2string();
  //   if (strncmp(messageline, dataformat, 6) == 0 & i>4)
  //   {
  //     Serial.println(messageline);
  //   }

  //
  // way to print ALL RECEIVED MESSAGES!
  //

  Serial.print(SWread(),BYTE); //use this to get all GPS output, comment out from char2string till here

}

I finaly understandood with the doc (http://static.garmincdn.com/pumac/GPS18x_TechnicalSpecifications.pdf) that the 18x 5hz functioned by default to 38400 giving an almost comprehensible pattern when I put the serialport to 38400 and delay on 9600?

In fact my problem could be here:

#define bit38400Delay?? 
#define halfBit38400Delay??

Someone could be able to tell me which delay I need?
If you know a better method at this speed with tinyGps I take it also! :-[

A bit delay would be 1/38400 seconds = 26 microseconds. The half bit delay would therefore be 13 microseconds, but you may have to fiddle the values slightly to account for overheads in the "delayMicroseconds" function.

It can be a little tricky, because if you have cumulative errors in your sample times, you may miss the ideal centre of the bit period towards the end of the character.

Hi Awol, Thank for your reply. I tried your timing but it didn't change anything... My theory seems to be wrong...

you may have to fiddle the values slightly to account for overheads in the "delayMicroseconds" function

God! I'm lost... I will try to adjust but i think the problem isn't here. Thank again ;)

84 microseconds for a 9600 bit period of 104 microseconds suggests an extreme ‘fiddle’.
Is this a non-standard clock?

84 microseconds for a 9600 bit period of 104 microseconds suggests an extreme 'fiddle'. Is this a non-standard clock?

Not sure what you mean... The hardware is arduino duemilanove with atmega 328 and I use a 74F04 to invert the signal on pin 2. Can't be sure about standard or non-standard clock... Forgot to say, I'm a beginner :P

If you have a standard Arduino, why are you not simply using Serial.read() and Serial.print() for input and output?

If the Arduino is a homemade breadboard affair, what crystal/resonator are you using? If it's a standard 16MHz crystal/resonator, see above question.

If it's not a standard 16MHz crystal/resonator, why isn't it?

Get rid of your software serial implementation, go get NewSoftSerial.

It has been tested at these speeds.

-j

Hi everyone,

It seems to be in progress…
with this code:

//Created August 15 2006
//Heather Dewey-Hagborg
//http://www.arduino.cc
//reworked to GPS reader
//Dirk, december 2006

#include <ctype.h>
#include <string.h>
#include <NewSoftSerial.h>

NewSoftSerial nss(0, 1);
#define bit38400Delay 26
#define halfBit38400Delay 13
#define bit9600Delay 84
#define halfBit9600Delay 42
#define bit4800Delay 188
#define halfBit4800Delay 94

byte rx = 0; //byte
byte tx = 1;
byte SWval;
char dataformat[7] = "$GPRMC";
char messageline[80] = "";
int i= 0;

void setup() {
  pinMode(rx,INPUT);
  pinMode(tx,OUTPUT);
 /* digitalWrite(tx,HIGH);
  digitalWrite(13,HIGH); //turn on debugging LED
  SWprint('h');  //debugging hello
  SWprint('i');
  SWprint(10); //carriage return*/
  Serial.begin(38400);  // this is used to echo what is read from the GPS out the USB->SerialDebugMonitor
}

void SWprint(int data)
{
  byte mask;
  //startbit
  digitalWrite(tx,LOW);
  delayMicroseconds(bit9600Delay);
  for (mask = 0x01; mask>0; mask <<= 1) {
    if (data & mask){ // choose bit
      digitalWrite(tx,HIGH); // send 1
    }
    else{
      digitalWrite(tx,LOW); // send 0
    }
    delayMicroseconds(bit9600Delay);
  }
  //stop bit
  digitalWrite(tx, HIGH);
  delayMicroseconds(bit9600Delay);
}

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 & 0x7f; // return val 

  }
}
void char2string()
{
  i = 0;
  messageline[0] = SWread();
  if (messageline[0] == 36) //string starts with $
  {
    i++;
    messageline[i] = SWread();
    while(messageline[i] != 13 & i<80) //carriage return or max size
    {
      i++;
      messageline[i] = SWread();
    }
    messageline[i+1] = 0; //make end to string
  }
}

void loop()
{
  digitalWrite(13,HIGH);

  //
  // 1st way to print only the $GPRMC message
  //

  //only print string with the right dataformat
   char2string();
  if (strncmp(messageline, dataformat, 6) == 0 & i>4)
  {
   for (int i=0; messageline[i] != '\0'; i++)
   {
        Serial.print(messageline[i], BYTE);
     }
   }

  //
  // 2nd way to print only the $GPRMC message
  //

  //   char2string();
  //   if (strncmp(messageline, dataformat, 6) == 0 & i>4)
  //   {
  //     Serial.println(messageline);
  //   }

  //
  // way to print ALL RECEIVED MESSAGES!
  //

  Serial.print(SWread(),BYTE); //use this to get all GPS output, comment out from char2string till here

}

I get that:

The progression happen when I put rx/tx on the arduino communication port…
kg4wsv, I see in theory the interest of NewSoftSerial but i can’t see actually how implement it in this code… I put it the code, inactive for the moment.
PaulS, my board is a standart board Duemilanese with a 16Mhz crystal
I tried the exemple of TinyGps and NewSoftSerial but I didn’t see anything :-[

Sorry guys, I must miss something.
It’s seem to be very easy but it’s my first…

With a standard Duemilanove, why are you trying to write your own code for reading from/writing to the serial port?

There exist perfectly functional hardware (Serial) and software (NewSoftSerial) classes already written read/write serial data. These functions are known to work.

Right. Thanks for help.

Seriously, I’m trying to understand what you are doing. If the goal is to write your own software to interface with the hardware, that’s great.

I’d start with using Serial and NewSoftSerial to validate that the hardware works as expected,

Then, I’d work on input using my own code, and output using the Serial and NewSoftSerial classes (or the other way around). When my serial code worked with the existing code, I’d work on the other half, output (or input if you do output first).

I’m sure you’d learn a lot from looking at the Serial and NewSoftSerial code.