Return to Snippet

Revision: 2450
at February 20, 2007 20:19 by k2vol


Initial Code
'****************************************************************
'*  Name    : UTARC GPS setting Real Time Clock TEST                                    *
'*  Author  : Daniel Bowen, Mike Coffey, Carl Lyster                    *
'*  Notice  : Copyright (c) 2007 UTARC www.utarc.org *
'*          : All Rights Reserved                               *
'*  Date    : 2/20/2007                                          *
'*  Version : 1.0                                               *
'*  Notes   :  Reads standard NMEA GPS information and sets Real Time Clock chip to within 5 seconds of GPS time.
'*			:	Clock chip used is serial NJR NJU6355ED, PIC is 18F4620
'*          :                                                   *
'****************************************************************

INCLUDE "MODEDEFS.BAS"
DEFINE OSC 20
DEFINE LOADER_USED 1
DEFINE HSER_BAUD 2400
DEFINE ADC_CLOCK 1
DEFINE ADC_BITS 10
DEFINE ADC_SAMPLEUS 50
SYMBOL LF=$0A
CMCON=$07
ADCON1=%00001100
TRISA=%00110111
TRISB=%01111101
TRISC=%10010100
TRISD=%10010100
TRISE=%00000000

'*** Pin assignments
Red VAR PORTE.0
Green VAR PORTE.1
Yellow VAR PORTE.2
RTCCE VAR PORTC.3
RTCCLK VAR PORTC.2
RTCD VAR PORTC.1
RTCIO VAR PORTC.0
GPSDataPin VAR PORTB.0



'****RTC VARIABLES****
dateTime          VAR byte[7]                     'Array for the RTC time input
YR                VAR dateTime[0]                 'RTC YEARS AS 2 HEX DIGITS
MO                VAR dateTime[1]                 'RTC MONTH AS 2 HEX DIGITS
DY                VAR dateTime[2]                 'RTC DAYS AS 2 HEX DIGITS
DW                VAR dateTime[3]                 'DAY OF WEEK NOT UESD
HR                VAR dateTime[4]                 'HOURS AS 2 HEX DIGITS
MN                VAR dateTime[5]                 'MINUTES AS 2 HEX DIGITS
SE                VAR dateTime[6]                 'SECONDS AS 2 HEX DIGITS

'***HEX-DEC Conversion Variables***
hexNum            VAR BYTE     'used for converting hex to ascii
decNum            VAR BYTE     'used for converting numbers to decimal integers

'***GPS Variables
gPSBaudMode             CON   24764
gPSSentenceString                VAR   byte[90]
gPSSentenceCheckSumValid         VAR BIT
gPSDataReceived         VAR     BIT
gPSFixValid             VAR     BIT
 'value extraction variables
data_String             VAR   BYTE[20]
comma_Count             VAR     BYTE
char                    VAR     BYTE
charPos                 VAR     BYTE
extract_Item            VAR     BYTE
bLoop                   VAR     BYTE
i                       VAR     Byte  
checkSum                VAR     BYTE
numlen                  VAR     BYTE
asciiNumber             VAR     WORD
power                   var     WORD 
gPSSentenceId           VAR     BYTE[5]


LOW RTCCE
LOW RED
LOW GREEN
LOW YELLOW

START:


    GOSUB SETLEDSFORGPS  'Set LED status lights for GPS status
    EXTRACT_ITEM = 1 'UTC time
      GOSUB extract_the_Value
      HSEROUT ["GPS Time: ",dec extract_Item," ",STR data_string,CR,LF]
    GOSUB RTCREAD
    HSEROUT ["RTC Time: ",HEX HR, HEX MN, HEX SE, CR,LF]  
    GOSUB SYNCRTCWITHGPS
    GOSUB RTCREAD
    PrintTimeLoop:
        GOSUB readGPS
        GOSUB RTCREAD
        EXTRACT_ITEM = 1 'UTC time
        GOSUB extract_the_Value
        HSEROUT ["GPS : ",dec extract_Item," ",STR data_string,CR,LF]
        HSEROUT ["RTC: ",HEX HR, " ", HEX MN, " ", HEX SE, CR,LF]  
    GOTO PrintTimeLoop
END
GOTO START



SYNCRTCWITHGPS:    'This will sync Real Time Clock with the GPS to +/-5s
    GOSUB readGPS
    EXTRACT_ITEM = 1 'UTC time
    GOSUB extract_the_Value

    'convert hours, and minutes to hex
    'Remove seconds from data string, then send hours/minutes to be converted
    GOSUB asciiHextoInteger   'Will truncate to just Min and Sec in asciiNumber variable
    SE = asciiNumber & $00FF  'save seconds   
    data_string[4] = 0
    data_String[5]= 0 
    GOSUB asciiHextoInteger
    MN = asciiNumber & $00FF 'Removes the first two hex digits, Save minutes
    HR = asciiNumber >> 8    'Shift hours over to be only digits, save hours
    'asciiNumber = asciiNumber >> 8
    HSEROUT ["GPS HR: ", HEX HR, " MN: ",HEX MN, " SE: ", HEX SE, CR,LF]
    
     'Increment the minutes to be saved, making sure not to exceed 59.
    IF MN = $59 THEN 
        MN = $0
    ELSE
        MN = MN + $1  'set minute to the next one just arrived at
    ENDIF
    
    'wait for minutes to increment, then sync with RTC
    WHILE SE < $55 'Keep Looping until the end of this minute
        GOSUB readGPS
        EXTRACT_ITEM = 1 'UTC time
        GOSUB extract_the_Value      '
        GOSUB asciiHextoInteger       'Take ascii text string and convert it to integer number
        SE = asciiNumber & $00FF  'Time in this variable currently only contains minutes and seconds
        'HSEROUT [" ",HEX SE]                       
    WEND
    'HSEROUT ["Time to sync! GPS Seconds: ", HEX SE,cr,lf] 
    SELECT CASE SE      'PAUSE remaining Seconds till next minute, this doesn't really work very well
        CASE 55
            PAUSE 4900  'Pause 4.9 seconds
        CASE 56
            PAUSE 3900  'Pause 3.9 seconds
        CASE 57
            PAUSE 2900  'Pause 2.9 seconds
        CASE 58
            PAUSE 1900  'Pause 1.9 seconds
        CASE 59
            PAUSE 900   'Pause 0.9 seconds
    END SELECT
        

    GOSUB RTCSET
    
RETURN
   
   


SETLEDSFORGPS:
      gPSSentenceId[0] = "G"
      gPSSentenceId[1] = "P"
      gPSSentenceId[2] = "G"
      gPSSentenceId[3] = "G"
      gPSSentenceId[4] = "A"
      extract_Item = 6 'Fix good or bad
      GOSUB readGPS
      GOSUB extract_the_value
      GOSUB ASCIIDECTOINTEGER

      IF ASCIINUMBER > 0 then        'Set Green LED on if there's valid FIX data
        HIGH GREEN
      ELSE
        LOW GREEN
      ENDIF
      
      IF gPSDataReceived = 1 THEN     'Set Yellow LED on if there is valid serial data
        HIGH YELLOW
      ELSE
        LOW YELLOW
      ENDIF
RETURN   
   
RTCREAD:       'READ THE REAL TIME CLOCK CHIP   
      LOW RTCCLK                        'SET CLOCK LOW
      LOW RTCIO                         'SET I/O TO READ
      HIGH RTCCE                        'ENABLE CHIP
      SHIFTIN RTCD,RTCCLK,1,[YR\8]      'READ YEAR AS 2 HEX DIGITS
      SHIFTIN RTCD,RTCCLK,1,[MO\8]      'READ MONTH AS 2 HEX DIGITS
      SHIFTIN RTCD,RTCCLK,1,[DY\8]      'READ DAY OF MONTH AS 2 HEX DIGITS
      SHIFTIN RTCD,RTCCLK,1,[DW\4]      'WE WILL NOT USE THE DAY OF WEEK
      SHIFTIN RTCD,RTCCLK,1,[HR\8]      'READ HOURS AS 2 HEX DIGITS
      SHIFTIN RTCD,RTCCLK,1,[MN\8]      'READ MINS AS 2 HEX DIGITS
      SHIFTIN RTCD,RTCCLK,1,[SE\8]      'READ SECONDS AS 2 HEX DIGITS
      LOW RTCCE                         'DISABLE RTC CHIP
      LOW RTCIO                         'RTC CHIP TO READ MODE
      RETURN
      
RTCSET:         'SET DATE AND TIME OF RTC CHIP
      LOW RTCCLK                        'SET CLK LOW
      HIGH RTCIO                        'ENABLE WRITE
      HIGH RTCCE                        'SELECT RTC
      SHIFTOUT RTCD,RTCCLK,0,[YR\8]    'YEAR AS 2 HEX DIGITS
      SHIFTOUT RTCD,RTCCLK,0,[MO\8]    'MONTH AS 2 HEX DIGITS
      SHIFTOUT RTCD,RTCCLK,0,[DY\8]    'DAY OF MONTH AS 2 HEX DIGITS
      SHIFTOUT RTCD,RTCCLK,0,[0\4]      'DAY OF WEEK NOT USED SET TO 0
      SHIFTOUT RTCD,RTCCLK,0,[HR\8]    'HOURS 24 HOUR FORMAT  2 HEX DIGITS
      SHIFTOUT RTCD,RTCCLK,0,[MN\8]    'MINUTES AS 2 HEX  DIGITS
                    'SECONDS SET TO 0 AUTOMATICALLY
      LOW RTCCE                         'DESELECT RTC CHIP
      LOW RTCCLK                        'LOW CLOCK
      LOW RTCIO                         'RTC IN READ MODE FROM NOW ON
      RETURN                            'CLOCK STARTS ON RETURN
          

TIMEPROCESSING:
      FOR i = 0 to 6'                   'Convert Hex time into Decimal
          hexNum = dateTime[i]          'copy number into converter var
          GOSUB HEXTOINTEGER            'Convert hex number to Dec integer
          dateTime[i] = decNum
      NEXT
RETURN

HEXTOINTEGER:
decNum = (hexNum / 16) * 10          'Get 10s place value of hex representation
decNum = decNum + (hexNum // 16)     'add 10s place to ones place
RETURN


'******************************************************************************
'FROM HERE ON DOWN, THESE ARE DAN'S UTILITY ROUTINES FOR GPS, AS MODIFIED BY MIKE
'DO NOT ENTER UNLESS YOU ARE VERY BRAVE!!!
'**************************************************************************
'  FUNCTION:      READGPS
'  INPUT:         gPSDataPin CON, gPSBaudMode CON,
'                 gPSSentenceId BYTE array - GPS Sentence name
'                     Serial data stream on gPSDataPin, accepts up to 90 bytes
'                     starting with gPSSentenceId, and ending with CRLF
'  OUTPUT:        gPSSentenceString BYTE array of requested sentence.                 
'  PURPOSE:       Capture desired GPS sentence from ASCII GPS serial data.
'                 Calls functions to verify the sentence checksum. 
'**************************************************************************
READGPS:
SERIN2 GPSDataPin, gPSBaudMode, 3000, NoData, [WAITSTR gPSSentenceId\5, STR gPSSentenceString\90 ]
gpsDataReceived = 1 'Note that we have received serial data from the GPS.
'hserin 3000, NoData, [WAITSTR gPSSentenceId\5, STR gPSSentenceString\90 ]
GOSUB GPSCOMPUTECHECKSUM
GOSUB GPSMATCHCHECKSUM
RETURN


'----[EXTRACT A VALUE BASED ON THE COMMA THAT IT FOLLOWS]----------------------
' Locates and extracts the value following the comma placed in EXTRACT_ITEM
' The extracted text is returned in array DATA_STRING with a NULL terminator
' If an invalid value is found, then 000000 will be returned in the array
    
EXTRACT_THE_VALUE:
FOR i = 0 to 19 STEP 1    
    DATA_STRING[i] = 0
NEXT
COMMA_COUNT = 0 ' Reset the comma counting variable
CHARPOS = 0 ' Start at the beginning of the array
WHILE CHARPOS < 199
    CHAR = gPSSentenceString[CHARPOS] ' Scan the array to parse
    If CHAR == "," Then 
        COMMA_COUNT = COMMA_COUNT + 1
    ENDIF ' Increment COMMA_COUNT if a comma is found
    If COMMA_COUNT == EXTRACT_ITEM Then ' Have we found the correct comma ?
    BLOOP = 0 ' Yes. So.... 
'    Repeat ' Form a loop
     WHILE CHARPOS < 199
        CHARPOS = CHARPOS + 1' Skip over the comma and keep scanning the array
        CHAR = gPSSentenceString[CHARPOS] ' Extract the pieces of the value into CHAR
        If CHAR = 0 Then Break
        If CHAR = "," Then Break
        DATA_STRING[BLOOP] = CHAR ' Fill DATA_STRING with the value
        BLOOP = BLOOP + 1 ' Point to the next data piece
'    Until CHARPOS >= 199 ' Keep looping until a terminator is found
     WEND
    DATA_STRING[BLOOP] = 0 ' Add a NULL to DATA_STRING
    
    Endif
    CHARPOS = CHARPOS + 1
WEND
BREAK:
Return 
GOTO START



'**************************************************************************
'  FUNCTION:      ASCIIHEXTOINTEGER
'  INPUT:         data_String BYTE array of ASCII HEX number characters 
'  OUTPUT:        asciiNumber WORD var with hex integer value of ascii  
'  PURPOSE:       Converts ascii hex string of numbers into integer WORD  
'**************************************************************************
ASCIIHEXTOINTEGER:

numlen = 0
asciiNumber = 0
char = 1
While char !=0
      char = data_string[numlen]
      numlen = numlen +1
WeND
pause 200
power = 1    ' Power of ten initially starting with 16^0
'**********************
' This subtracts integer 48 from ascii numerals, which have ascii values
' 0=48 1=49 2=50 etc.  Then multiplies it times the place value of that
' number - 1's, 16's, 256's, 4096's etc using increasing powers of 16.
'**********************
for i = numlen-2  to 0 STEP -1
    IF data_string[i] > 57 THEN   'ASCII exceeds decimal numbers, must be hex
        'subtract 55 from ascii hex letters to get numbers
        asciiNumber = asciiNumber + ((data_string[i]-55) * power)
    else
        asciiNumber = asciiNumber + ((data_string[i]-48) * power)
    endif
    power = power * 16
NEXT
RETURN



'**************************************************************************
'  FUNCTION:      ASCIIDECTOINTEGER
'  INPUT:         data_String BYTE array of ASCII decimal number characters 
'  OUTPUT:        asciiNumber WORD var with integer value of ascii text number  
'  PURPOSE:       Converts ascii string of decimal numbers into integer WORD 
'  NOTE:          Will stop when a non-decimal character is encountered.
'**************************************************************************
ASCIIDECTOINTEGER:
numlen = 0
asciiNumber = 0
char = "1"
While (char !=0 AND (char >= "0" AND char <="9"))
      char = data_string[numlen]
      numlen = numlen +1 
WeND
power = 1    ' Power of ten initially starting with 10^0
'**********************
' This subtracts integer 48 from ascii numerals, which have ascii values
' 0=48 1=49 2=50 etc.  Then multiplies it times the place value of that
' number - 1's, 10's, 100's, 1000's etc using increasing powers of 10.
'**********************
for i = numlen-2  to 0 STEP -1
    asciiNumber = asciiNumber + ((data_string[i]-48) * power)
    power = power * 10
NEXT
RETURN
    
'**************************************************************************
'  FUNCTION:      GPSCOMPUTECHECKSUM
'  INPUT:         gPSSentenceID BYTE array, 5 byte
'                 gPSSentenceString BYTE array 
'  OUTPUT:        checkSum BYTE var, containing computed hex checksum
'                 gPSSentenceCheckSumValid BIT var
'  PURPOSE:       Computes checksum of GPS Sentence ID plus sentence data.
'                 Uses bitwise XOR of each successive character. 
'**************************************************************************
GPSCOMPUTECHECKSUM:
Checksum = 0
CHARPOS = 0   'first compute the checksum of the GPS Sentence ID
WHILE CHARPOS < 5 
      CHAR = gPSSentenceId[charpos]
      IF char = 0 THEN FIRSTCHECKDONE     
      checkSum = checkSum ^ CHAR        'Bitwise XOR checksum
      charpos = charpos + 1     
WEND
FIRSTCHECKDONE:
'************************
'Compute the checksum of the rest of the sentence
' starting with the checksum from the GPS Sentence ID.
'************************
charPos = 0
WHILE CHARPOS < 80 
      CHAR = gPSSentenceString[charpos]
      IF CHAR = "*" THEN CHECKDONE
      IF char = 0 THEN CHECKDONE      
      checkSum = checkSum ^ CHAR         'Bitwise XOR checksum
      charpos = charpos + 1     
WEND
CHECKDONE:
      RETURN


'**************************************************************************
'  FUNCTION:      GPSMATCHCHECKSUM
'  INPUT:         gPSSentenceString BYTE array with whole NMEA Sentence 
'                 checksum BYTE var computed checksum
'  OUTPUT:        gPSsentenceCheckSumValid BIT var  
'  PURPOSE:       Find checksum in NMEA string, starts with asterisk.
'                 compares reported checksum to computed checksum
'**************************************************************************
GPSMATCHCHECKSUM:
i=0
char = 1
WHILE char !="*"     'Search for asterisk checksum in array
      char = gPSSentenceString[i]
      i =i+1 
      IF char = 0 THEN 
         GOSUB GpsBadChecksum       'If no * found, abort checking
      endif
WEND 
data_string[0] = gPSSentenceString[i]     'transfer checksum from discovered
data_string[1] = gPSSentenceString[i+1]     'location.
data_String[2] = 0 'end with null
GOSUB ASCIIHEXTOINTEGER         'converts the ascii hex to integer
IF checksum = asciiNumber THEn 
       gPSSentenceChecksumValid = 1  'valid
   ELSE
       GOSUB GpsBadChecksum 'not valid
ENDIF
'HSEROUT ["Converted HEX: ",HEX2 asciiNumber, " Checksum Match: ",DEC gPSSentenceChecksumValid, CR]
RETURN

NoData:
gPSDataReceived = 0
HSEROUT ["No Serial data is being received at all!",CR]
RETURN

GpsBadChecksum:
gPSsentenceChecksumValid = 0
HSEROUT ["Corrupted data received from GPS.",CR]
RETURN

GpsNoFix:
gPSFixValid = 0
HSEROUT ["The GPS is working, but we don't have a position fix.",CR]
RETURN


GOTO START





' GPRMC
'RMC  = Recommended Minimum Specific GPS/TRANSIT Data
'
'1    = UTC of position fix
'2    = Data status (V=navigation receiver warning)
'3    = Latitude of fix
'4    = N or S                                  
'5    = Longitude of fix
'6    = E or W
'7    = Speed over ground in knots
'8    = Track made good in degrees True
'9    = UT date
'10   = Magnetic variation degrees (Easterly var. subtracts from true course)
'11   = E or W
'12   = Checksum
'****************************************************************************
' GPGGA
'GGA  = Global Positioning System Fix Data
'
'1    = UTC of Position
'2    = Latitude
'3    = N or S
'4    = Longitude
'5    = E or W
'6    = GPS quality indicator (0=invalid; 1=GPS fix; 2=Diff. GPS fix)
'7    = Number of satellites in use [not those in view]
'8    = Horizontal dilution of position
'9    = Antenna altitude above/below mean sea level (geoid)
'10   = Meters  (Antenna height unit)
'11   = Geoidal separation (Diff. between WGS-84 earth ellipsoid and
'       mean sea level.  -=geoid is below WGS-84 ellipsoid)
'12   = Meters  (Units of geoidal separation)
'13   = Age in seconds since last update from diff. reference station
'14   = Diff. reference station ID#
'15   = Checksum
'****************************************************************************

Initial URL
http://www.utarc.org/wiki/index.php?title=Source_Code

Initial Description
Messy, yes, but it's available anyway.

Initial Title
PicBasic Interfacing PICMicro 18F to RTC and GPS

Initial Tags


Initial Language
PicBasic