![]() |
Forum Index : Microcontroller and PC projects : GPS Code
Author | Message | ||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
Geoff's GPS code is excellent but as I discovered once you put OPTION EXPLICIT and OPTION DEFAULT NONE in, it breaks For those that are new to Microbasic like I am I thought it might be helpful if I posted the corrected code The code as it is works for GMT in the UK, but Australian DST settings are in the last function - just comment out the UK code and uncomment the DST code Don't forget to set the timezone and USE DST sections correct for where you are. Thanks to WhiteWizzard who helped me with the GMT section and Matherp for his help in understanding why certain sections didn't work and everyone else who helped Hopefully it might be of some use to someone [code]'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' GPS CODE ' ' Geoff Graham, March 2014 ' ' Modified by lew247 (15/08/2016)to include the OPTION statements ' '(Hope you don't mind Geoff) ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Configuration constants OPTION EXPLICIT OPTION DEFAULT NONE DIM INTEGER TIMEZONE DIM INTEGER USEDST DIM INTEGER dms DIM INTEGER dhs DIM INTEGER dme DIM INTEGER dhe DIM INTEGER i DIM INTEGER year DIM INTEGER month DIM INTEGER hour DIM INTEGER sec DIM INTEGER latitude DIM INTEGER longitude DIM INTEGER mins DIM INTEGER min DIM INTEGER yr DIM INTEGER mth DIM INTEGER hr DIM INTEGER day DIM STRING LINE1 DIM STRING LINE2 DIM STRING x,LAT_DEG,lat_min,lat_sec,long_deg,long_min,long_sec DIM INTEGER md(12) DIM STRING arg$(20) ' Configuration constants TimeZone = 0.0 ' hours from GMT (+ or -) UseDST = 1 ' set to 1 to enable daylight saving time (DST/GMT) adjust dms = 3 ' the month that DST starts dhs = 2 ' the hour that DST starts dme = 10 ' the month that DST ends dhe = 2 ' the hour that DST ends DATA 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 FOR i = 1 TO 12: READ md(i): NEXT i OPEN "COM1:9600" AS #1 ' open the GPS serial interface 9600 baud ' this is the main program loop, it never exits '********************************************************************************************* DO KeepSearching: DO GetGPSRecord ' get a GPS record LOOP UNTIL arg$(0) = "GPRMC" ' we only want the RMC record IF arg$(2) <> "A" THEN ' "A" means valid record print "Searching", " For Satellites" ' TEST ***DOES NOT PRINT THIS GOTO KeepSearching ' go back and keep looking ENDIF ' the GPS has the valid time ' first extract the elements of the date/time from the GPS record year = VAL(RIGHT$(arg$(9), 2)) ' extract the date month = VAL(MID$(arg$(9), 3, 2)) day = VAL(LEFT$(arg$(9), 2)) hour = VAL(LEFT$(arg$(1), 2)) ' extract the time min = VAL(MID$(arg$(1), 3, 2)) sec = VAL(MID$(arg$(1), 5, 2)) ' extract and format latitude (data element #3, ddmm.mmmm) lat_deg$ = LEFT$(arg$(3), 2) lat_min$ = MID$(arg$(3), 3, 2) lat_sec$ = str$(cint(val(mid$(arg$(3), 5, 9)) * 60.0)) latitude = val(lat_deg$) + val(lat_min$) / 60.0 + val(lat_sec$) / 3600.0 ' extract and format longitude (data element #5, dddmm.mmmm) long_deg$ = LEFT$(arg$(5), 3) long_min$ = MID$(arg$(5), 4, 2) long_sec$ = str$(cint(val(mid$(arg$(5), 6, 10)) * 60.0)) longitude = val(long_deg$) + val(long_min$) / 60.0 + val(long_sec$) / 3600.0 ' convert the time to minutes since midnight 1st Jan 2014 ' then add/subtract the timezone and if required add daylight saving ' this calculation takes just 15mS at 40MHz mins = GetMins(year, month, day, hour, min) mins = mins + TimeZone * 60 ' adjust for the timezone If mins < GetDST(year, dme, dhe) OR mins > GetDST(year, dms, dhs) THEN mins = mins + 60 'adjust for AWST DST EndIf ENDIF ' because we will display the time at the start of the next second ' we have to add 1 second to the current time sec = sec + 1 IF sec >= 60 THEN sec = 0 : mins = mins + 1 ' finally convert the minutes back into the current date/time Line1 = GetDate$(mins) Line2 = GetTime$(mins) ' we now have the date/time for the next second ready for display ' we have to wait for the end of the data stream from the GPS ' then we wait for the start of the next second and only then update the LCD DO : LOOP WHILE TIMER < 950 ' wait for the data to finish DO : LOOP WHILE INPUT$(200, #1) <> "" ' clear the input buffer DO WHILE INPUT$(1, #1) <> "$" : LOOP ' wait for a new second to start TIMER = 0 ' display the date and time for this second IF sec MOD 5 = 0 THEN '***********displays data below every 5 seconds************ PRINT Line1$ " ", Line2$ " " latitude " " ,(arg$(4))" ",longitude " ",(arg$(6))"" TIME$ = LINE2$ print TIME$ ENDIF LOOP '********************************************************************************************** ' subroutine to get a GPS record into the array arg$() SUB GetGPSRecord DO DO WHILE INPUT$(1, #1) <> "$" : LOOP ' wait for the start FOR i = 0 TO 20 arg$(i) = "" ' clear ready for data DO ' loops until a specific exit x$ = INPUT$(1, #1) ' get the character IF x$ = "," THEN EXIT DO ' new data item, new field IF x$ = "*" THEN EXIT SUB ' end of record, so return with it arg$(i) = arg$(i) + x$ ' add to the data LOOP ' keep going NEXT i ' increment the field LOOP END SUB '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' calculate the minutes since midnight 1st Jan 2014 FUNCTION GetMins(yr as integer, mth as integer, day as integer, hr as integer, min as integer) as integer GetMins = (yr - 14) * (365 * 24 * 60) + ((yr - 13) \ 4) * (24 * 60) GetMins = GetMins + (md(mth) * (24 * 60)) GetMins = GetMins + ((day - 1) * (24 * 60)) GetMins = GetMins + (hr * 60) GetMins = GetMins + min IF (yr - 16) MOD 4 = 0 AND mth > 2 THEN GetMins = GetMins + (24 * 60) END FUNCTION ' convert minutes back into the time (as a string) FUNCTION GetTime$(minutes AS INTEGER) LOCAL hr AS INTEGER, min AS INTEGER, am$ hr = (minutes \ 60) MOD 24 IF hr = 0 THEN hr = 12 min = minutes MOD 60 GetTime$ = STR$(hr) + ":" GetTime$ = GetTime$ + RIGHT$("0" + STR$(min), 2) + ":" GetTime$ = GetTime$ + RIGHT$("0" + STR$(sec), 2) + " " + am$ END FUNCTION ' convert minutes back into the date (as a string) FUNCTION GetDate$(minutes AS INTEGER) LOCAL yr AS INTEGER, mth AS INTEGER, day AS INTEGER, mths$, days$ mths$ = " JanFebMarAprMayJunJulAugSepOctNovDec" days$ = "SunMonTueWedThuFriSat" FOR yr = 14 TO 99 IF minutes < GetMins(yr + 1, 1, 1, 0, 0) THEN EXIT FOR NEXT yr FOR mth = 1 TO 12 IF minutes < GetMins(yr, mth, 1, 0, 0) THEN EXIT FOR NEXT mth mth = mth - 1 day = ((minutes - GetMins(yr, mth, 1, 0, 0)) \ (24 * 60)) + 1 GetDate$ = MID$(days$, ((((minutes \ (24 * 60)) + 3) MOD 7) * 3) + 1,3)+" " GetDate$ = GetDate$ + RIGHT$(" " + STR$(day), 2) GetDate$ = GetDate$ + "-" + MID$(mths$,mth*3,3) + "-" + STR$(yr + 2000) END FUNCTION ' get the minutes that GMT will start or end in a month ' modified for UK GMT which starts on the LAST Sunday of the month FUNCTION GetDST(yr AS INTEGER, mth AS INTEGER, hr AS INTEGER) AS INTEGER LOCAL as INTEGER d, m, n m = GetMins(yr, mth, 1, hr, 0) d = ((m \ (24 * 60)) + 3) MOD 7 m = m + (((7 - d) MOD 7) * 24 * 60) n = GetMins(yr, mth + 1, 1, 0, 0) do while m + (7 * 24 * 60) < n m = m + (7 * 24 * 60) loop GetDST = m END FUNCTION ' get the minutes that DST will start or end in a month 'FUNCTION GetDST(yr, mth, hr) ' LOCAL d, m ' m = GetMins(yr, mth, 1, hr, 0) ' d = ((m \ (24 * 60)) + 3) MOD 7 ' GetDST = m + (((7 - d) MOD 7) * 24 * 60) 'END FUNCTION [/code] |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
EDIT I've set it to it sets the Micromite clock to the correct time (TIME$ = LINE2$ ) If you don;t want that comment it out or delete the line also I've got it looping every 5 seconds - this was only so I could see it was working properly |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
Sorry, But I've gotta be blunt... The two examples I see of Geoff's code using GPS are the Boat Computer & the Super Clock. In both cases he explicitly declares variables.... [Code] ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' Boat Computer ' Geoff Graham, Feb 15 ' ' Requires MMBasic 5.1 or later and an ILI9341 based LCD panel with touch ' Plus a GPS module ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Option autorun on Option explicit Option default integer AND ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' Super Clock ' Geoff Graham, April 2016 ' ' Requires MMBasic 5.1 or later and an ILI9341 based LCD panel with touch ' Plus a DS3231 Real Time Clock or a GPS module ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Option Explicit Option Default None [/code] Everyone should. You've defied this practice, sorry, [Quote=Lew247]BTW the reason I don't use OPTION EXPLICIT..... [/quote] That is just asking for trouble, others have said it.... Defined variables removes the unknown.. String is:- "ABC", or "Abc123", or "123" where 123 are just like other letters but numbers. Integer is 1 or 2 or 3, even 2745; ALL whole numbers, no decimals. Float is:- Numbers with decimals. So "123" can be a string, just like "ABC"; BUT you can't do something like multiply 123 by 2 if its a String, Just like you can't multiply ABC by 2; It makes no sense. That's why declaring variables is so important. Cheers Phil |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
I wish I'd see the boat computer and super clock The one I saw was This I really don't get "You've defied this practice, sorry, " And the reason I used OPTION EXPLICIT was I got told off yesterday for NOT using it |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
Hmmm, Ok I hadn't relly looked at that code. In any case, as he didn't declare stuff, it meant variables defaulted to FLOAT, as mentioned on page 64. Like I said, "You can't multiply abc by 2.... But as far as INTEGERS and FLOAT variables are concerned they can interact. Consider it this way, mixing floating and integers... Two floating numbers.... 2.0 & 2.5; 2.0 x 2.5 = 5. A float & an Integer.... 2 & 2.5; (the integer can only be a whole number.....) But still; 2 x 2.5 works, basic takes care of it. If 2 happened to be a String, it becomes just like "ABC", And ABC x 2.5 doesn't work. Hope that explains it a bit more. Cheers. |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
Actually, When you look closely at that code of Geoff's you will see that some variables are "Declared on the Fly"; don't know that that's the correct term. When he uses say;- [Code]UseDST = 0 ' set to 1 to enable daylight saving time (DST) adjust dms = 10 ' the month that DST starts dhs = 2 ' the hour that DST starts dme = 4 ' the month that DST ends dhe = 2 ' the hour that DST ends [/code] They will all be assumed as Floating variables. But a few lines later he uses a variable:- Arg$ and a few more lines down Line1$ & Line2$, In all these cases the dollar sign, "$", on the end, tell Basic that these variables are STRINGs, not FLOATs, which is the default. |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6269 |
Lew, I think the GPS_clock.bas you are referring to was put together before MMBasic had OPTION EXPLICIT. I hate OPTION EXPLICIT and the language I wrote MMEdit in doesn't have it. MMEdit is about 13000 lines now and the number of times I have 'kicked the cat' in frustration because I had a spelling error and ended up using the wrong variable... I use OPTION EXPLICIT to save the cat getting too bruised and save me getting too frustrated. (Animal lovers should be advised that I don't have a cat) Jim VK7JH MMedit |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
And feral cats definitely don't deserve love in Tassie Jim ![]() |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |