• PicŪ Basic


  • Demo code for the ZX4120 GPS

    The Amicus GPS shield contains a 16 channel ZX4120 GPS receiver, as well as a 16k byte (128 kbit) serial (I2C) eeprom, and a 3 Volt, 12mm battery socket in order to maintain the receiver's built-in RTC (Real Time Clock). A SMA socket allows attachment of the GPS receiver's aerial.
    See the original project of Les Johnson on the wiki.

    I had decided to acquire this module in order to learn the GPS system and develop future projects because of the ease with which this product offers to be used in the Amicus18 board.
    I wanted to get a code as fast as possible to be able to perform other tasks.
    Les Johnson has made some very effective codes in the "GPS.inc" library.
    Due to the hardware already defined in the GPS schield, the PORTA.0 pin for Rsin and the PORTA.1 pin for RsOut; The communication must be of the software type by obligation. The PIC18F25K20 has a single UART port only reserved for the USB port.

    I have not had the possibility to use the powerful and very good RSin/RSOut commands so far. This code really works great at 9600 bauds (speed of GPS data output), using it with the PIC overclocked at 80Mhz.
    In short, my chalenge is to get the highest speed of reception of the NMEA data without losing any data nor the synchronism and all this in every second; and increase the security of the data received; frame and checksum controls. What the GPS.inc code does not get.

    To get speed:
    - I need to change the codes to be more efficient.
    - For that you get speed I must write more individuals routines.
    - Read all NMEA lines first. One line => one buffer.
    - One extract code for every NMEA lines. One routine for one function and for every line.
    - Frame control
    - Checksum control.
    - Terminal control.

    RX Buffers: GPS_ggaRxBuffer, GPS_gsaRxBuffer, GPS_gsv1RxBuffer, GPS_gsv2RxBuffer, GPS_gsv3RxBuffer, GPS_rcmRxBuffer, GPS_vtgRxBuffer.

    Waiting for the $GPGGA line allows getting synchronization with the timing every second.
    Then the next line is expected. In principle, it is not known what type it is because the sending of ZX4120 GPS data is not always the same.
    Code:
    Second: 00
    $GPGGA,075800.927,4129.6583,N,00207.8115,E,0,00,00.0,0.0,M,49.9,M,,*61
    $GPRMC,075800.927,V,4129.6583,N,00207.8115,E,0.00,267.62,250717,,,A*70
    $GPVTG,267.62,T,,,0.00,N,0.00,K,A*77
    
    Second: 01
    $GPGGA,075801.927,4129.6583,N,00207.8115,E,0,00,00.0,0.0,M,49.9,M,,*60
    $GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30
    $GPRMC,075801.927,V,4129.6583,N,00207.8115,E,0.00,267.62,250717,,,A*71
    $GPVTG,267.62,T,,,0.00,N,0.00,K,A*77
    
    Second: 02
    $GPGGA,075802.927,4129.6583,N,00207.8115,E,0,00,00.0,0.0,M,49.9,M,,*63
    $GPGSV,2,1,06,2,31,079,,12,43,061,20,14,37,287,,24,29,136,19*4E
    $GPGSV,2,2,06,31,25,311,,32,38,260,,,,,,,,,*77
    $GPRMC,075802.927,V,4129.6583,N,00207.8115,E,0.00,267.62,250717,,,A*72
    $GPVTG,267.62,T,,,0.00,N,0.00,K,A*77
    The $GPGSV line could be one, two or three randomly. It is not easy to detect.

    Reading code exampe for GGA line:
    Code:
    ' $GPGGA file - Global Positioning System Fix Data
        F_Do_CKS = 0
        DO_Checksum = cvGGA_Checksum                ' Load checksum GPGGA word.
        GPS_eCharpos = 0
        GPS_wFSR0 = VarPtr GPS_ggaRxBuffer          ' Point FSR0L/H to the start of the buffer
    
        RsIn {__GPS_TimeoutGGA},Wait("$GPGGA")      ' Wait for the $GPGGA string (with a timeout)
        ' Receive the rest of the NMEA text into GPS_ggaRxBuffer
        Repeat                                      ' Create a loop to receive the serial string
            RsIn {__GPS_TimeoutGGA},WREG            ' Receive a character serially from the GPS module
            POSTINC0 = WREG                         ' Load a value of array GPS_ggaRxBuffer        
            GPS_bChar = WREG
            ' Make checksum of all of bytes of the file until "*" character.
            If F_Do_CKS = 0 Then
                If GPS_bChar <> "*" Then             
                    DO_Checksum = DO_Checksum ^ GPS_bChar ' Do checksum
                Else
                    F_Do_CKS = 1                    ' Stop DO checksum.
                EndIf
            EndIf
            If GPS_bChar = 13 Then GoTo SuccesReadingGGA ' Exit the loop when the string reaches the end
            Inc GPS_eCharpos
        Until GPS_eCharpos = SizeOf(GPS_ggaRxBuffer)  ' Repeat the loop until the buffer runs out (security)
        F_ErrorGGAfile = 1                            ' Get an error, the Carriage Return not found.
        GoTo ReadGGAexit                              ' If the Frame is bad GoTo error.
    SuccesReadingGGA:
    
        ' Check the final checksum of file.
        GoSub MakeFinalChecksum_Sub
        If DO_Checksum <> FinalLineChecksum Then     ' Compare the 2 checksums.
            F_ErrorGGAfile = 1                         ' Get an error, checksum fails.
        EndIf
    
    ReadGGAexit:
        If F_ErrorGGAfile = 1 Then
            HRSOut "$GPGGA fails",13,10
            Return  ' Return of GPS_Parse() routine.
        EndIf
    After receiving and saving the first $GPGGA line, I have written a special code to detect the Head of the others lines randomly.
    Code:
        GPS_bChar = 0
        ASCIIbyteCounter = 5
        RsIn {__GPS_TimeoutStart},Wait("$") ' Wait for the $ start character of file. (with a timeout)
        ' Receive the rest of the HEADER.
        Repeat                              ' Create a loop to receive the serial string
            Dec ASCIIbyteCounter
            RsIn {__GPS_TimeoutStart},WREG  ' Receive a character serially from the GPS module
            GPS_bChar = GPS_bChar + WREG
        Until ASCIIbyteCounter = 0          ' Exit the loop when the string reaches the end
    
        Select GPS_bChar
            $ifdef _ReadGPGSA_
            Case cvGSA_Sum          ' Symbol cvGSA_Sum = 114
                GoTo ReadGSA_Sub    ' Read the "$GPGSA" file.
            $endif
            $ifdef _ReadGPGSV_
            Case cvGSV_Sum          ' Symbol cvGSV_Sum = 135
                GoTo ReadGSV_Sub    ' Read the 1, 2 or 3 "$GPGSV" files.        
            $endif
            Case cvRMC_Sum          ' Symbol cvRMC_Sum = 121
                GoTo ReadRMC_Sub    ' Read the "$GPRMC" file.    
            $ifdef _ReadGPVTG_
            Case cvVTG_Sum          ' Symbol cvVTG_Sum = 136
                GoTo ReadVTG_Sub    ' Read the "$GPVTG" file. Last one & print all files.
            $endif
        EndSelect
        GoTo EndOfReadingFiles
    In this way each line has its individual reading code and its own buffer.
    Although for the lines "$GPGSV-1", "$GPGSV-2" and "$GPGSV-3" the reading is completely automatic.
    After writing all the lines, considering that the label "$GPVTG" is the last one, it begins to send the data to the terminal if these conditions have been defined by the user of the PDS.
    This format is for the ZX4120 GPS receiver, for another GPS it would be very easy to modify the order of the routines or the Code.

    At start up of the PIC, the lines are printed perfectly to fit its format.
    Code from a Reset:
    Code:
    XTAL = 80Mhz
    GPS NMEA Demo:
    
    Second: 50
    $GPGGA,071650.426,4129.6429,N,00207.8829,E,1,05,06.5,122.3,M,49.9,M,,*60
    $GPRMC,071650.426,A,4129.6429,N,00207.8829,E,0.00,151.03,130817,,,A*68
    $GPVTG,151.03,T,,,0.00,N,0.00,K,A*76
    Date: 13:08:17
    Time: 07:16:50 UTC
    Fix type: 1
    Sats in view: 5
    ALT: 122 Meters
    Heading: 151.03 Degrees
    Speed: 0 Km/h
    LAT_DMm: 4129.6433
    LONG_DMm: 207.8829
    LAT_Dd: 41.49405
    LONG_Dd: 2.13138
    LAT_DMS: 41 Deg 29' 38.63" N
    LONG_DMS: 2 Deg 07' 53.07" E
    
    Distance: 505 Km
    Antenna Bearing: 258 Deg
    
    My QTH Locator: JN11BL
    
    QTH Locator: JN11BL
    LAT_Dd: 41.47916
    LON_Dd: 2.12500
    
    Second: 51
    $GPGGA,071651.426,4129.6429,N,00207.8829,E,1,05,06.5,122.4,M,49.9,M,,*66
    $GPRMC,071651.426,A,4129.6429,N,00207.8829,E,0.00,151.03,130817,,,A*69
    $GPVTG,151.03,T,,,0.00,N,0.00,K,A*76
    Date: 13:08:17
    Time: 07:16:51 UTC
    Fix type: 1
    Sats in view: 5
    ALT: 122 Meters
    Heading: 151.03 Degrees
    Speed: 0 Km/h
    LAT_DMm: 4129.6433
    LONG_DMm: 207.8829
    LAT_Dd: 41.49405
    LONG_Dd: 2.13138
    LAT_DMS: 41 Deg 29' 38.63" N
    LONG_DMS: 2 Deg 07' 53.07" E
    
    Distance: 505 Km
    Antenna Bearing: 258 Deg
    
    My QTH Locator: JN11BL
    
    QTH Locator: JN11BL
    LAT_Dd: 41.47916
    LON_Dd: 2.12500
    
    Second: 52
    $GPGGA,071652.425,4129.6429,N,00207.8828,E,1,05,06.5,122.4,M,49.9,M,,*67
    $GPGSA,A,3,02,12,24,25,29,,,,,,,,9.9,6.5,7.5*38
    $GPGSV,3,1,09,2,29,060,47,12,32,076,46,14,35,266,,24,14,143,32*4A
    $GPGSV,3,2,09,25,65,045,45,26,06,280,,29,78,210,25,31,39,310,*77
    $GPGSV,3,3,09,32,29,242,,,,,,,,,,,,,*4E
    $GPRMC,071652.425,A,4129.6429,N,00207.8828,E,0.00,151.03,130817,,,A*68
    $GPVTG,151.03,T,,,0.00,N,0.00,K,A*76
    Date: 13:08:17
    Time: 07:16:52 UTC
    Fix type: 1
    Sats in view: 5
    ALT: 122 Meters
    Heading: 151.03 Degrees
    Speed: 0 Km/h
    LAT_DMm: 4129.6433
    LONG_DMm: 207.8828
    LAT_Dd: 41.49405
    LONG_Dd: 2.13138
    LAT_DMS: 41 Deg 29' 38.63" N
    LONG_DMS: 2 Deg 07' 53.06" E
    
    Distance: 505 Km
    Antenna Bearing: 258 Deg
    
    My QTH Locator: JN11BL
    
    QTH Locator: JN11BL
    LAT_Dd: 41.47916
    LON_Dd: 2.12500
    For a buffer to be printed or used to extract data, it is necessary to pass 3 controls:
    - A line has been read. (Buffer full)
    - A Carriage Return has been received. (No Frame error)
    - No checksum error.

    Then the data are extracted from the different files.
    The commands to extract the data are: GPS_ExtractValueGGA(CommaPosition), GPS_ExtractValueGSA(CommaPosition), GPS_ExtractValueGSV(CommaPosition),...

    Every second, the lines $GPGGA and $GPRMC are usually sent, not the others.
    Every 2 seconds, $GPGSA lines can appear or not.
    Every 3 seconds, $GPGSA, $GPGSV lines appear or not, but could be 1, 2 or 3 lines.
    Then the data is sent to the terminal and remain because the buffers are not deleted after each reading, and are updated every 1, 2 or 3 seconds.
    You can override this function by deleting the GPS_FilesOKFlags every second. (see the code)

    Special Functions:
    For my future project I will need:
    - Calculate the distance and direction of the antenna between 2 points using Lat/Lon data. (John Drew Routine)
    - Calculate the QTH locator from the Latitude and Longitude data. (Routine extracted from the wiki containing an error that I have fixed)
    - Calculate the Latitude and Longitude from a QTH locator. (John Drew Routine)

    With the new library it is possible to read 7 NMEA lines, write them to buffers, make all controls and perform distance calculations with Lat/Lon and QTH locator data, all done every second. And there is time to do more things.
    Three GPS format are avaible: Degrees + Minutes,Minutes decimals, Degrees + Minutes + Seconds (H/S or E/W) and Degrees, degrees decimals.

    Comment: The code runs with a PIC18F25K20 at 80 Mhz. Not tested at 64 Mhz.
    I have incorporated my bootloader for FOSC = 80 Mhz. Some compilation errors occur with version 3.5.9.9 of the PDS.

    On this date I could not send commands to the GPS, It does not accept them.
    I appreciate the help of John Drew to lead the way and the other friends of the forum for their help.
    Enjoy the code.
    August 2017

    Updated: 25/08/2017 version 1.4
    Curiously and temporarily the GPS sends 4 GSV files at boot (Fix type = 0) or when there are 10 satellites. This mode does not correspond to the GPS manual, but I have modified the code to receive these 4 files. This is easy because the code is very modular.
    Code:
    $GPGGA,172135.495,0000.0000,S,00000.0000,W,0,00,00.0,0.0,M,0.0,M,,*59
    $GPGSV,4,1,14,1,64,243,49,3,,,,7,,,,8,,,*4E
    $GPGSV,4,2,14,9,,,,11,38,220,47,14,,,,16,,,*79
    $GPGSV,4,3,14,17,,,,19,,,,22,66,356,39,23,,,*4E
    $GPGSV,4,4,14,26,,,,31,43,051,35,,,,,,,,*4F
    $GPRMC,172135.495,V,0000.0000,S,00000.0000,W,0.00,0.00,250817,,,A*74
    Date: 25:08:17
    Time: 17:21:35 UTC
    Sats in view: 0
    No GPS Fix
    I have improved the detection of the lines too. I also propose another way to calculate the other formats by calculating them from the Float value received from the lines. The result is that the code is shorter and much faster.

    Download the code from HERE.
  • Recent Activity

    towlerg-21522

    FineLineIDE

    Thread Starter: normnet

    Coming soon a new IDE: FineLineIDE! Features include:<O:p</O:p Bracket lines linking If-Endif, For-Next etc.<O:p</O:p Tabbed explorer so...

    towlerg Today, 16:49 Go to last post
    evoortman-388

    Pic16f18877 oread

    Thread Starter: evoortman

    Hi, On a PIC16F18877 the OREAD command doesn't seem to work. The code is working on a PIC16F1939. Both controllers use 32MHz int osc. If i...

    evoortman Today, 11:13 Go to last post
    amod-29593

    Multiple functions by a single switch

    Thread Starter: amod

    Hi, How can I use multiple function by a single switch.I want to use 4 functions by a single switch.

    amod Today, 17:15 Go to last post
    towlerg-21522

    FUSES for PIC18F47K20

    Thread Starter: gtv_pic

    000 Good morning I am using the PIC18F47K20 and in the help of the proton I did not locate the FUSES for said micro. Where can I locate...

    towlerg Today, 14:52 Go to last post