Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.68/56: Рейтинг темы: голосов - 56, средняя оценка - 4.68
 Аватар для northcitizen
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345

Разбор NMEA сообщений

26.06.2019, 13:14. Показов 12666. Ответов 34

Студворк — интернет-сервис помощи студентам
Товарищи, подскажите, что не так делаю.

Решил распарсить данные с GPS приемника. Принимаю с помощью USART на скорости 9600. Проблема в том что данные обновляются с периодичностью 2-10 секунд. Надеялся, что хотябы 1 сек. будет. Нашел такой код.

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Прием посылок от GPS-приемника
void USART2_IRQHandler(void)
{
 volatile char UsartTemp = 0;
 
 if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
 {
 UsartTemp = USART_ReceiveData(USART2);
 GPSBuf[GPSBufWrPoint] = UsartTemp;
 
 if ((GPSBufWrPoint > 1) && (GPSBufWrPoint < GPSBUFLENGTH)) // Проверка нахождения внутри буфера, чтобы при дальнейшем преобразовании не выскочить за границу
 {
 if ((GPSBuf[GPSBufWrPoint-1] == ',') && (GPSBuf[GPSBufWrPoint] == ','))
 { // Принятая последовательность байт вида ",," превращается в ",0,", тем самым превращая неопределенный параметр в четкий 0
 GPSBuf[GPSBufWrPoint]   = '0';
 GPSBuf[GPSBufWrPoint+1] = ',';
 GPSBufWrPoint++;
 }
 if ((GPSBuf[GPSBufWrPoint-1] == ',') && (GPSBuf[GPSBufWrPoint] == '*'))
 { // Принятая последовательность байт вида ",*" превращается в ",0*", тем самым превращая неопределенный параметр в четкий 0
 GPSBuf[GPSBufWrPoint]   = '0';
 GPSBuf[GPSBufWrPoint+1] = '*';
 GPSBufWrPoint++;
 }
 }
    
 if (GPSBufWrPoint < GPSBUFLENGTH)
 GPSBufWrPoint++; // Продолжаем заполнять буфер
     else
     { // Если буфер заполнился, начинаем искать и декодировать NMEA сентенции
 
           NMEA_Parser_RMC(); // парсим RMC пакет
           NMEA_Parser_GLL();  // парсим GLL пакет
           NMEA_Parser_GGA(); // парсим GGA пакет
            
             GPSBufWrPoint = 0;
     }
         
    }
}
Для получения координат парсю три набора данных GLL, RMC, GLL. (Тем самым увеличил скорость обновления данных(ну, я так думал, по крайней мере)). Парсю по такому примеру:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
uint8_t NMEA_Parser_GLL(void)
{
 uint8_t CommaPos;
 uint8_t k;
 uint16_t i,StartPos = 0; // Начало строки
 
 while (!( (GPSBuf[StartPos]   == '$')
    &&(GPSBuf[StartPos+3] == 'G')
    &&(GPSBuf[StartPos+4] == 'L')
    &&(GPSBuf[StartPos+5] == 'L'))
    && StartPos < 7)
 StartPos++;
 
 // начало пакета слишком сильно смещено, отбрасываем пакет
 if (StartPos>5) return 0;
 
// if (ControlCheckSum(StartPos) == 0) return 0; // Проверка контрольной суммы
 
 memset(&GPSFixData, 0, sizeof(GPSFixData)); // Очищаем структуру
 
 for (i = StartPos+6; i < GPSBUFLENGTH ; i++) // Ждем или конца буфера или последнейй запятой
 {
 if (GPSBuf[i] == ',')
 {
 CommaPos++; // Наращиваем счетчик запятых
 k=0;
 }
 else
 switch (CommaPos) // Пользуемся тем, что данные разделяются запятыми. Неопределенные данные (две запятые подряд) мы заменили нулем в обработчике прерывания USART1_IRQHandler()
 {
 
 case 1: if(k < sizeof(GPSFixData.Latitude)-1) GPSFixData.Latitude[k++]=GPSBuf[i]; break;
 case 2: if(k < sizeof(GPSFixData.NS)) GPSFixData.NS=GPSBuf[i]; break;
 case 3: if(k < sizeof(GPSFixData.Longitude)-1) GPSFixData.Longitude[k++]=GPSBuf[i]; break;
 case 4: if(k < sizeof(GPSFixData.EW)) GPSFixData.EW=GPSBuf[i]; break;
 case 5: if(k < sizeof(GPSFixData.UTC)-1) GPSFixData.UTC[k++]=GPSBuf[i]; break;
 case 7: return 1; break; // последня запятая 
 default: break;
 }
 }
 return 1;
}
Не знаю, как увеличить скорость обновления. Частота тактирования шины на которой висит уарт = 6Мгц
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
26.06.2019, 13:14
Ответы с готовыми решениями:

проблема с принятием NMEA сообщений
Дело таково: Принимаю на УАПП ATmega128 Nmea сообщения от Геос-1М. Принимаю сообщения по прерыванию по байту, тем самым распознавая...

Разбор работы системы сообщений в Win32 проекте
Здравствуйте, я, вообщем-то, желаю разобраться как работает цикл обработки сообщений в проекте Win32. Как взаимодействуют между собой...

парсер NMEA
Помогите пожалуйста, нужно написать программу которая читает из txt файла строку формата nmea и выдает информацию оттуда в привычной нам...

34
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
27.06.2019, 11:51
Студворк — интернет-сервис помощи студентам
Ethereal, да можно и так. Я так тоже делал, правда мне нужна была одна конкретная строка. А GPS отсылает пачку из 5-6 этих строк каждая из которых начинается с $ и заканчивается переводом строки. Между ними нет времени на разбор ибо они идут потоком.

Либо можно после принятия одной строки копировать ее в другой буффер и там парсить, а в это время набивать основной буффер.
1
 Аватар для northcitizen
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345
27.06.2019, 12:03  [ТС]
Ethereal,
Цитата Сообщение от Ethereal Посмотреть сообщение
1.) Принимаем и отбрасываем пока не встретится $ .
2.) Принимаем и укладываем в буфер длиной 80 символов. Если встретился перевод строки - парсим
Цитата Сообщение от _SayHello Посмотреть сообщение
А если на середине передачи устройство зависло и символ никогда не придет?
Когда я работал с GPS он как правило посылал несколько строк NMEA в пакете $GPRMC, $GPGLL и так далее. И в каждой есть эти символы. Времени между строками на парс мало, а вот между целыми пакетами достаточно.
0
 Аватар для Евгений В
912 / 672 / 134
Регистрация: 01.03.2010
Сообщений: 1,279
27.06.2019, 12:03
[quote="northcitizen;13684993"]Это для модуля Sim800L такой таймаут выбран?[/quo
Цитата Сообщение от northcitizen Посмотреть сообщение
Почему именно 100 мс.? Это для модуля Sim800L такой таймаут выбран?
Да. Там ничего шустрого нет. Все входящие смс автоматически запоминаются в модуле. В моем случае времени на их обработку вагон (ваяю автополив на даче)
1
 Аватар для Ethereal
6773 / 2741 / 385
Регистрация: 17.02.2013
Сообщений: 4,048
27.06.2019, 17:12
А если на середине передачи устройство зависло и символ никогда не придет?
Вот тогда-же при написании первого сообщения накидал дополнение, но не стал публиковать. В связи с этим вопросом оно кстати :

Вернее тайм-аут желателен, но не для того чтобы определять конец пакета.
После обработки принятого байта посылки счетчик времени делаем t=0 и далее инкрементируем его в моменты тика некоего таймера. Если t переполяется, а очередной байт все еще не пришел, то связь вообще пропала и идем на пункт 1. Если очередной байт пришел в момент когда t неприлично большой, то верить посылке тоже нельзя, в ней была большая пауза, а значит возможно мы приняли начало одной посылки, потом на время потеряли связь и теперь принимаем хвост другой. Тогда если пришел $ начинаем пункт 2 с начала, а если не $, то идем на пункт 1. Вполне строгий на проверки и весьма простой алгоритм.

Добавлено через 12 минут
Времени между строками на парс мало, а вот между целыми пакетами достаточно.
Ну тогда пожалуй да. Тайм-аут как определение конца пакета строк в таком случае уместен. Хотя я бы все равно постарался сделать что-нибудь поизящнее. В общем алгоритм надо затачивать по ситуации, рассуждая про вообще можно только идеи накидать, а при живой работе с конкретным устройством все равно виднее.

Добавлено через 5 минут
Я так тоже делал, правда мне нужна была одна конкретная строка. А GPS отсылает пачку из 5-6 этих строк каждая из которых начинается с $ и заканчивается переводом строки.
Если в пакете 5-6 строк и только одна нужная, то все сводится к приему одной строки. После прихода возврата каретки три байта в заголовке строки посмотреть и уже ясно это нужная тебе строка или не нужная и тогда отбросить и тут-же принимать следующую.
1
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
27.06.2019, 17:16
Ethereal,
Цитата Сообщение от Ethereal Посмотреть сообщение
Так после прихода возврата каретки там только три байта в заголовке строки посмотреть и уже ясно это нужная тебе строка или не нужная и тогда отбросить.
Точно не помню как там в проекте было, там надо было принимать все, но выбирать определенную строку в зависимости от каких то обстоятельств. Тем проще было, что в stm32f3 UART умеет сам таймаут отмерять.
0
 Аватар для Ethereal
6773 / 2741 / 385
Регистрация: 17.02.2013
Сообщений: 4,048
27.06.2019, 17:26
Подумал и согласился, что если несколько строк непрерывным потоком, то тайм-аут как определение конца пачки строк хорошо. Ну а если делаем так. Имеем два буфера по 80 байт. Сначала принимаем в один, на лету порубая поток символов на строки тем алгоритмом, что я предложил. Как пришел перевод строки проверяем три байта в заголовке. Если это нужная нам строка, то переключаемся на прием во второй буфер (переставляем указатель). И вот наконец когда тайм-аут который говорит нам о том, что пачка строк закончилась, в первом буфере на лету вырезанная нужная нам строка.
0
0 / 0 / 0
Регистрация: 07.05.2020
Сообщений: 7
07.05.2020, 13:43
Здравствуйте, я начинающий. Подскажите, пожалуйста где и как необходимо описать структуру GPSFixData
Спасибо!
0
 Аватар для northcitizen
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345
07.05.2020, 19:08  [ТС]
Almaz72,
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 __packed struct  GPGGA_Struct // Структура с данными GPS-модуля
{
 char Time [sizeof("hhmmss")+RESERVE]; // Время
 char Latitude [sizeof("XXXX.XXX")+RESERVE]; // Широта
     char NS; // Север-Юг
 char Longitude[sizeof("XXXXX.XXX")+RESERVE]; // Долгот
 char EW; // Запад-Восток
 char UTC [sizeof("nncccc")+RESERVE]; // Количество спутников в решении
 char Latitude_GGA[sizeof("XXXX.XXX")+RESERVE]; // Месяц
 char Longitude_GGA[sizeof("XXXXX.XXX")+RESERVE]; // Число
 char UTC_GGA [sizeof("nncccc")+RESERVE]; // Поправка на местное время, часы
 char UTC_RMC [sizeof("nncccc")+RESERVE]; // Поправка на местное время, часы
 char Latitude_RMC[sizeof("XXXX.XXX")+RESERVE]; // Месяц
 char Longitude_RMC[sizeof("XXXXX.XXX")+RESERVE]; // Число
};
0
0 / 0 / 0
Регистрация: 07.05.2020
Сообщений: 7
08.05.2020, 09:43
Спасибо большое! Только я все равно не могу понять, почему структура называется GPGGA_Struct, а обращение к ней в программе идет по названию GPSFixData. И компилятор (Keil) ругается). Извините, еще раз, если задаю глупые вопросы, до этого писал только на Ассемблере. Попробовал поменять GPGGA_Struct на GPSFixData, компилятор все равно ругается)
0
 Аватар для northcitizen
38 / 31 / 9
Регистрация: 29.03.2019
Сообщений: 345
08.05.2020, 10:53  [ТС]
Almaz72, потому что struct GPGGA_Struct это тип, вам нужно создать GPSFixData типа GPGGA_Struct.
C
1
struct GPGGA_Struct GPSFixData;
и с ней уже работать
P.S.
Так же как и для создания переменной а типа int вы пишите
C
1
int a;
;
0
0 / 0 / 0
Регистрация: 07.05.2020
Сообщений: 7
08.05.2020, 14:02
спасибо огромное!
0
42 / 35 / 11
Регистрация: 22.09.2017
Сообщений: 125
08.05.2020, 18:08
Ненужные сообщения можно отключить.
В ublox это делается посылкой в GPS модуль таких команд:
C
1
2
3
4
const uint8_t GGA_Disable[16] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x24};
const uint8_t GLL_Disable[16] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B};
const uint8_t GSA_Disable[16] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32};
const uint8_t VTG_Disable[16] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x47};
Подробнее можно посмотреть в документации на модуль.
0
0 / 0 / 0
Регистрация: 07.05.2020
Сообщений: 7
13.05.2020, 13:22
Здравствуйте! Всем спасибо за ответы!
Появился еще один вопрос: На Stm32f030 хотел сделать так: один раз в 10(время настраиваемое) устройство просыпается.
считывает время с gnss модуля(mc60), это время записывается в RTC, далее устанавливается время будильника + 20 сек(например), включается прерывания от RTC и устройство уходит в спящий режим(HAl_Pwr_enterStanbyMode()). При загрузке программы или первом включении работает правильно - пробуждается через 10 сек. Затем начинается что то непонятное для меня - оно начинает просыпаться каждую секунду. В rtc.c установку времени, даты , параметров, будильника убрал. Попробую вставить код, если получится) Как писал выше . до этого работал только на ассемблере
и больше всего с AVR и MCS51, прошу , сильно не ругайте
В терминале - первое сообщение - нормальное, через 10 секунд, остальные через секунду или две( в программе задержка была)
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 //----------здесь готовлю время,считанное с gnss модуля------------------------------- 
  str[0]= GPSFixData.UTC[0];
  str[1]= GPSFixData.UTC[1];                                                 // hour
  str[3]= 0;
  sTime.Hours = StrToInt(str);
  str[0]= GPSFixData.UTC[2];
  str[1]= GPSFixData.UTC[3];
  sTime.Minutes = StrToInt(str);                                             // minutes 
  str[0]= GPSFixData.UTC[4];
  str[1]= GPSFixData.UTC[5];
   sTime.Seconds = StrToInt(str);                                             // seconds
   sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
   sTime.StoreOperation = RTC_STOREOPERATION_RESET;
   HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);                             // save to rtc current utc time from gnss
                        
  //-----------------------test------------------------------                
   sAlarm.AlarmTime.Seconds =  sTime.Seconds + 10;
   if (sAlarm.AlarmTime.Seconds > 60U) {sAlarm.AlarmTime.Seconds = sAlarm.AlarmTime.Seconds - 60;}
 //------------------------------------------------------------              
   sAlarm.AlarmTime.Hours = sTime.Hours;                        
 //---------------------set rtc alarm-------------------------------------------------        
   sAlarm.AlarmTime.Minutes = sTime.Minutes;
   sAlarm.AlarmTime.SubSeconds = 0x0;
   sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
   sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
   sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS
                                | RTC_ALARMMASK_MINUTES;
   sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
   sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;
   sAlarm.Alarm = RTC_ALARM_A;
    HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN); 
    // вывожу на терминал для самопроверки---------------------------------------------------                     
              HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // RTC_FORMAT_BIN , RTC_FORMAT_BCD
              snprintf(trans_str, 63, "Time %d:%d:%d\n", sTime.Hours, sTime.Minutes, sTime.Seconds);
              HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000);
 
               HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
              snprintf(trans_str, 63, "Date %d-%d-20%d\n", sDate.Date, sDate.Month, sDate.Year);
              HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000);
 
            HAL_RTC_GetAlarm(&hrtc, &sAlarm, RTC_ALARM_A, RTC_FORMAT_BIN); 
             snprintf(trans_str, 63, "Alarm %d:%d:%d\n", sAlarm.AlarmTime.Hours, sAlarm.AlarmTime.Minutes,                sAlarm.AlarmTime.Seconds);
             HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000);
                         
        //----------------------------ухожу в stanby---------------------------------------------              
     HAL_PWR_EnterSTANDBYMode();
Миниатюры
Разбор NMEA сообщений  
0
0 / 0 / 0
Регистрация: 07.05.2020
Сообщений: 7
16.05.2020, 10:38
Добрый день! Вообщем, разобрался, может кому-то поможет-
надо было сбросить флаг _ HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU) до бесконечного цикла while(1)
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,875
16.05.2020, 10:56
Цитата Сообщение от Almaz72 Посмотреть сообщение
Всем спасибо за ответы!
правила п 3.6
Если какой-либо пост на форуме показался вам полезным, то вы можете выразить свою благодарность, нажав кнопку "Спасибо" внизу самого поста.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.05.2020, 10:56

nmea over ethetnet
Собственно даже не знаю куда и писать.. Есть задача написать сервер для трансляции nmea 1083 в udp. Вроде естьтакой стандарт но не смог...

Перевод координат NMEA
Добрый вечер, прошу совета в построении алгоритма перевода координат NMEA (ddmm.mmmm). Нужно привезти их в градусы. Есть формула...

Отправка nmea на сервер
Вот таким образом пытаюсь отправить nmea строку на сайт(php) url = &quot;http://213.57.209.92:8080&quot;; client = new...

NMEA-эмуляция COM-портом
Есть ли возможность эмуляции GPS , используя виртуальный или физический COM порт с последующим считыванием с него данных? Можете...

$GPVTG протокола NMEA в GPS
Вопрос тем, кто уже игрался с сообщениями по протоколу NMEA отправляемых с GPS модулей. Конкретно интересует сообщение VTG - истинное...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru