robert.rozee Guru
Joined: 31/12/2012 Location: New ZealandPosts: 2290 |
Posted: 03:22am 18 Dec 2016 |
Copy link to clipboard |
Print this post |
|
hi, below is a small demo showing how to achieve the following:
1. configure a SiRF chipset to output a single NMEA sentence repeatedly 2. implement serial input using an interrupt, data saved in a circular line buffer 3. use VT100 codes to clear screen and position cursor 4. extract comma delimited data from a string
NMEA sentences from the GPS are terminated with CR+LF, and this pair is used to split up the data stream into individual lines. up 9 lines can be held in the circular line buffer before it overflows.
the SiRF chipset can be configured with static navigation on or off. when turned on, static navigation attempts to eliminate 'wandering' causing the appearance of false motion. in general, it does this poorly, and so by default the below code turns static navigation off. the SiRF3 default is for it to be turned on.
cheers, rob :-)
' demonstration of SiRF GPS configuration and ' serial port input with circular line buffer ' (c) Robert Rozee 2016
' configure circular line buffer ' ******************************
Dim CB$(10) head = 1 tail = 1 running = 0
A$ = "" B$ = ""
Const clreol$ = Chr$(27)+"[K"
Open "COM1:9600,1024,isr,S2" As #1
' configure SiRF chipset ' **********************
SS1$ = "$PSRF100,0,9600,8,1,0*0C"+Chr$(13)+Chr$(10) For I = 1 To 10: Read J: SS2$ = SS2$+Chr$(J): Next I ' disable static nav For I = 1 To 10: Read J: SS3$ = SS3$+Chr$(J): Next I ' enable statis nav For I = 1 To 32 Read J If (I>=5) And (I<=28) Then K = K+J ' checksum accumulated in K If I=29 Then J = K \ 256 If I=30 Then J = K Mod 256 SS4$ = SS4$+Chr$(J) Next I
Print #1, SS1$; ' enter SiRF binary mode Pause 100 Print #1, SS2$; ' disable static navigation Pause 100 Print #1, SS4$; ' return to NMEA mode Pause 100 running = 1 clrscr
' main loop ' *********
Do If head<>tail Then ' collect NMEA sentence from buffer B$ = CB$(tail) tail = (tail Mod 10)+1 validate(B$) ' verify checksum EndIf
If Instr(B$,"$GPRMC")=1 Then ' check if sentence is the one we want
Print at$(1,4); B$; clreol$ Print clreol$
For I = 1 To 16 ' extract parameters one at a time J = Instr(B$,",") If J=0 Then Exit For B$ = Mid$(B$,J+1) '$GPxxx is first discarded (param 0)
If I=1 Then GPS.time = Val(B$) If I=2 Then GPS.OK = (Left$(B$,1)="A") If I=3 Then K = Instr(B$,".") IP% = Val(Left$(B$,K-1)) FP% = Val(Mid$(B$,K+1)) GPS.lat% = IP%*10000+FP% ' 1/10000th of a degree per count EndIf If (I=4) And (Left$(B$,1)="S") Then GPS.lat% = -GPS.lat%
If I=5 Then K = Instr(B$,".") IP% = Val(Left$(B$,K-1)) FP% = Val(Mid$(B$,K+1)) GPS.long% = IP%*10000+FP% ' 1/10000th of a degree per count EndIf If (I=6) And (Left$(B$,1)="W") Then GPS.long% = -GPS.long%
If I=7 Then GPS.sog = Val(B$)*1.852 ' convert knots to km/h If I=8 Then GPS.cog = Val(B$) If I=9 Then GPS.date = Val(B$)
Next I
time.H = GPS.time \ 10000 time.M = (GPS.time \ 100) Mod 100 time.S = GPS.time Mod 100
date.D = GPS.date \ 10000 date.M = (GPS.date \ 100) Mod 100 date.Y = GPS.date Mod 100
Print at$(1,8); Print "time = ", Print Str$(time.H,2,0," "); "h", Print Str$(time.M,2,0,"0"); "m", Print Str$(time.S,2,0,"0"); "s"
Print "date = ", Print Str$(date.Y,2,0,"0"); "y", Print Str$(date.M,0,0,"0"); "m", Print Str$(date.D,0,0,"0"); "d" Print Print "lat = ", GPS.lat% \ 10000, ". "; Abs(GPS.lat% Mod 10000) Print "long = ", GPS.long% \ 10000, ". "; Abs(GPS.long% Mod 10000) Print Print "sog = ", GPS.sog; " km/h"; clreol$ Print "cog = ", GPS.cog; " degrees"; clreol$ Print If GPS.OK Then Print "FIX OK"; Print clreol$;
EndIf
B$ = ""
Loop End ' end of program
Sub isr ' serial port handler Local I, S$ length 80 S$ = Input$(72,#1) ' grab data into temporary buffer If running Then A$ = Right$(A$,255-Len(S$))+S$ ' add to end of linear buffer I = Instr(A$,Chr$(13)+Chr$(10)) ' check for eol marker (CR+LF) Do While I<>0 CB$(head) = Left$(A$,I-1) ' transfer into circular buffer head = (head Mod 10)+1 If I<254 Then A$ = Mid$(A$,I+2) Else A$="" I = Instr(A$,Chr$(13)+Chr$(10)) ' check for any more eol markers Loop EndIf End Sub
Sub validate(B$) ' verify B$ is undamaged Local header, footer, checksum, I header = Instr(B$,"$") ' header marker, $ footer = Instr(B$,"*") ' footer marker, * checksum = 0 If (header<>1) Or (footer<>(Len(B$)-2)) Then B$ = "" Else For I = header+1 To footer-1 ' xor together everything in between checksum = checksum Xor Asc(Mid$(B$,I,1)) Next I If Hex$(checksum,2)<>Right$(B$,2) Then B$ = "" EndIf End Sub ' B$ is cleared if anything is wrong
Function at$(x,y) ' VT100 position cursor at$ = Chr$(27)+"["+Str$(Y)+";"+Str$(X)+"H" End Function
Sub clrscr ' VT100 clear screen and home cursor Print Chr$(27)+"[2J"+Chr$(27)+"[H"; End Sub
' disable static navigation Data &hA0, &hA2 ' count + header Data &h00, &h02 ' payload length (2 bytes) Data &h8F, &h00 ' command + SN flag Data &h00, &h8F ' payload checksum Data &hB0, &hB3 ' footer
' enable static navigation Data &hA0, &hA2 ' count + header Data &h00, &h02 ' payload length (2 bytes) Data &h8F, &h01 ' command + SN flag Data &h00, &h90 ' payload checksum Data &hB0, &hB3 ' footer
' return to NMEA mode Data &hA0, &hA2 ' count + header Data &h00, &h18 ' payload length (24 bytes) Data &h81, &h02 ' command + mode Data &h00, &h01 ' GGA (1) (interval + CS flag) Data &h00, &h01 ' GLL (interval + CS flag) Data &h00, &h01 ' GSA (1) (interval + CS flag) Data &h00, &h01 ' GSV (5) (interval + CS flag) Data &h01, &h01 ' RMC (1) (interval + CS flag) ## 1 sec ## Data &h00, &h01 ' VTG (1) (interval + CS flag) Data &h00, &h01 ' MSS (interval + CS flag) Data &h00, &h00 ' <unused> Data &h00, &h01 ' ZDA (interval + CS flag) Data &h00, &h00 ' <unused> Data &h25, &h80 ' baud rate (9600) Data &hFF, &hFF ' payload checksum (calculated at runtime) Data &hB0, &hB3 ' footer
[updated to account for multiple <CR><LF> markers in a single read]Edited by robert.rozee 2016-12-28 |