Программирование BASCOM

GPS спидометр


Идея была сделать GPS спидометр для моторной лодки, чтобы можно было вмонтировать в панель, как обычный прибор. Вот результат:



Функции:
  • GPS Спидометр
  • GPS координаты
  • Одометр
  • Текущий пробег, время в пути.
  • Данные о предыдущей поездке.
  • Суточный пробег
  • Максимальная скорость
  • Тахометр
  • Моточасы
  • Вольтметр
  • Температура двигателя с индикацией перегрева
  • Часы

В приборе используется:
Большой ЖКИ фирмы МЭЛТ 20x4 с размером рабочего поля 123мм на 43мм.
GPS приемник MC-1513.  
Датчик температуры DS18B20.



Кнопка 1 служит для переключения режимов отображения (Главный экран->координаты->одометры->счетчик моточасов).
Кнопка 2 сбрасывает все накопленные данные (нужно удерживать нажатой в момент подачи питания).









Испытания пока проводились только на автомобиле (зима) и надо сказать, что он там прижился.











«Камни».
При пропадании питания все накопленные данные записываются в энергонезависимую память.
Момент выключения определяется с помощью компаратора.
При использовании, в качестве резервного питания, конденсатора 2200мкФ удавалось записать только 4 байта. С ионистором на 1F устройство работает после отключения питания около 18 секунд, но поскольку испытания проводились в машине при минусовой температуре, оказалось, что емкость ионистора падала в 10 раз. Хотя везде написано про их широкий температурный диапазон. В помещении свободно хватало ионистора в 0.1F.

Модуль GPS MC-1513, при наличии на выходе RXA напряжения меньше 3.6 вольта, не подает признаков жизни, видимо так он определяет наличие подключения к принимающему устройству. (Два дня отнял...). Надо ещё сказать, что при минусовой температуре GPS перестает ловить спутники.

На данный момент не решена только одна задача:
При кратковременном отключении питания (а контроллер продолжает работать от ионистора) происходит вызов процедуры сохранения данных. Но после выхода из нее не редко происходит зависание контроллера. Положение спасает Watch Dog таймер без каких либо последствий для информации, но факт существования проблемы остается.

Дополнительные материалы.

При написании программы использовались части кода из статьи GPS логгер.
Автор: Radan
'Yashnov Dmitry N.Novgorod
'*********************************
'*   Boat Comp V.1  Y.D.E. 2013  *
'*********************************

'Маршрутный компьютер для моторной лодки
'GPS Спидометр,одометр, время в пути, суточный пробег, вольтметр, температура двигателя,часы, GPS координаты, максимальная скорость,
'тахометр, моточасы

'***FUSES***
'Boden level - 1
'Boden - 0
'Ext Crystal 101111
'OCD - 1
'JTAG - 1
'SPI - 0
'CKOPT - 1
'Erase EEPROM - 0
'Boot size - 00
'Reset vector -1
'***Концы***
'1wire  - PORTA.1
'Umeter - PORTA.4 (ADC4)
'Taho   - PORTB.1 (T1)
'Kn1    - PORTA.3
'Kn2    - PORTA.2
'

$regfile = "m16def.dat"
$crystal = 11059000
$baud = 9600

$hwstack = 40
$swstack = 20
$framesize = 40

Config Lcdpin = Pin , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5 , E = Portc.1 , Rs = Portc.0
Config Lcd = 20 * 4
Config Serialin = Buffered , Size = 100
Config Adc = Single , Prescaler = Auto , Reference = Internal_2.56
Start Adc
Config 1wire = Porta.1
Config Watchdog = 2048

Const Delitel = 1                                           'делитель количество импульсов на один оборот двигателя
Const T_control = 95                                        'пороговое значение температуры для предупреждения

Dim Flag As Bit
Dim Data_izm As Bit
Dim Tputi_h As Byte
Dim Tputi_m As Byte
Dim Tputi_s As Byte

Dim Tputi_h_last As Byte
Dim Tputi_m_last As Byte

Dim Kn_on As Bit

Dim Um As Byte
Dim Uh As Byte
Dim C As Byte , A As Byte
Dim Dsp As Byte
Dim Dsp1 As Byte
Dim Spd0 As Byte
Dim Ar(8) As Byte
Dim Leng As Byte
Dim Hh As Byte
Dim Max_speed As Byte

Dim U As Word


Dim T As Integer , I As Integer
Dim Speed As Integer
 Dim Road_last As Single
 Dim Spd2 As Single
 Dim Spd3 As Single
 Dim Road As Single

 Dim Road_all As Single
 Dim Road_day As Single
 Dim Tah As Single
Dim Moto_h As Integer
Dim Moto_m As Byte
Dim Moto_s As Byte

Dim Day As String * 2
Dim T_day As String * 2

Dim Temp As String * 6
Dim Uts As String * 10
Dim Hhs As String * 2
Dim Mm As String * 2
Dim Dot As String * 1
Dim Av As String * 2
Dim Lat As String * 12
Dim Ns As String * 2
Dim Lon As String * 13
Dim Ew As String * 2
Dim Spd As String * 6
Dim Crs As String * 6
Dim Da4 As String * 8
Dim Sat As String * 2
Dim Gpsfix As String * 1
Dim Ee_road_last As Eram Single
Dim Ee_road_all As Eram Single
Dim Ee_road_day As Eram Single
Dim Ee_tputi_h As Eram Byte
Dim Ee_tputi_m As Eram Byte
Dim Ee_max_speed As Eram Byte
Dim Ee_day As Eram String * 2
Dim Ee_moto_h As Eram Integer
Dim Ee_moto_m As Eram Byte
Dim Ee_moto_s As Eram Byte

Deflcdchar 0 , 19 , 9 , 5 , 18 , 29 , 1 , 1 , 32            ' спецсимволы для ЖКИ
Deflcdchar 1 , 32 , 32 , 10 , 31 , 17 , 31 , 31 , 32        '
Deflcdchar 5 , 24 , 26 , 2 , 7 , 2 , 2 , 3 , 32             '

Declare Sub Getline
Declare Sub Wait_for_string(byval S As String)
Declare Function Read_string() As String

Config Timer0 = Timer , Prescale = 256
Config Timer1 = Counter , Edge = Falling                    'подсчет импульсов тахометра
On Timer0 Pulse:                                            'прерывания для опроса кнопок


Config Pinb.1 = Input                                       '
Config Pinb.3 = Input                                       ' ногу AIN1 на вход
Config Aci = On , Compare = Off , Trigger = Rising          'компаратор задействован для определения момента отключения питания

On Aci Save_eeprom                                          ' подпрограмма прерывания от компаратора для записи в EEPROM


Config Porta = Input
Kn1 Alias Pina.3
Kn2 Alias Pina.2

Cls
Cursor Off Noblink

Data_izm = 0
Dsp = 1
Uts = "0"
Road = 0
Flag = 0
Tputi_h = 0
Tputi_m = 0
Tputi_s = 0


If Kn2 = 0 Then                                             'если во время подачи питания нажата кнопка 2 то стираем все одометры и прочее
  Cls
  Locate 2 , 1 : Lcd "     Erase ODO"
  Ee_road_all = 0
  Ee_road_day = 0
  Day = "01"
  Ee_road_last = 0
  Ee_tputi_h = 0
  Ee_tputi_m = 0
  Ee_max_speed = 0
  Ee_moto_m = 0
  Ee_moto_h = 0
  Ee_moto_s = 0
  Wait 1
End If
'чтение накопленных данных из EEPROM
Road_last = Ee_road_last
Road_all = Ee_road_all
Road_day = Ee_road_day
Max_speed = Ee_max_speed
Tputi_h_last = Ee_tputi_h
Tputi_m_last = Ee_tputi_m
Day = Ee_day
Moto_m = Ee_moto_m
Moto_h = Ee_moto_h
Moto_s = Ee_moto_s

'заставка
Cls
Locate 1 , 1 : Lcd "                    "
Locate 2 , 1 : Lcd "   Boat Comp V1.0   "
Locate 3 , 1 : Lcd "    Y.D.E. 2013     "
Locate 4 , 1 : Lcd "                    "
Wait 1

'начало
Enable Interrupts
Enable Timer0
Enable Aci
Start Ac
Start Watchdog                                              'start the watchdog timer

'основной цикл
Loop:
'запускаем DS18b20
1wreset                                                     ' reset the bus
1wwrite &HCC                                                ' skip rom
1wwrite &H44                                                ' Convert T

Call Wait_for_string( "$GPGGA,")                            ' вызов подпрограмы ожидающий строку, начинающуюся с $GPGGA,
   Sat = Read_string()                                      'разбриаем строку  $GPGGA на состовляющие
   Sat = Read_string()                                      'пропускаем ненужные используя одну переменную
   Sat = Read_string()                                      '
   Sat = Read_string()                                      '
   Sat = Read_string()                                      '
   Gpsfix = Read_string()                                   'если 0 то положение не определено
   Sat = Read_string()                                      ' Количество задействованых спутников

 Call Wait_for_string( "$GPRMC,")                           ' вызов подпрограмы ожидающий строку, начинающуюся с $GPRMC,
                                                            'разбриаем строку  $GPRMC на состовляющие
   Uts = Read_string()                                      'время по гринвичу
   Av = Read_string()

   Lat = Read_string()                                      'широта
   Leng = Len(lat) - 1                                      '
   Lat = Left(lat , Leng)                                   '

   Ns = Read_string()                                       'северная южная
   Leng = Len(ns) - 1                                       '
   Ns = Left(ns , Leng)                                     '

   Lon = Read_string()                                      'долгота
   Leng = Len(lon) - 1                                      '
   Lon = Left(lon , Leng)                                   '

   Ew = Read_string()                                       'западная восточная
   Leng = Len(ew) - 1                                       '
   Ew = Left(ew , Leng)                                     '

   Spd = Read_string()                                      'скорость в милях в час
   Leng = Len(spd) - 1                                      '
   Spd = Left(spd , Leng)                                   '

   Crs = Read_string()                                      ' курс
   Leng = Len(crs) - 1                                      '
   Crs = Left(crs , Leng)                                   '

   Da4 = Read_string()                                      'дата
   Da4 = Left(da4 , 6)                                      '



    Spd2 = Val(spd)
    Spd2 = Spd2 * 1.852                                     'пересчитываем скорость из миль в км/ч
   If Gpsfix = "0" Then Spd2 = 0                            'если нет фиксации GPS то обнуляем скорость потому как она не верна
    Speed = Int(spd2)                                       'отбрасываем дробную часть для лучшего отображения

   If Speed > Max_speed Then Max_speed = Speed              'запоминаем максимальную скорость
   Spd3 = Spd2 / 3600                                       ' путь пройденый за 1 секунду

   If Spd2 > 2 Then                                         'если скорость меньше 2 км/ч одометры не задействованы
      Road = Road + Spd3
      Road_day = Road_day + Spd3                            'судочный пробег
      Road_all = Road_all + Spd3                            'суммарный пройденый путь

   End If

   Hhs = Left(uts , 2)                                      'выделяем часы минуты
   Hh = Val(hhs)
   Mm = Mid(uts , 3 , 2)

   Hh = Hh + 4                                              'коректировка времени на часовой пояс (Медведевская Москва +4 часа в данном случае)
   If Hh > 23 Then Hh = Hh - 24

    T_day = Left(da4 , 2)                                   'выделяем из даты день
   If Gpsfix <> "0" Then
    If Day <> T_day Then                                    'при смене суток обнуляем данные суточного пробега
    Day = T_day
    Ee_day = Day
    Ee_road_day = 0
    Road_day = 0
    End If
   End If
   If Gpsfix <> "0" And Speed > 3 Then Data_izm = 1         'если есть связь и скорость больше 3 км/ч даем разрешение на сохранение данных в eeprom
   Flag = Not Flag                                          'изменяется каждую секунду
If Flag = 1 Then                                            'мигание точек в часах
 Dot = ":"
Else
 Dot = " "
End If
'******** счетчик времени в пути *********
If Spd2 > 2 Then Incr Tputi_s
'Incr Tputi_s
If Tputi_s > 59 Then
 Incr Tputi_m
 Tputi_s = 0
End If
If Tputi_m > 59 Then
 Incr Tputi_h
 Tputi_m = 0
End If


'************** Напряжёметр ***************
  U = Getadc(4)                                             'читаем АЦП
  Shift U , Right , 2                                       'из 12 бит делаем 8
  'U = U / 2
  Um = U Mod 10 : Uh = U - Um : Uh = Uh / 10                ' выделяем десятые доли вольта
'**************************************'
'читаем DS18b20
1wreset                                                     'reset
1wwrite &HCC                                                'пропуск пзу
1wwrite &HBE                                                'чтение памяти

For I = 1 To 9
  Ar(i) = 1wread()                                          'place into array
Next
 T = 0                                                      'преобразование температуры
 T = Makeint(ar(1) , Ar(2))
 T = T * 10
 T = T / 16
I = T Mod 10 : T = T - I : T = T / 10
If I < 0 Then I = I * -1

If T > T_control Then Dsp = 5                               'контроль перегрева двигателя

Reset Watchdog

If Dsp1 <> Dsp Then                                         'переключатель экранов
 Dsp1 = Dsp
 Cls
 Kn_on = 1
End If

' тахометр
Tah = Timer1
Tah = Tah / 16.6                                            'переводим герцы в обороты в минуту
Tah = Tah / Delitel                                         'делитель количество импульсов на один оборот двигателя
'****** счетчик моточасов ********
If Tah > 0.2 Then                                           'если обороты больше 200 то считаем моточасы
 Incr Moto_s
 If Moto_s > 59 Then
  Incr Moto_m
  Moto_s = 0
 End If
 If Moto_m > 59 Then
  Incr Moto_h
  Moto_m = 0
 End If
End If

'******* Экран перегрева ****************
If Dsp = 5 Then
 If Flag = 1 Then                                           'мигаем страшными словами
  Locate 1 , 1 : Lcd "####################"
  Locate 2 , 1 : Lcd "#### WARNING!!! ####"
  Locate 3 , 1 : Lcd "#### t " ; T ; "." ; I ; " C "
  Locate 3 , 16 : Lcd " ####"
  Locate 4 , 1 : Lcd "####################"
 Else
  Locate 1 , 1 : Lcd "                    "
  Locate 2 , 1 : Lcd "     WARNING!!!     "
  Locate 3 , 1 : Lcd "     t " ; T ; "." ; I ; " C "
  Locate 3 , 16 : Lcd "     "
  Locate 4 , 1 : Lcd "                    "
 End If
End If

'******** Главный экран *************************
If Dsp = 1 Then
' тахометр

If Tah > 0.1 Then
Locate 2 , 1 : Lcd "Tah " ; Fusing(tah , "#.#") ; " Rpm "
Else
Locate 2 , 1 : Lcd "               "
End If

Timer1 = 0

'дата и кол-во спутников
 If Gpsfix <> "0" Then
  Locate 1 , 1 : Lcd Chr(0) ; Sat ; "   " ; Left(da4 , 2) ; "/" ; Mid(da4 , 3 , 2) ; "/" ; Right(da4 , 2) ; "  "
 Else
  Locate 1 , 1 : Lcd "Connecting...  "
 End If
 'часы
 If Hh < 10 Then
   Locate 1 , 16 : Lcd "0" ; Hh ; Dot ; Mm
 Else
   Locate 1 , 16 : Lcd Hh ; Dot ; Mm
 End If
 'температура
 Locate 2 , 16
 If T = 0 Then Lcd "     "
 If T < 0 Then Lcd Chr(5) ; T ; " "
 If T > 0 And T < 10 Then Lcd Chr(5) ; T ; "." ; I ; "C"    '
 If T >= 10 And T < 100 Then Lcd Chr(5) ; T ; "." ; I       '
 If T >= 100 Then Lcd Chr(5) ; T ; "C"
 'вольтметр
 If Uh < 11 Then
  If Flag = 0 Then
   If Uh >= 10 Then
    Locate 3 , 16 : Lcd Chr(1) ; Uh ; "." ; Um              '; "v"
   Else
    Locate 3 , 16 : Lcd Chr(1) ; " " ; Uh ; "." ; Um
   End If
  Else
   Locate 3 , 16 : Lcd "     "
  End If
 Else
  If Uh >= 10 Then
   Locate 3 , 16 : Lcd Chr(1) ; Uh ; "." ; Um               '; "v"
  Else
   Locate 3 , 16 : Lcd Chr(1) ; " " ; Uh ; "." ; Um
  End If
 End If
 'скорость
 Locate 3 , 1 : Lcd "Spd< " ; Speed ; " >km/h "

 'одометр
 Locate 4 , 1
 If Road >= 100 Then Lcd "Odo " ; Fusing(road , "####.#") ; "km "
 If Road >= 10 And Road < 100 Then Lcd "Odo 0" ; Fusing(road , "####.#") ; "km "
 If Road < 10 Then Lcd "Odo 00" ; Fusing(road , "####.#") ; "km "


 'время в пути
 If Tputi_h < 10 Then
  Locate 4 , 13 : Lcd "0" ; Tputi_h ; ":"
 Else
  Locate 4 , 13 : Lcd Tputi_h ; ":"
 End If
 If Tputi_m < 10 Then
  Locate 4 , 16 : Lcd "0" ; Tputi_m ; ":"
 Else
  Locate 4 , 16 : Lcd Tputi_m ; ":"
 End If
 If Tputi_s < 10 Then
  Locate 4 , 19 : Lcd "0" ; Tputi_s
 Else
  Locate 4 , 19 : Lcd Tputi_s
 End If


End If


'******** экран навигации *************************
If Dsp = 2 Then
 Locate 1 , 1 : Lcd "CѕyїЅёєё " ; Sat ; " Єёєc " ; Gpsfix ; " "
 Locate 2 , 1 : Lcd "¬ёp " ; Lat ; " " ; Ns
 Locate 3 , 1 : Lcd "аo»ґ " ; Lon ; " " ; Ew
 Locate 4 , 1 : Lcd "CєopocїД " ; Fusing(spd2 , "###.#") ; " Kј/А "
End If
'******** экран одометров *************************
If Dsp = 3 Then
 Locate 1 , 1 : Lcd "Max Speed " ; Max_speed ; " km/h "
 Locate 2 , 1 : Lcd "Last " ; Fusing(road_last , "####.#") ; "km "
 Locate 3 , 1 : Lcd "Day  " ; Fusing(road_day , "####.#") ; "km "
 Locate 4 , 1 : Lcd "All  " ; Fusing(road_all , "####.#") ; "km "

 If Tputi_h_last < 10 Then
  Locate 2 , 14 : Lcd "<0" ; Tputi_h_last ; ":"
 Else
  Locate 2 , 14 : Lcd "<" ; Tputi_h_last ; ":"
 End If
 If Tputi_m_last < 10 Then
  Locate 2 , 18 : Lcd "0" ; Tputi_m_last ; ">"
 Else
  Locate 2 , 18 : Lcd Tputi_m_last ; ">"
 End If
End If
'******** экран моточасов *************************
If Dsp = 4 Then
 Locate 1 , 5 : Lcd "Moto hours "
 Locate 3 , 1 : Lcd "   << " ; Moto_h ; "h " ; Moto_m ; "m " ; Moto_s ; "s >> "
End If

Goto Loop




'------------------------------------------------------
Sub Wait_for_string(byval S As String) As String            'подпрограмма ожидания строки  $GPRMC в данных GPS приемника
Local Ii As Byte
Local Cc As Byte
Ii = 1
M1:
   Cc = Waitkey()
   If Cc <> Mid(s , Ii , 1) Then
      Goto M1
   Else
      Incr Ii
      If Ii > Len(s) Then Goto M2
      Goto M1
   End If
M2:
End Sub

'------------------------------------------------------         'подпрограмма "разбора " строки $GPRMC на части
Function Read_string() As String
Local Cc As Byte
Local Ss As String * 14

Ss = ""
Do
   Cc = Waitkey()                                           'ожидает символ
      If Cc <> "," Then Ss = Ss + Chr(cc)

Loop Until Cc = ","
Cc = ""
Read_string = Left(ss , 12)
End Function
End



Save_eeprom:
Reset Watchdog                                              'запись текущего пути и времени в EEPROM по выключении питания. Используется ионистор 0.1Ф для резерв питания
If Data_izm = 1 Then                                        'если данные не менялись (gpsfix=0 и скорость<3) тогда не пишем
Ee_road_last = Road
Ee_road_all = Road_all
Ee_road_day = Road_day
Ee_tputi_h = Tputi_h
Ee_tputi_m = Tputi_m
Ee_max_speed = Max_speed
Data_izm = 0
End If
Ee_moto_m = Moto_m
Ee_moto_h = Moto_h
Ee_moto_s = Moto_s

Return

Pulse:                                                      'кнопки


 If Kn1 = 0 And Kn_on = 1 Then
  Incr Dsp
  Kn_on = 0
  If Dsp > 4 Then Dsp = 1
 End If

Return


End