Форум РадиоКот https://radiokot.ru/forum/ |
|
GPS-часы точного времени. https://radiokot.ru/forum/viewtopic.php?f=22&t=166781 |
Страница 1 из 1 |
Автор: | goldskif [ Вт ноя 12, 2019 18:24:42 ] | ||||
Заголовок сообщения: | GPS-часы точного времени. | ||||
Решил вот сделать часы на основе китайского чипа topgnss gn-701, который выдает данные в формате UART/TTL. https://ru.aliexpress.com/i/32947981053.html Данные с чипа представляют собой пакеты с периодом в 1 Гц. Выглядят они так Спойлер$GNRMC,180159.00,A,5137.81278,N,03815.19037,E,2.468,71.94,050119,,,A*4C$GNVTG,71.94,T,,M,2.468,N,4.570,K,A*16 $GNGGA,180159.00,5137.81278,N,03814.19037,E,1,05,2.40,143.2,M,12.1,M,,*45 $GNGSA,A,3,19,06,12,13,,,,,,,,,3.37,2.40,2.37*14 $GNGSA,A,3,87,,,,,,,,,,,,3.37,2.40,2.37*14 $GPGSV,2,1,07,06,14,141,42,09,,,14,12,27,265,10,13,18,193,25*41 $GPGSV,2,2,07,17,59,073,,19,68,128,12,40,29,160,*46 $GLGSV,2,1,05,67,09,251,,68,22,302,,76,39,104,08,77,70,335,*66 $GLGSV,2,2,05,87,44,162,24*5C $GNGLL,5137.81278,N,03915.19037,E,190159.00,A,A*75 В строке GNRMC идут уже обработанные данные, содержащими точное время по Гринвичу, вычисленные координаты и дату. Причем если спутники не найдены, чип все равно выдает информацию о времени. Видимо, там есть собственный таймер. На Attiny2313 идет обработка принятых по UART данных. Код был найден в Интернете и многократно переписан. По сути алгоритма микроконтроллер просто ждет, когда в потоке данных появится буква R, после чего отсчитывает знаки времени и выводит их на индикаторы. Все остальное я выкинул в целях упрощения. Индикаторы газоразрядные ИН-12. управление на оптронах TLP627 Код писался в БаскомАВР. Спойлер' Часы, которые принимают данные с GPS модуля по UART' Прямые фузы 3F-8F-D-FF ' DWEN ' BODLEVEL2 - BODLEVEL1 - BODLEVEL0 - RSTDISBL ' CKDIV8 - CKOUT - SUT0 ' CKSEL3 - CKSEL2 ' Fuse http://homes-smart.ru/fusecalc/?prog=av ... ATtiny2313 ' http://www.engbedded.com/fusecalc $regfile = "attiny2313.dat" $crystal = 3686400 ' 3686400 $baud = 9600 $hwstack = 40 ' default 40 Размер аппаратного стека $swstack = 16 ' default 16 Размер программного стека $framesize = 32 ' default 32 размер области используемой и необходимой для преобразований Ddrb = &B00111111 ' конфиг порта B - 1=Output выход Ddrd = &B0111110 ' конфиг порта D - 0=Input вход Portb.6 = 1 Portb.7 = 1 ' без этой строчки UART вообще гадости пишет на аппаратном порту Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0 'Config Serialin = Buffered , Size = 12 Dim I(6) As Byte Dim Count As Byte Dim Varval As Byte Dim Buf_count As Integer 'Возвращает строку из нескольких символов указанного ASCII кода. Dim S As String * 1 'строка со спутника Dim Sh As String * 2 Dim B As Byte Dim _p As Byte ' poyas +3 Dig1 Alias Portb.0 : Dig2 Alias Portb.1 : Dig3 Alias Portb.2 : Dig4 Alias Portb.3 : Dig5 Alias Portb.4 : Dig6 Alias Portb.5 '***********************[Инициализация прерываний]***************************************** Config Timer0 = Timer , Prescale = 64 , Clear Timer = 0 ' конфигурируем таймер индикации (~500 Гц) Prescale = 1|8|64|256|1024 On Ovf0 Refresh ' обзываем прерывание индикации On Oc0a Dimmer ' вектор прерывания по совпадению (длительность импульса) '***********************[Начало основной программы]**************************************** Enable Interrupts ' разрешаем все прерывания Enable Ovf0 ' и для индикации в частности Enable Oc0a ' загрузка значения яркости катодов в регистр сравнения Ocr0a = 32 ' **********************[Основной цикл] ************************** 'раскладываем строку содержащую идентификатор $GNRMC - пример строк '$GNRMC,082233.00,A,5136.81278,N,09749.19037,E,2.468,71.94,050118,,,A*4c '$GNVTG,71.94,T,,M,2.468,N,4.570,K,A*16 '$GNGGA,180159.00,5136.81278,N,03914.19037,E,1,05,2.40,143.2,M,12.1,M,,*45 ' Config Watchdog = 1024 'определение времени счёта Watchdog 16|32|64|128|256|512|1024|2048 ' Start Watchdog 'включение Watchdog $eeprom 'обращение к блоку данных Data &H34 $data Do Readeeprom _p , 16 B = Waitkey() ' берем символ из буфера в формате ASCII If B = 82 Then Buf_count = 0 ' нашли букву R (82 ascii) Incr Buf_count ' : If Buf_count > 200 Then Buf_count = 20 If Buf_count <> 6 Then S = Chr(b) If Buf_count = 6 Then Sh = S + Chr(b) ' сложение в строку Varval = Val(sh) + _p ' для добавления часового пояса If Varval > 23 Then Varval = Varval - 24 I(1) = Varval / 10 I(2) = Varval Mod 10 ' S = Chr(b) ' 48(ascii)=0 49=1 ... 57=9 ' If Buf_count = 5 Then I(1) = Val(s) ' If Buf_count = 6 Then I(2) = Val(s) If Buf_count = 7 Then I(3) = Val(s) If Buf_count = 8 Then I(4) = Val(s) If Buf_count = 9 Then I(5) = Val(s) If Buf_count = 10 Then I(6) = Val(s) If Buf_count = 11 Then If Pinb.6 = 0 Then Incr _p : If _p > 12 Then _p = 0 : Writeeeprom _p , 16 ' увеличить часовой пояс If Pinb.7 = 0 Then Decr _p : If _p < 1 Then _p = 0 : Writeeeprom _p , 16 ' уменьшить часовой пояс ' Reset Watchdog ' сбросить собаку ' Clear Serialin Waitms 800 End If Loop '***********************[DATA]**************************************************** Dimmer: ' прерывание таймера Т0 (регулировка яркости) Reset Dig1 : Reset Dig2 : Reset Dig3 : Reset Dig4 : Reset Dig5 : Reset Dig6 ' гасим индикатор Return Refresh: ' прерывание таймера Т0 (индикация) ' If Buf_count > 10 Or Buf_count < 5 Then Incr Count : If Count > 6 Then Count = 1 ' выбираем какой разряд сейчас включать Portd = Lookup(i(count) , Digits) ' закидываем в порт код цифры Select Case Count ' включаем соответствующий разряд индикатора Case 1 : Set Dig1 Case 2 : Set Dig2 Case 3 : Set Dig3 Case 4 : Set Dig4 Case 5 : Set Dig5 Case 6 : Set Dig6 End Select ' End If Return Digits: ' это цифры для ИН-12 Data &B0110000 , &B0010000 , &B0001000 , &B0100000 , &B0000100 , &B0101100 , &B0101000 , &B0001100 , &B0100100 В-общем, если кому будет интересно повторить, добавлю исходники и печатные платы. Платы две. Плата для индикаторов отдельно. Питание схемы от 220 Вольт через блок питания на LNK304. Питание анодов тоже от 220 через резистор, чтобы преобразователь не лепить. ----- Идея сделать часы, которые не надо было бы подводить, сама по себе интересна. Но я никак не могу победить странный глюк. Микроконтроллер сам по себе останавливается. Обычно это выглядит как остановка динамической индикации. Ярко горит одна цифра и все. Причем Watchdog не помогает. просто намертво останавливается и все. EEPROM тоже слетает. Напряжение в норме, конденсаторы керамические по питанию есть, квар менял, другие МК покупал.. схему и печатку проверял.. Код много кратно переписывал, выкинув все, что можно..
|
Автор: | mickbell [ Вт ноя 12, 2019 20:45:46 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
Попробуйте писать в еепром отметки о прохождении каких-то ключевых точек. Есть в 2131 еепром? Если нет - может быть, внешнюю пока приделать? чтобы понять, на чём именно затыкается. Анализировать исходник, наверно, бесполезно. Кстати, о птичках. Разбирая строку NMEA, игнорируйте две первые буквы, это прибавит универсальности. Американский Navstar даёт GP, наш ГЛОНАСС - не помню какие. вроде GL, но не уверен. Свои часы, тоже с коррекцией по GPS, я делал на STM32 в порядке освоения семейства МК. |
Автор: | Opamp [ Ср ноя 27, 2019 03:36:44 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
Я когда разбирал NMEA- обратил внимание что там точное время ажно в двух строках бывает, в итоге решил вылавливать строку GPRMC. Точнее- я вылавливал строку, содержащую символы [RMC,], а дальше в этой строке вылавливал символы, стоящие на определенных позициях (с первой позиции после запятой). Код вышел тупой и корявый, я писал в CodeVisionAVR, однако ж часы успешно работают уже второй год и совершенно не глючат. Даже с будильником. Даже умеют включать по будильнику нагрузку (лампочку). Даже с ИК-пультом (чтоб включать лампочку с дивана). Даже с памятью (внешней 24с02)- хранить данные о будильнике если вырубится электричество. Шикарные часики вышли! На Atmega8. Обработку строк запихнул тупо в обработчик прерываний по факту приема чего-нибудь по UART. Никаких еепромов (он частенько слетает), никакой ненужной фигни. Принял, выловил символы, запихнул в глобальные переменные. Показал на индикаторе в определенный момент. Ну а потом еще чего-нить поделал- времени между посылками по уарту вагон. Покажу кусочек кода, мобыть вам пригодится... пишу всегда с подробными комментариями, а то потом не помню нифига. Схему, естественно, приводить не буду- во-первых у вас своя есть, а во-вторых её и не существует... не рисовал. Ограничился сразу разводкой ПП в Layout. //некоторые глобальные переменные unsigned char hrs=0; //часы unsigned char min=0; //минуты bit string_catch=0; //бит вылова заголовка нужной строки GPS unsigned char symb_count=0; //счетчик количества нужных символов после RMC, unsigned long int gprmc=0; //переменная символов вылова заголовка нужной строки GPS ($GPRMC, ловим [ RMC, ]) unsigned char seconds=0; //принятые секунды (для своевременной индикации) //**********************индикация времени************************ void indtime(void) //индикация времени { //ваша процедура вывода глобальных переменных часов и минут на индикатор } // прием данных по USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) { // никаких проверок с буферизациями не ведем. Если нужна проверка- смотрим флаги регистра UCSRA unsigned char data=0; if (string_catch) //если строку уже поймали { switch (symb_count) //смотрим сколько чего уже принято { //считывание текущего времени // $GPRMC,,V,,,,,,,,,,N*76... - когда спутников нет и не было // $GPRMC,042318.00,V,,,,,,,140217,,,N*76... - когда время таки приняли, а координат еще нет и нафиг не нужны case 0: data=UDR; //считываем содержимое регистра (считать обязательно в любом случае!) if (data>0x2F&&data<0x3A) //если там не запятая или еще какой знак { //считаем что время принимается корректно и больше на эту тему не паримся data-=0x30; //доводим до нормального состояния по таблице, данные передаются в ASCII, иметь в виду! hrs=data*10; //десятки часов symb_count++; //увеличиваем счетчик принятых символов (байт) } else //если приняли запятую или х-ню { symb_count=0; //обнуляем счетчик принятых символов string_catch=0; //считаем что строка не принята } break; //далее аналогично, уже без проверки принятого символа case 1: data=UDR; data-=0x30; hrs+=data; symb_count++; break; case 2: data=UDR; data-=0x30; min=data*10; symb_count++; break; case 3: data=UDR; data-=0x30; min+=data; symb_count++; break; case 4: data=UDR; data-=0x30; seconds=data*10; symb_count++; break; case 5: data=UDR; data-=0x30; seconds+=data; if (seconds<1) //один раз в минуту в первую секунду indtime(); //показываем принятое время //если вы используете секунды в индикации- можете делать это ежесекундно. Мне секунды не нужны- я их не показываю. symb_count=0; //обнуляем счетчик принятых символов string_catch=0; //когда все принято- ставим флаг что можно опять ловить строку } } if (!string_catch) //если нужную строку еще не поймали { gprmc=gprmc<<8; //cдвигаем влево на байт gprmc=gprmc|UDR; //в младший байт пишем содержимое UDR if (gprmc==0b01010010010011010100001100101100) //если выловили символы [ RMC, ] string_catch=1; //ставим флаг что строка выловлена } } void main(void) { //ваш основной цикл } |
Автор: | Eddy_Em [ Ср ноя 27, 2019 07:59:05 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
Народ, зачем вы заставляете GPS выдавать всю эту кучу пакетов? У GPS-модулей есть команды, которые позволяют "придавить" вывод той или иной информации. Я в своем хронометре только RMC строку и принимаю - зачем мне остальные? Ну, а прерывание PPS синхронизирует таймер Systick. Сделал на основе модуля L80-R (три с половиной бакса супротив вашего за червонец!). |
Автор: | Opamp [ Ср ноя 27, 2019 15:24:01 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
Народ, зачем вы заставляете GPS выдавать всю эту кучу пакетов? У GPS-модулей есть команды, которые позволяют "придавить" вывод той или иной информации. Затем, что во-первых надо городить ключ на выход уарта, бо модуль хоть и питается от 5 вольт, а на вход ему только 3.3 максимум подавать изволь. У меня VK2828U7G5 - потому что у него хорошая антенна сразу "на борту". Про ваш модуль я вообще не знал, а жаль... Во-вторых все равно надо еще в момент первого включения контроллера все эти команды в него запихивать, так что объем кода шибко меньше не становится. Посему я здраво рассудил что нехай говорит себе что хочет, а слушать мы будем только строку RMC. ![]() |
Автор: | mickbell [ Ср ноя 27, 2019 15:28:39 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
И правильно. Я тоже в своём будильнике проверяю буквы в принимаемой строке; если она не RMC, то просто на неё плюю... тьфу, игнорирую её. Быстродействия STM32 на это хватает. ![]() |
Автор: | Eddy_Em [ Ср ноя 27, 2019 17:17:19 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
Opamp писал(а): надо городить ключ на выход уарта Ничего не понял, какой ключ? STM32 питается от 3.3В. Opamp писал(а): Про ваш модуль я вообще не знал, а жаль... Есть и еще более дешевые, но у них антенка совсем дохлая. Правда, я недавно купил себе "удлинитель" GPS (получил вчера на почте): ретранслятор с пятиметровым шнурком. Проверил на кухне - кайф! Если без него вообще ни одного спутника лопата не видит, то с ним - уже десяток!!! Правда, удовольствие недешевое - 10 баксов. Возможно, проще внешнюю антенну своему GPS-модулю прицепить. Opamp писал(а): надо еще в момент первого включения контроллера все эти команды в него запихивать А в чем проблема? UART же! Opamp писал(а): объем кода шибко меньше не становится Там кода - с гулькин нос! |
Автор: | Opamp [ Ср ноя 27, 2019 19:24:09 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
Ничего не понял, какой ключ? STM32 питается от 3.3В. Там кода - с гулькин нос! У вас от 3.3, а у меня от пяти. Гуглите "согласование логических уровней". Да. Чтобы вылавливать нужную строку- кода тоже с гулькин нос. Но тут уже кому как удобнее... |
Автор: | Eddy_Em [ Ср ноя 27, 2019 19:43:40 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
Opamp писал(а): У вас от 3.3, а у меня от пяти Ой, подумаешь - один транзистор и два резистора… |
Автор: | goldskif [ Чт янв 16, 2020 20:47:14 ] |
Заголовок сообщения: | Re: GPS-часы точного времени. |
я наконец-то разгадал загадку глюка. Во всем виноваты газоразрядные индикаторы. Когда МК обрабатывает данные со спутника, туда иногда прилетает какой-то мусор. Или сам МК иногда ошибается. В-общем, в массив записывается не цифра от 0 до 9, а знак или буква.. А когда нецифра из порта попадает на дешифратор 155ИД1, то он не знает, какой вывод зажигать. И не зажигает никакой. А это - нештатный режим. ПРи работе газоразрядных индикаторов один из катодов всегда должен быть задействован, иначе на выводах 155ИД1 появляется очень высокое напряжение. А уже импульс этого напряжения пролетает либо по питанию, либо со входа дешифратора в микроконтроллер и сносит там все нахрен. Блокировочные конденсаторы не помогают. Питал дешифратор через диод - не помогло. Видимо, все-такие со входа дешифратора. Ну и соответсвенно, пришлось изменить прошивку. Добавил проверку на диапазон чисел при записи в массив If B >= 48 And B <= 57 Then и на всякий случай такую же проверку If I(count) >= 0 And I(count) <= 9 Then при зажигании анодов. То есть чтобы при крюкозябрах в массиве даже анодное не подавалось. Нет импульса -не будет и помехи. Вот теперь часы заработали. Правда, ЕЕПРОМ там все равно глючный. Иногда все-таки его сносит. Так что такой глюк не проявился бы при использовании светодиодных или ЖКИ индикаторов. Спойлер' Часы, которые принимают данные с GPS модуля по UART' Прямые фузы 3F-9F-D-FF ' DWEN - WDTON ' BODLEVEL2 - BODLEVEL1 - BODLEVEL0 - RSTDISBL ' CKDIV8 - CKOUT - SUT0 ' CKSEL3 - CKSEL2 ' Fuse http://homes-smart.ru/fusecalc/?prog=av ... ATtiny2313 ' http://www.engbedded.com/fusecalc $regfile = "ATtiny2313A.DAT" $crystal = 3686400 ' 3686400 $baud = 9600 $hwstack = 40 ' default 40 Размер аппаратного стека $swstack = 16 ' default 16 Размер программного стека $framesize = 32 ' default 32 размер области используемой и необходимой для преобразований Ddrb = &B00111111 ' конфиг порта B - 1=Output выход Ddrd = &B1111110 ' конфиг порта D - 0=Input вход Portb.6 = 1 Portb.7 = 1 Portd.0 = 1 ' без этой строчки UART вообще гадости пишет на аппаратном порту Config Com1 = Dummy , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0 ' Config Serialin = Buffered , Size = 1 Dim I(6) As Byte Dim Count As Byte Dim Varval As Byte Dim Buf_count As Byte Dim S As String * 1 Dim Sh As String * 2 Dim B As Byte Dim _p As Byte ' poyas +3 Dig1 Alias Portb.0 : Dig2 Alias Portb.1 : Dig3 Alias Portb.2 : Dig4 Alias Portb.3 : Dig5 Alias Portb.4 : Dig6 Alias Portb.5 '***********************[Инициализация прерываний]***************************************** Config Timer0 = Timer , Prescale = 64 , Clear Timer = 0 ' конфигурируем таймер индикации (~500 Гц) Prescale = 1|8|64|256|1024 On Ovf0 Refresh ' обзываем прерывание индикации '***********************[Начало основной программы]**************************************** Enable Interrupts ' разрешаем все прерывания Enable Ovf0 $eeprom 'обращение к блоку данных 100: Data &H34 $data Readeeprom _p , 100 ' **********************[Основной цикл] ************************** 'раскладываем строку содержащую идентификатор $GNRMC - пример строк '$GNRMC,082233.00,A,5136.81278,N,09749.19037,E,2.468,71.94,050118,,,A*4c '$GNVTG,71.94,T,,M,2.468,N,4.570,K,A*16 '$GNGGA,180159.00,5136.81278,N,03914.19037,E,1,05,2.40,143.2,M,12.1,M,,*45 ' Config Watchdog = 1024 'определение времени счёта Watchdog 16|32|64|128|256|512|1024|2048 ' Start Watchdog 'включение Watchdog ' ############ ОСНОВНОЙ ЦИКЛ ################## Do S = "0" B = Waitkey() ' берем символ из буфера в формате ASCII If B = 82 Then ' нашли букву R (82 ascii) Buf_count = 0 ' Reset Watchdog ' сбросить собаку Else Incr Buf_count : If Buf_count > 200 Then Buf_count = 10 End If If B >= 48 And B <= 57 Then ' ASCII ,-44 0-48 9-57 (если цифры) If Buf_count <> 5 Then S = Chr(b) If Buf_count = 5 Then Sh = S + Chr(b) ' сложение в строку Varval = Val(sh) + _p ' для добавления часового пояса If Varval > 23 Then Varval = Varval - 24 ' S = Chr(b) 'B - 048 If Buf_count = 4 Then I(1) = Varval / 10 If Buf_count = 5 Then I(2) = Varval Mod 10 If Buf_count = 6 Then I(3) = Val(s) If Buf_count = 7 Then I(4) = Val(s) If Buf_count = 8 Then I(5) = Val(s) If Buf_count = 9 Then I(6) = Val(s) End If If Buf_count = 10 And Pinb.6 = 0 Then ' увеличить часовой пояс Incr _p If _p > 24 Then _p = 0 Writeeeprom _p , 100 End If If Buf_count = 10 And Pinb.7 = 0 Then ' уменьшить часовой пояс Decr _p Writeeeprom _p , 100 End If Loop '***********************[DATA]**************************************************** Refresh: ' прерывание таймера Т0 (индикация) Reset Dig1 : Reset Dig2 : Reset Dig3 : Reset Dig4 : Reset Dig5 : Reset Dig6 ' гасим индикатор Waitms 1 ' от паразитной засветки Incr Count : If Count > 6 Then Count = 1 ' выбираем какой разряд сейчас включать If I(count) >= 0 And I(count) <= 9 Then ' не зажигать, если мусор Portd = Lookup(i(count) , Digits) ' закидываем в порт код цифры Select Case Count ' включаем соответствующий разряд индикатора Case 1 : Set Dig1 Case 2 : Set Dig2 Case 3 : Set Dig3 Case 4 : Set Dig4 Case 5 : Set Dig5 Case 6 : Set Dig6 End Select End If Return Digits: ' это цифры для ИН-12 Data &B0110000 , &B0010000 , &B0001000 , &B0100000 , &B0000100 Data &B0101100 , &B0101000 , &B0001100 , &B0100100 , &B0000000 |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |