Прием и парсинг NMEA-данных от GPS-приемника
GPS-приемники сегодня используются в самых разных устройствах - от автомобильных трекеров до беспилотных летательных аппаратов, независимо от применения, большинство таких модулей передают информацию о положении в формате NMEA 0183, в этой статье я разберу, как принять эти данные от GPS-модуля на микроконтроллер STM32 и преобразовывать их в удобный для программы вид.
А также в статье будут рассмотрены два варианта подключения GPS-приемников к микроконтроллеру STM32:
- Модуль GPS c UART-интерфейсом (TTL-уровни), подключаемый на прямую к микроконтроллеру;
- Модуль GPS с интерфейсом RS-232, данные от такого типа gps, необходимо принимать через преобразователь уровней TTL.
В данном проекте используются GPS-приемники: LS23030 (UART) и LS23036(RS-232).
Схема подключения GPS-UART
Сигнал GPS, подключается к выводу PA10-31_контакт - RX(МК-STM32F103)
Для более стабильного напряжения питания можно использовать следующую схему, в которой работает понижающий преобразователь MP231, но необходим источник +12В, в моем случае используется аккумуляторная сборка (NiMH/Pb +12В).
!!! P.S. заранее прошу прощения за некачественные картинки осциллограмм, осциллограф (с возможностью сохранения данных на флешку), некорректно производит измерения ...!!!
Вид осциллограммы передаваемых данных модуля-gps(uart) (линия TX)
Показатель амплитуды данных от модуля gps(uart) = delta [ 3.4V ], можно подключать к микроконтроллеру STM32.
Схема подключения GPS(RS-232)
Сигнал модуля-gps(rs-232), сначала приходит на 13 контакт преобразователя ADM3202, далее преобразованный сигнал (TTL) уходит на PA10-31_контакт - RX(МК-STM32F103)
Схема подключения ADM3202 к МКSTM32 - макет
Также для более стабильного напряжения питания по +5В, можно использовать схему преобразователя напряжения MP2315.
Для более стабильного напряжения питания по +3В, можно использовать следующую схему, в которой работает линейный стабилизатор напряжения LP2985.
Краткая информация о преобразователе ADM3202
Микроконтроллеры STM32, работают с логическими уровнями TTL/CMOS - обычно это 3.3В или 5В, интерфейс RS-232, напротив, использует более высокие и отрицательные напряжения ( от ±3В до ±12В), что делает их напрямую несовместимыми.
Если подключить напрямую модуль-GPS (RS-232) к выводам МК-STM32, это может не только привести к искажению данных, но и физически повредить выводы. ADM3202 решает эту задачу, переводя сигналы из одного уровня в другой, в обоих направлениях.
ADM3202 - это двухканальный приемопередатчик уровней RS-232 - TTL, выполняет сразу две задачи:
- Преобразование входящих RS-232 сигналов в безопасные TTL-уровни(RX-канал);
- Преобразование исходящих TTL-сигналов микроконтроллера в RS-232(TX-канал).
Для формирования требуемых амплитуд RS-232, внутри микросхемы используется помповый преобразователь напряжения(chage pump) с четырьмя внешними конденсаторами, это позволяет работать от одного источника питания (от 3В до 5.5В).
Вид осциллограммы передаваемых данных модуля-gps(rs-232) до преобразования ADM3202
Показатель амплитуды данных от модуля gps(rs-232) до преобразования = delta [ 10.6V ], нельзя подключать к микроконтроллеру STM32.
Вид осциллограммы передаваемых данных модуля-gps(rs-232) после преобразования ADM3202
Показатель амплитуды данных от модуля gps(rs-232) после преобразования = delta [ 3.6V ], можно подключать к микроконтроллеру STM32.
Настройка микроконтроллера STM32F103 в CubeIDE
Конфигурация Parametr Settings
В параметрах USART (Parametr Settings) я выбираю:
- Mode: Asynchronous (асинхронный режим);
- Baud Rate: 9600 бит/с (в моем примере два модуля-gps (rs-232 и uart) работают на скорости 9600).
все остальные параметры без изменений.
Конфигурация NVIC Settings
Захожу в параметр (NVIC Settings) и включаю глобальное прерывание
Для отслеживания состояния интерфейса USART и обработки важных событий (например, завершения приема или ошибки), в разделе NVIC Settings было включено глобальное прерывание USART, это обеспечивает возможность немедленного реагирования со стороны микроконтроллера на изменения состояния периферии без постоянного опроса регистров.
При работе с GPS-модулями, которые передают NMEA-сообщения раз в секунду (1Hz), важно правильно организовать прием данных, чтобы не пропустить ни одного пакета. Необходимо настроить DMA в режиме Circular данный режим минимизирует нагрузку на процессор и гарантирует надежный прием.
Конфигурация DMA Settings
Захожу в параметр DMA Settings и выполняю следующие настройки:
- Выбор потока/канала: USART1_RX (прием данных);
- Mode: Circular ;
- Increment Memory Address: Enabled (автоинкремент памяти);
- Data Width: Byte (8 бит, соответствует формату NMEA).
Реализация программного кода(настройка и прием данных)
Коротко о NMEA 0183
Это текстовый протокол, используемый для передачи данных между морским и авиационным навигационным оборудованием, включая GPS-приемники. Большинство современных GPS-модулей выводят информацию именно в этом формате.
Основные особенности:
- Текстовый формат – данные передаются в виде ASCII-строк;
- Структура сообщений – каждая строка начинается с $, содержит идентификатор типа данных и заканчивается контрольной суммой;
- Скорость передачи – обычно 9600 бод (но может быть и выше для высокочастотных модулей);
- Частота обновления – чаще всего 1 раз в секунду (1Hz), но бывают 5Hz, 10Hz и более.
Пример строки (GGA – Global Positioning System Fix Data):
Время: 11:25:30
Широта: 60.20576° N
Долгота: 30.261315° E
Качество фикса: 1
Спутников: 10
Высота: 45.3 м
Пример строки (RMC – Recommended Minimum Navigation Information):
После обработки RMC:
- Время: 11:25:30
- Статус: Данные действительные
- Широта: 60.20576° N
- Долгота: 30.261315° E
- Скорость: 5.12 узла (~9.48 км/ч)
- Курс: 87.45°
- Дата: 11.08.2025
Также прикрепляю еще одну ссылку, где в детальности продемонстрирована расшифровка протокола NMEA0183 [https://wiki.iarduino.ru/page/NMEA-0183/].
Определение структур данных в заголовочном файле [ NMEA.h ]
Для удобства работы с навигационной информацией из gps-приемника, здесь я заранее описываю набор структур, каждая из которых отвечает за свой логический блок данных.
Реализация модуля парсинга протокола NMEA.c
Функция decodeGGA()
Парсит строку $GPGGA и заполняет структуру GGASTRUCT данными: время, координаты, высота, количество спутников, качество фиксации.
Шаги работы функции:
- Подготовка к поиску нужных данных, переменная inx - это текущий индекс в строке GGAbuffer, сначала идет пропуск ненужных полей (счетчик двигается до следующей ,)
- Проверка валидации качества позиционирования В NMEA поле качества фиксации (Fix Quality) может быть:0 - нет фикса, 1 - GPS Fix, 2-DGPS Fix, 4/5/6 другие корректные варианты, если поле содержит из разрешенных цифр, то в gga->isfixValid устанавливается в 1, иначе функция возвращает ошибку.
- Чтение времени, извлекается время в формате HHMMSS (UTC);Преобразуются числа, корректируется по смещению GMT, при необходимости меняется день (daychange++ или daycahnge--).
- Чтение широты (Latitude)Формат в NMEA: DDMM.MMM;Первые цифры - градусы, остальное - минуты, код выделяет минуты, делит их на 60 и добавляет к градусам, если NS == 'S', широта делается отрицательной.
- Чтение долготы (Longitude)Формат в NMEA: DDMM.MMM;Аналогично широте, но первые 3 цифры - градусы, если EW == 'W', долгота делается отрицательной.
- Чтение типа вычисления координат из поля после долготы извлекается число (gga->calc.calculation), указывающее метод позиционирования.
- Чтение количества спутников, следующее поле - количество видимых спутников (gga->numofsat).
- Пропуск HDOPHDOP (Horizontal Dilution of Precision) не используется, просто пропускается.
- Чтение высоты поле с высотой (gga->alt.altitude) и единицами (gga->alt.unit, обычно 'M' - метры).
- завершение возвращается 0 при успешном разборе.
Функция decodeRMC()
Парсит строку $GPRMC и заполняет структуру RMCSTRUCT и извлекает: валидность данных, скорость, курс и дату.
- Пропуск времени
- Сначала идет поле времени, но в этой функции оно не сохраняется.
- Проверка валидности Если после времени идет А(Active) - данные актуальны;
- Если V(Void) нет актуальных данных, функция возвращает ошибку.
- Пропуск координат, пропускаются поля широты, долготы и направления (NS/EW).
- Чтение скорости В NMEA скорость указывается в узлах, код переводит строку в число с плавающей точкой и записывает в rmc->speed.
- Чтение курса, следующее поле - курс (угол направления движения в градусах относительно севера).
- Чтение даты формат: DDMMYY;Код выделяет день, месяц, год, корректирует день с учетом daychange (из GGA), и записывает в rmc->date.
Реализация модуля обработчика потока от UART-GPS uartProc_GNSS.c
Функция uart_Handler_GNSS - это основной обработчик UART-потока, вызывается постоянно из главного цикла.
Логика работы:
- Проверяет, сработали ли прерывания DMA (половина буфера или полный буфер);
- Если пришли новые данные - устанавливает флаг активности GPS (gParams.isGPS = 1);
- Поиск GGA или RMCВ режиме shabloneMode = 0 ищет последовательность GGA или RMC;Когда шаблон найден, переключаемся в режим shabloneMode = 1;В режиме 1 копирует байты до символа конца строки (13 или 10);
- Действие когда собрана строка, записывает строку в буфер buf_GGA или buf_RMC в зависимости от типа, обновляет время последнего получения GPS (gps_time_receive).
- Декодирование вызывает decodeGGA() и decodeRMC() для извлечения данных в структуру gpsData.
- Формирование выходного пакета, если хотя бы одно из сообщений валидно, формирует строку с координатами, временем, количеством спутников, режим фикса, высотой и курсом. Записывает в результат в uart_rezult_buf_out_AB[] с преамбулой 0x5A 0xA5 и длиной пакета.
- Если в течение (DELAY_GPS_STATUS_CONNECT)1000 миллисекунд новых данных нет - GPS считается отключенным (gParams.isGPS= 0).
- uint8_t* dpi_getGPS_buffer (Возвращает указатель на готовый пакет данных для передачи ведущему устройству, а так же его размер).
- void uart_startRecieving_GNSS (Запускает прием данных от GPS-приемника в режиме DMA).
Функции прерываний
Главный модуль
Ссылка на скачивание исходного кода [ https://t.me/ChipCraft В закрепленном сообщении [ #исскуствомк_исходный_код -Исходный код для Module_GPS_NMEA0183]
Графический GPS-трекер я разработал для тестирования на С#, если Вам будет интересно, пишите в комментариях и я с радостью напишу статью.
Если статья показалась Вам интересной, буду рад выпустить для Вас еще множество статей исследований по всевозможным видам устройств, так что, если не хотите их пропустить – буду благодарен за подписку на мой ТГ-канал: https://t.me/ChipCraft.