Getting Data from Adafruit Ultimate GPS V3 onto 28x2 Picaxe

ChrisN141

New member
Hello all,
I am attempting to use the Adafruit Ultimate GPS V3 (https://cdn-learn.adafruit.com/downloads/pdf/adafruit-ultimate-gps.pdf) to get data (time, speed, lat, long, etc.) into a 28x2 picaxe so I can take the usable data and send it off to an LCD screen. I am struggling with what commands to use to pull data from the GPS and into the picaxe. I tried using HSERIN and SERIN on my own as well as using some other people's codes I found on the forums for somewhat related projects with no luck. I know the GPS sends data in the NMEA format but I'm not sure what to do for the code. Do I need any other supporting devices? Any help is appreciated as I am fairly new to programming picaxes with only a semester of experience.
 

PhilHornby

Senior Member
There are some pertinent threads in the forum :-

(3) Adafruit Ultimate GPS Breakout | PICAXE Forum

and

(3) Extracting GPS time with PICAXE | PICAXE Forum

and especially

(3) GPS Data receiver using X2's background serial data reception | PICAXE Forum

I would start by connecting to the module using a terminal emulator (such as Putty or Realterm), so you can understand the data you're dealing with.

The ADAFruit programming examples aren't that useful, because they rely on a 'library; to do the work - and no such library exists for PicAxe.
 

papaof2

Senior Member
I know it's do-able because I worked with a guy who was trying to make a dog a messenger with a backpack and GPS guidance. Recorded spoken words of "Forward", "Right" and so forth triggered by the GPS's position and a (rather large) lookup table. I think the design may have had two 40X2's in it.
I worked on some of the GPS code and I might still have a copy. No promises, but I will go look.
 

papaof2

Senior Member
Found some code for reading a ublox GPS with an attribute to www.gpsinformation.org - that might be a place to find more info.
It looks like PICAXE code that sends all the info to the terminal so maybe I found it here?
You'll have to determine your GPS's data speeds and so forth.

Code:
'
'NMEA ref: http://www.gpsinformation.org/dale/nmea.htm#ZDA
'
'init
#terminal 19200 on
setfreq m16

symbol GPSTX = c.2  ' Orange cable
symbol blueLED = c.4
symbol greenLED = B.7
symbol GPSlock = b20
symbol KPH = b21
symbol tempNum = b22    
symbol SatNum = b23

'vars
symbol baud = T9600_16
GPSlock = 0'no lock
symbol MinSats = 6

strt:
 gosub Acquire
 gosub GetTime
 gosub GetPosition
 gosub GetHeadingSpeed
 gosub GetNumOfSat
 'gosub showallgpsstrings
 gosub LEDStatus 
  
 pause 100
goto strt

'------------------------------------------

ShowAllGPSStrings:

 serin GPSTX, T9600_16,("$GPRMC"), b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10
 sertxd  ("##",b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10  ,"#" ,13,10)

return

Acquire:

 serin GPSTX, T9600_16,("$GPRMC,"), b0,b1
 
 if b1 = "V" THEN'do time yet
 
  sertxd (" - No signal", 13,10)
  GPSlock = 0
  
 else'time aquired
 
  sertxd (" - ACTIVE", 13,10)
  GPSlock = 1
  
 end if

return

GetTime:
 
 serin GPSTX, T9600_16,("$GPRMC,"), b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11
 
 if GPSlock = 0 then 'no data yet
  return
 end if
 
 sertxd ("Time ", b0, b1, ":", b2, b3, ":", b4, b5, 13,10)

return

GetPosition:
 
 serin GPSTX, T9600_16,("$GPGLL,"), b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11
 
 if GPSlock = 0 then'no data yet
  return
 end if
 
 sertxd ("Latt ", b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b11, 13,10)
 
 if b11 = "N" then'north lattitude
  serin GPSTX, baud,("N,"), b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12
 else'south lattitude
  serin GPSTX, baud,("S,"), b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12
 end if
 
 sertxd ("Long ", b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b12, 13,10)

return

GetNumOfSat:
 
 serin GPSTX, T9600_16,("$GPGSV,"), b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16'number of satelites
 
 SatNum = b4 - $30 * 10
 SatNum = SatNum + b5 - $30
 
 if GPSlock = 0 then 'no data yet
  return
 end if
 
 sertxd ("# of Satelites ", b4, b5, 13,10)
 
 return
 
GetHeadingSpeed:
 
 serin GPSTX, baud, ("$GPVTG"), b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16
 
 if GPSlock = 0 then'no data yet
  return
 end if
 
 if b1 = "," then''not moving
  sertxd ("Speed 0", 13, 10)
  low b.7
 else'moving
  sertxd ("Heading ", b1, b2, b3, b4, b5, 13,10)
  sertxd ("Speed ", b13, b14, b15, b16, 13,10)
  
  if b14 = "." then'slower than 10KPH
   tempNum = b13 - $30
  else'faster than 10KPH
  '100ths
   tempNum = b13- $30 * 10
   '10ths
   tempNum = tempNum + b14 - $30
   
   'not an erroneous reading & enough Satelites / error keeps last KPH
   if tempNum < 150 and SatNum >= minSats then
    KPH = tempNum
   end if
   
  end if
  
  if KPH >= 20 then
   
   sertxd ("Faster than 20 KPH")
   high greenLED
   
  else
  
   low GreenLED
   
  end if
  
 end if
 
 return
 
LEDStatus:
 
 if GPSLock = 0 then'no lock slow blink LED
  
  'blink LED slowly
  toggle blueLed
  pause 150
  toggle blueLed
  
 elseif SatNum < minSats and GPSlock = 1 then'les than min sats, turn on fast blink LED
  'blink LED
  
  high blueLED
  pause 50
  low blueLED
  
 else'lock and enough Satelites solid LED
 
  high blueLED
  
 end if
return
And one for a 28X2 running as an I2C slave:

Code:
; *******************************
; ***** GPS I2C Slave       *****
; *******************************
;    Filename: GPS_Pixaxe  
;    Date:   04/09/2011 
;    File Version: 1.5 
;    Written by:  Marcwolf 
;    Function:  Decode GPS Signals
;    Last Revision:
;    Target PICAXE: 28X2
; ******************************* 
' This should work on any Picaxe with a scratchpad and variable space
' The scratchpad is split into 2 parts
' 0 to 256 (changable as we only really need 130.. But this is only the 
' start for this project.
' and 256 + for info retrieved from the GPS unit (EM406A but can be any)
' The target conept is to have a Slave I2C PicAxe that will gather 
' GPS, Temp, Voltage etc data and present it in the scratchpad
' ready for the master to collect it.
' There is no special speed constraints on this so no SetFreq is needed
Symbol ptrSer = w26  ' Pointer for incoming serial
Symbol ptrI2C = w27  ' Pointer for outgoing I2C
Symbol SerPoke = 256 ' Start of the Scratchpad area of Serial
Symbol I2CPoke = b49 ' Slave I2C store ptr for Master to grab
Symbol PokePtr = b51 ' Temp area for extraction
Symbol Commas = b50  ' # of comma's to start from
Symbol GPSPort = b.7 ' Where is the GPS
' Starts of routine
GPS:
' Clear scratchpad to spaces ready for data
ptr =0: for b0 = 0 to 150 : ptr = b0 : @ptr = 32 : next 
ptr=SerPoke ' Set pointer to start of GPS store
' Get the GPS info in. Had issues with HSERIn so now just use the scratchpad
serin GPSPort,T4800,("GPGGA"),@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc
pause 100 ' pause to take processing breath
' Get the information
' Search GPS scratchpad for the number of Comma's
' then put the resulting text into the scratchpad
' starting at potion I2CPoke
Commas = 1: gosub GetString : I2CPoke = 0   : gosub PutString ' Time
Commas = 2: gosub GetString : I2CPoke = 30  : gosub PutString' Lat
Commas = 3: gosub GetString : I2CPoke = 110 : gosub PutString ' E/W
Commas = 4: gosub GetString : I2CPoke = 45  : gosub PutString ' Long 
Commas = 5: gosub GetString : I2CPoke = 115 : gosub PutString ' N/S
Commas = 9: gosub GetString : I2CPoke = 60  : gosub PutString ' MSL
Commas = 10:gosub GetString : I2CPoke = 120 : gosub PutString ' Meters for MSL
' Same again
ptr=SerPoke
serin GPSPort,T4800,("GPRMC"),@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc
Pause 100
Commas = 2: gosub GetString : I2CPoke = 125 : gosub PutString ' GPS Fix
Commas = 7: gosub GetString : I2CPoke = 75  : gosub PutString ' speed
Commas = 8: gosub GetString : I2CPoke = 90  : gosub PutString ' Direction
Commas = 9: gosub GetString : I2CPoke = 15   : gosub PutString ' Date
' now read out the scratchpad to simulate a I2C Master 
Readptr =0: for b0 = 0 to 150 : ptr = b0: sertxd(@ptr) : next : sertxd(CR,LF)' you can add other functions and processes.
GOTO GPSGetString:' Clear temp mem - 15 Bytes
for b0 = 80 to 95: poke b0,32: next
' Search along the scratchpad for X number of comma'sptr
Ser =  SerPoke
ptr = SerPoke -1
b2 = 0  ' count of comma's
do  ' look until we find the comma we are looking for  
if @ptrinc = "," then ' We found a comma
    inc b2     
if b2 = Commas then exit ' Are we X Comma's along. If so then exit  
end if
loop' We are at the X comma, check that there is a next character
if @ptrinc = "," then return : end if ' empty string as in ,,
dec ptr :PokePtr = 80 ' Step back one position and reset the temp memory ptr
' Now get the string to the next commado 
 b0 = @ptrinc ' Get the valid character  
if b0 = "," then  ' Are we at the next delimiter  
  exit ' ok jump out of loop 
 else     poke PokePtr, b0 ' put the actual value into the memory store    
 inc  PokePtr ' increment memory store ptr  
end if
loop' nothing more to do.  GPS extract is in bytes 80 to 95 ready for processing
return  

PutString:' put the memory store back into the correct position of the  SLAVE I2C storeptr = I2CPoke  ' set pointer to the I2C slave area
For b0 = 80 to 95 ' loop through memory store 
  peek b0,b1 ' get the info
   if b1 = 32 then return: end if ' A space - then we are at the end of the string 
  @ptrinc  = b1 ' poke the value into the I2C store
Next
Return
And this one from Robin for some of his robot boat work:

Code:
So, looking at those SERIN statements from Hippy:

SERIN 3, N4800_16, ( "$GPRMC," ) 'thanks Hippy :-)
SERIN 3, N4800_16, ( "," ), b1 'A = GPS tracking or V = not yet tracking
SERIN 3, N4800_16, ( ",W," )
SERIN 3, N4800_16, ( "," )
SERIN 3, N4800_16, #w2 'the GPS heading the boat is travelling

Can we just insert some more SERINs ?
'$GPRMC,114801,A,5129.8944,N,00041.0771,W,3.53,358 . 23,280608,,*18

MMmmm - needs a bit more thought..... maybe something like this ????
SERIN 3, N4800_16, ( "$GPRMC," ) 'thanks Hippy :-)
SERIN 3, N4800_16, ( "," ), b1 'A = GPS tracking or V = not yet tracking
'now we are near the latitude - start by reading 5129.89 into bytes ???
SERIN 3, N4800_16, ( "," ), b2,b3,b4,b5,b6,b6,b7 'first b6 is to skip the decimal point
w6 = b2*10 + b3 'degrees
w6 = w6 * 1000 'scale it to 1/1000ths of a degree
w7 = b4 *10 + b5 'minutes
w7 = w7 * 1000 / 60 'convert minutes to scaled degrees
w6 = w6 + w7 '5129 converted in scaled degrees


Many Thanks in advance.
Robin
www.gpss.co.uk 

[/code}
 

marks

Senior Member
Hi ChrisN141,
I guess the first step is to try if can receive data ok.
This program should sertxd your gprmc sentence from the picaxe.
At the end the checksum is displayed in decimal it is usually hex
the conversion is required to check that it is correct.

You can also check what the actual gps is sending using the Picaxe Editor
just connect your usb to usbc cable and refresh comports.
Reopen the serial terminal and select the usb device from the com port settings.
Code:
SYMBOL Checksum = B2
SYMBOL CRCerrors = W9
SYMBOL CRC = B1
SYMBOL Datebptr = B4
              #picaxe 28x2
   SETFREQ M16 #terminal 19200
  
GPS_SKM53:'$GPRMC,HHMMSS.sss,A,DDMM.mmmm,S,DDDMM.mmmm,E,0.02,133.23,DDMMYY,,,D*7D
NEO_7M:'$GPRMC,HHMMSS.ss,A,DDMM.mmmmm,S,DDDMM.mmmmm,E,0.007,88.53,DDMMYY,,,D*7D

Main:
 ptr = 0
 SERIN C.7,t9600_16,("RMC"),@ptr,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,_
 @ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,_
 @ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,_
 @ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,_
 @ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,_
 @ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,_
 @ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,_
 @ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc

  GPSmessageCRC:
SERTXD (13,10," $GPRMC,")
 ptr=0
CRC=103 ' seed GPRMC,
DO until @ptr="*" ' crc = XOR all characters between $ and *
SERTXD(@ptr)
CRC=CRC XOR @ptrinc
LOOP
SERTXD(@ptr) '*
datebptr=ptr-10
CRCchecksum: ' convert ascii $x+$x to dec
inc ptr : @ptrinc = @ptr /64 *9 + @ptr *16
Checksum = @ptr /64 *9 + @ptrdec &$0F +@ptr
SERTXD(#Checksum," ")

IF CRC <> Checksum THEN :INC CRCerrors : SERTXD (CR,LF, "Checksum Error ",#CRCerrors) : GOTO Main : ENDIF
ptr =10 : IF @ptr = "," THEN : INC ptr : ENDIF
IF @ptr <> "A" THEN : SERTXD(@ptr) : GOTO Main : ENDIF ' A=(Active)data valid  or   V=(Void)data not valid

 goto main
 

Aries

New Member
This is part of my code for a Picaxe M2 getting date & time - I have decoded location as well, but it wasn't relevant to my needs here.
Code:
#define GPSfreq T9600_32
#terminal 38400
symbol GPSTX = B.1
symbol GpsDataArea        = 100
symbol GpsAreaSize        = 60
symbol GpsAreaSizeMinus1 = GpsAreaSize - 1
symbol GpsDataAreaEnd    = GpsDataArea + GpsAreaSizeMinus1

' Wait for a GPRMC record - include comma for convenience
ReadGPS:
    sertxd(13,10,"ReadGPS")
    bptr = GpsDataArea
    serin [4000,EndReadGPS],GPSTX,GPSfreq,("$GPRMC,"),_
        @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc,_
        @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc,_
        @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc,_
        @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc,_
        @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc,_
        @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc, @bptrinc
    bptr = GpsDataArea
    sertxd(" ",#InternalTimer," ",@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,_
                        @bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,_
                        @bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc)
  return
 

ChrisN141

New member
Thanks everyone for the help. It turns out I was only missing the Setfreq m16 line and the serin command worked just fine loading the message into variables. I have one 28X2 reading the full NMEA sentence into 55 variables with serin and then serout just the variables I care about to another 28X2 so I can use them to do math. So far I have been able to get Time and date, latitude and longitude, speed in knots, and even course over ground in degrees displayed on an axe133y OLED. The issues I am running into now are converting speed from knots to MPH (1 knot x 1.15 = mph, floating number issue) as well as getting the time set correctly for my time zone. The GPS spits out UTC time, and my time zone is -7 from UTC. The issue with doing the offset and with the speed math is that each number is put into its own variable, so 12:00 is 5 variables, b1= ASCII 1, b2=ASCII 2, etc, but I need to subtract 7 from 12, not 7 from a one and a two. The same issue applies with speed, as it is loaded into three variables (x.xx). I would need to convert the ascii characters across multiple variables into a decimal number in one variable to do this math, correct? Thanks for the responses.
 

Aries

New Member
From the same program as above, this is the subroutine for doing the conversion of ASCII bytes to decimal. bptr points to the first byte.
On return, value is in b0; b1 = 0 for OK, 1 for conversion error; bptr points to next byte.
Code:
' convert two decimal character bytes into a number
ConvertTwoBytes:
    b0 = 0
    b1 = 1
    if @bptr < "0" or @bptr > "9" then EndConversion    ' error
    b0 = @bptrinc - "0"
    if @bptr < "0" or @bptr > "9" then EndConversion    ' error
    b0 = b0 * 10 + @bptrinc - "0"
    b1 = 0
EndConversion:
    return
 
Top