'********************************************************************
'* GPS Coordinate display on LCD
'* uP:          AT89S8313
'* Language:    BASCOM-AVR 1.11.7.4
'* Date:        2005.Jan.22
'* Version:     V2.00
'* Author:      Brett England
'********************************************************************
$regfile = "2313def.dat"
$crystal = 8000000
$baud = 4800
 
' condition compilation flag
Const Debug = 0
 
#if Debug
  Dim Temp_i As Byte
#endif
 
Dim Rs232_exit As Byte                            ' Sec count for RS232 timeout
Dim Read_ok As Bit                                ' Valid GPS frame found
Dim Data_ok As Bit                                ' Start of GPS frame
Dim Read_num As Byte                              ' RS232 character count
 
Dim S2 As String * 16                             ' LCD output buffer
 
Dim Gps_state As Bit
Dim Gps_date As String * 7                        ' DDMMYY + comma
Dim Gps_time As String * 6                        ' HHMMSS
Dim Latitude As String * 9
Dim Longitude As String * 10
Dim North_south As Byte                           ' N/S
Dim East_west As Byte                             ' E/W
 
Dim Spin_c As Bit                                 ' Toggles when no data Rx
 
Dim Temp_j As Byte
 
Dim Time1_count As Byte                           ' Second ticker
Dim Time1_store As Byte
Dim Time1_ok As Bit                               ' Internal timer overflow ind
Dim Eventime As Bit                               ' Set every other second
 
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.3 , Rs = Portb.2
Config Lcd = 16 * 1                               'configure lcd screen
 
 
' Once enabled, the timer counts each clock period (or you can select a
' divided down input clock if you prefer). When the timer overflows (65536
' counts) you get an interrupt. With a 8MHz clock, this doesn't work out to
' anything very useful. At 8MHz, each clock pulse is 125nS and 65536 of them
' is 8.192 milliseconds.
 
' I want a timer that resolves to 1000mS, so the first step is to divide down
' the input clock .  Input clock to divide by 256, so now each clock pulse is
' worth (8.192/256)=32uS.
 
' The trick is to preload the counter with a value that will cause it to count
' for 1000mS. Each time the counter expires, you can force the new number back
' into the timer register. We need 1/.000032 or 31250 counts. However, the
' counter expires at 65536, so the correct number to preload is 65536-31250 or
' 34285 This way, the timer will count up 31250 counts (1 second) and
' expire.
 
Const 1000ms = 34285
Config Timer1 = Timer , Prescale = 256
 
On Timer1 Timer1_int                              ' Timer Overflow ISR
On Urxc Rec_rs232                                 ' Serial Rx ISR
 
Cls
Cursor Off Noblink
 
Time1_count = 0 : Timer1 = 1000ms : Time1_ok = 0 : Spin_c = 0
 
Start Timer1
Enable Timer1
Enable Interrupts
 
' Main Program LOOP
'   Screen updates rotate every 2 seconds
'      T+1 - Latitude
'      T+3 - Longitude
'      T+5 - Date/Time
'   GPS unit polling occurs at
'      T+0,T+2,T+4
Do
  If Time1_ok = 1 Then
      Read_ok = 0 : Read_num = 0 : Data_ok = 0
 
      Stop Timer1
      ' Every even second check GPS
      If Eventime = 0 Then
         Gps_date = "" : Gps_time = "" : Latitude = "" : Longitude = ""
         Gps_state = 0
         Gosub Rs232_r
      Else
        ' Odd duty cycle tasks (2sec spacing)
        If Time1_count = 1 Then
           If North_south = 78 Then               ' "N" -> 78
              S2 = "North "
           Else
              S2 = "South "
           End If
           S2 = S2 + Latitude
         Elseif Time1_count = 3 Then
           If East_west = 69 Then                 ' "E" -> 69
              S2 = "East "
           Else
              S2 = "West "
           End If
           S2 = S2 + Longitude
         Elseif Time1_count = 5 Then
           S2 = Gps_date + " " + Gps_time
         End If
      End If
 
' Animate symbol to show activity when no valid GPS data found
      If Gps_state = 0 Then
         S2 = "No GPS Frame "
         If Spin_c = 0 Then
            S2 = S2 + "*"
            Set Spin_c
         Else
            S2 = S2 + "+"
            Reset Spin_c
         End If
      End If
 
      Cls
      Lcd S2
 
      Reset Time1_ok
      Start Timer1
   End If
Loop
 
' Timer interrupt handler
Timer1_int:
   Timer1 = 1000ms
   Set Time1_ok
   Incr Time1_count
   Incr Rs232_exit
   If Time1_count > 5 Then Time1_count = 0        ' 6sec wrap - 0..5
   Eventime = Time1_count.0
   Return
 
' Decode the following string from an Etrex GPS receiver
'$GPRMC,103044,A,5125.5210,N,00012.3645,W,0.0,304.9,290105,2.6,W,A*1E
'12345678901234567890123456789012345678901234567890123456789012345678
'         11111111112222222222333333333344444444445555555555666666666
Rec_rs232:
   Incr Read_num
 
   If Udr = 36 Then                               '"$"-->36
      Read_num = 1 : Data_ok = 1 : Temp_j = 0
   Elseif Data_ok = 1 Then
      Select Case Read_num
         Case 6:
            If Udr <> 67 Then Data_ok = 0         '"C"-->67
         Case 8 To 13:
            Gps_time = Gps_time + Chr(udr)
         Case 15:
            If Udr = 65 Then Gps_state = 1        '"A"-->65
         Case 17 To 25:
            Latitude = Latitude + Chr(udr)
         Case 27:
             North_south = Udr                    ' N/S indicator
         Case 29 To 38:
            Longitude = Longitude + Chr(udr)
         Case 40:
             East_west = Udr                      ' E/W indicator
' The next two parameters after E/W indicator are:
' Speed over ground, Course over ground - They vary dynamically in size.
         Case Is > 40:
' Note: The gps_date var will contain the date plus the trailing comma.
' Start on 3rd comma after E/W indicator
            If Temp_j = 3 Then Gps_date = Gps_date + Chr(udr)
            If Udr = 44 Then Incr Temp_j                    '","-->44
            If Temp_j >= 4 Then Read_ok = 1
      End Select
   End If
 
   #if Debug
       ' Display 1st 16 characters after $ (should be a GPS message)
       ' Note: With this code enabled the interrupt may take too long
       '       to service URXC and characters can be dropped.
       If Data_ok = 1 And Read_num < 17 Then
         Locate 1 , Read_num
         Lcd Chr(udr)
       End If
   #endif
 
   Rs232_exit = 0
   Return
 
Rs232_r:
#if Debug
   Locate 1 , 1
   Lcd "Reading GPS"
#endif
   Reset Usr.7
   Reset Ucr.7
   Enable Urxc
   Rs232_exit = 0
   ' Don't let the RS232 timeout code affect the next task in the main loop.
   Time1_store = Time1_count
   Start Timer1
   Do
   ' The GPS unit sends data every 2secs, so on the 3rd sec if no data has
   ' been received then stop waiting.
      If Rs232_exit > 2 Then Exit Do
   Loop Until Read_ok = 1
   Disable Urxc                                   'disable receive ISR
   Stop Timer1
   Time1_count = Time1_store
   Return