Basic GPS

Work has been busy so this has suffered somewhat.

I have done some work around integrating a EM406A SiRF III GPS with an Arduino compatible and displaying the results on a 2x16 LCD.

Here's a photo of the completed prototype.
GPS Image
Sorry about the smudging of the last two digits on the display - it actually resolves right to my house!

Connecting the GPS to the Ardweeny is trivial. Buy a spare cable to connect the GPS with. These are usually 30cm long. Cut it in 1/2 and solder pins onto the wire ends. Connect the GND & +5v pins, then connect the Tx pin to D0 (pin 2) of the Ardweeny.

Next we need to connect the display to the Ardweeny.
These connections control the display device:
D10 <-> 4 (RS)
D11 <-> 5 (R/W)
D12 <-> 6 (Enable)
These connections carry data 4bits at a time:
D4 <-> 11 (Data 4)
D5 <-> 12 (Data 5)
D6 <-> 13 (Data 6)
D7 <-> 14 (Data 7)

Finally we need to connect the remaining display pins:
1 <-> GND
2 <-> +5v
3 <-> GND (LCD Contrast)
7 <-> 4.7k resistor <-> GND (Data0)
8 <-> 4.7k resistor <-> GND (Data1)
9 <-> 4.7k resistor <-> GND (Data2)
10 <-> 4.7k resistor <-> GND (Data3)

To make it work you'll need the following sketch. This will print the current LAT/LONG to the LCD as well as echo the selected messages to the TX line, suitable for viewing via the serial monitor.

int contrastPin= 9;
int contrast   = 0;
int stepval    = 25;
int dir        = 1;
int limit      = 250;

int RegisterSelect = 10;
int ReadWrite      = 11;
int Enable         = 12;
int LEDPin         = 13;

static int bpc     = 8;

void setup() {
// Set digital output pins 0 though 7 as outputs.
// These are used to send the displayed characters
DDRD = 0xF0; // d4,d5,d6 & d7 are outputs
// DDRD = 0xFF; // All pins are outputs.

// Initialize the LCD control lines.
digitalWrite(Enable, HIGH);
digitalWrite(RegisterSelect, LOW); // LOW = device CTRL, HIGH=data
digitalWrite(ReadWrite, LOW);
digitalWrite(LEDPin, LOW);
analogWrite(contrastPin, 60);
//digitalWrite(contrastPin, LOW);

// Set control pins to be outputs
pinMode(RegisterSelect, OUTPUT); // LCD Register Select
pinMode(ReadWrite, OUTPUT);      // LCD ReadWrite
pinMode(Enable, OUTPUT);         // LCD Enable
pinMode(contrastPin, OUTPUT);    // LCD Contrast
pinMode(LEDPin, OUTPUT);         // LED Blinkin Light
delayMicroseconds(250);

// Step one - set the Bits per character (and command)
writeCommand(0x30);
writeCommand(0x30);
writeCommand(0x30);
set4bitmode();
writeCommand(0x28); // 4bit mode, 2 lines, 5x7 dots
writeCommand(0x0F); // Display ON, Cursor ON, Blink ON
clearDisplay();     // Clear the display
delayMicroseconds(500);

Serial.begin(4800);
//delay(1000);
//Serial.write("$PSRF100,01,4800,08,01,00*0E\r\n");

writeString("GPS_TO_LCD");
moveCursor(1, 0);
writeString("Version 0.1");
delay(2000);
}

void printPrompts() {
clearDisplay();
writeString("Lat:");
moveCursor(1,0);
writeString("Long:");
}

void moveCursor(int row, int col) {
char outputByte = 0x0;
outputByte = row * 0x40 + col;
outputByte |= 0x80;
writeCommand(outputByte);
}

void clearDisplay() {
writeCommand( 0x01 );
delay(4);
}

void enableDisplay() {
writeCommand( 0x0F );
}

void set8bitmode() {
bpc = 8;
PORTD = 0x38;
digitalWrite(RegisterSelect, LOW);// LOW = device CTRL, HIGH=data
digitalWrite(Enable, LOW);
delayMicroseconds(250);
digitalWrite(Enable, HIGH);
delayMicroseconds(250);
}

void set4bitmode() {
bpc = 4;
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(RegisterSelect, LOW);// LOW = device CTRL, HIGH=data
digitalWrite(Enable, LOW);
delayMicroseconds(250);
digitalWrite(Enable, HIGH);
delayMicroseconds(250);
}

void writeCommand(char character) {
digitalWrite(RegisterSelect, LOW);// LOW = device CTRL, HIGH=data
if(bpc == 4) {
   writeNibble((character & 0xF0) >> 4);
   writeNibble(character & 0x0F); }
else {
   PORTD = character;
   digitalWrite(Enable, LOW);
   delayMicroseconds(250);
   digitalWrite(Enable, HIGH);
   delayMicroseconds(250); }
}


void writeCharacter(char character) {
digitalWrite(RegisterSelect, HIGH);// LOW = device CTRL, HIGH=data
if(bpc == 4) {
   writeNibble((character & 0xF0) >> 4);
   writeNibble(character & 0x0F); }
else {
   PORTD = character;
   digitalWrite(Enable, LOW);
   delayMicroseconds(250);
   digitalWrite(Enable, HIGH);
   delayMicroseconds(250); }
}

void writeNibble(char character) {
   digitalWrite(7, character & 0x08 ? 1 : 0);
   digitalWrite(6, character & 0x04 ? 1 : 0);
   digitalWrite(5, character & 0x02 ? 1 : 0);
   digitalWrite(4, character & 0x01 ? 1 : 0);
   digitalWrite(Enable, LOW);
   delayMicroseconds(250);
   digitalWrite(Enable, HIGH);
   delayMicroseconds(250);
}
void writeString(char *string) {
char *pointer = string;
while(*pointer) {
   writeCharacter(*pointer);
   pointer++; }
}

void loop() {
   char nmea_sentence[128];
   char *ptr = nmea_sentence;
   char newchar;
   int  match_cnt;
   char *saveptr, *latlongptr;
   char time[11];
   char latitude[11];
   char northSouth[2];
   char longitude[11];
   char eastWest[2];
   char quality[2];

   Serial.print("Entering main loop\r\n");
   printPrompts();
   while(true) {
      while(Serial.available() > 0) {
        newchar = Serial.read();
        *ptr = newchar;
        ptr++;
        if(newchar == 0x0A) {
          *ptr = 0x00;
           /* Is it a string we're interested in? */
           if(strncmp(nmea_sentence, "$GPGLL", 6) == 0 ) {
              Serial.write(nmea_sentence);
              }
           else if(strncmp(nmea_sentence, "$GPGGA", 6) == 0 ) {
              Serial.write(nmea_sentence);
              ptr = nmea_sentence;
              strsep(&ptr, ",");
              strsep(&ptr, ",");
              latlongptr = strsep(&ptr, ",");
              moveCursor(0,15-strlen(latlongptr));
              writeString(latlongptr);
              writeString(strsep(&ptr, ","));

              latlongptr = strsep(&ptr, ",");
              moveCursor(1,15-strlen(latlongptr));
              writeString(latlongptr);
              writeString(strsep(&ptr, ","));
              }

           /* We're finished with that string, reset the pointer. */
           ptr = nmea_sentence;
           }
        else {
           if(ptr > nmea_sentence + sizeof(nmea_sentence)) {
              clearDisplay();
              writeString("Error - NMEA");
              moveCursor(1,0);
              writeString("string too long");
              delay(1000);
              printPrompts();
              ptr = nmea_sentence; }
           }
       }
   }
}