#1 Re: Апаратні питання » MCU: 168MHz STM32F405RGT6 32BIT потребую допомоги » 2025-08-16 22:14:09

jokeer пише:

Із простого - відключити і передавач, він же на роз'ємі. Підключатись до заднього порта USB, хорошим кабелем. І може бути різниця, USB 2 чи 3. Видалити драйвер камери.
Якщо нічого не вийде - припаяти програматор.

roll roll roll roll roll roll roll roll roll roll roll roll

Я знав, що так і буде....  Від'єднав камеру і відео передавач бо збила з пантелику та що відтягувалась в диспетчері обладнання...
А приймач треба було відпаювати і я чесно кажучи полінувався це зробити...

Ваш чарівній пендаль простимулював мої дії, і все... контроллер прошився ....

#2 Re: Апаратні питання » MCU: 168MHz STM32F405RGT6 32BIT потребую допомоги » 2025-08-16 21:48:35

jokeer пише:

А ви периферію відпаяли?

Залишився тільки передавач, все інше від'єднав.

#3 Re: Апаратні питання » MCU: 168MHz STM32F405RGT6 32BIT потребую допомоги » 2025-08-16 21:35:29

dimich пише:
renoshnik пише:

Не можу підключитися в режимі ВООТ, контроллер визначається як відеокамера ...
Але зараз треба залити нову прошивку на плату

Хіба "DFU" в "Camera DFU Device" не означає "Device Firmware Upgrade"? Тобто девайс якраз і очікує на прошивку.
Що STLink каже при спробі прошити?

Бетафлай - пише, що нема зв'язку з контроллером.
Camera DFU Device --  так в менеж не камера...

При підключенні контроллера пише що

1111111.jpg

555555.jpg

#4 Апаратні питання » MCU: 168MHz STM32F405RGT6 32BIT потребую допомоги » 2025-08-16 21:01:30

renoshnik
відповідей: 9

Шановне панство, потрібна допомога.  Звертався на профільні форуми, проблему не вирішили ...

Не можу підключитися в режимі ВООТ, контроллер визначається як відеокамера ...
В іншому все без зауважень, налаштування в "бетці" проходять, передавач прошивається.

Але зараз треба залити нову прошивку на плату, а вона не хоче переходити в режим ВООТ   sad  sad  sad

ImpulseRC_Driver_Fixer - не допомагає, вона висить нескінченно без результату.
zadig-2.3 - теж не вирішує проблеми.
STM32 Cube Programmer - теж його не бачить.

000000.jpg

#5 Re: Проекти » Налаштувати Проект Робота Arduino » 2025-07-13 19:38:57

jokeer пише:

З GPS навігацією зараз дивно іноді. Вийшов на стадіон побігати - трекеру здалось, що я пробіг 17 км по Лімі (Перу).

Це реалії сьогодення ....

#6 Re: Проекти » Налаштувати Проект Робота Arduino » 2025-07-13 10:03:41

nofasnss пише:

Є схема і програма все працювало два роки. Зараз спеціаліст відсутній в мене не виходить звести до ладу підїду привезу все що є для наладки,  для звязку телеграм @selokarpatu Київ  Двигун https://prom.ua/ua/p2443527056-motor-reduktor-100.html керується nano v3  підключені три потенціометри для зміни швидкості і частоти  вмикання також GPS модуль  для вмикання через задану відстаеь

Это агродрон для разбрасывания трихограммы ?
Делал такую программу до войны ....

#9 Re: Апаратні питання » Стенд для тестів FPV » 2025-06-14 16:59:42

strannik пише:

USB : посилаємо команду - вімикаємо два ланцюга data in/out з невеликою затримкою вимикаємо + та -.

Якою програмою будете посилати команди ?

#10 Re: Програмування Arduino » Вопрос по цифровому реле с питанием 12В » 2025-05-17 09:08:49

kepler пише:
jokeer пише:

Ніт
Ваші вподобання досить незвичні wink я сумніваюся, чи існує таке готове рішення. Саморобки повинні існувати.

Готового нет, а программируемое решение?
Так, вподобання незвичні, но сейчас это нужно..

Колись робив улучшайзінг по типу Hunter XCH-1200, поливалку на 12 каналів...

https://driver.top/blog/422159/


https://youtu.be/VsHSq5yDYUc?si=lt-yJOMSBwluPJAA

#11 Re: Проекти » Список исполнителей » 2025-05-08 17:00:04

Yuri57 пише:

hmm Необхідна допомога програміста у програмі на Arduino.
"Залізо" зібране (14-канальний пристрій), працює на 100%. Програма працює, але є недоліки, які необхідно прибрати. тел. 099 707 72 17

очень интересно но ничего не понятно ...

#12 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-15 14:27:28

dimich пише:
renoshnik пише:
String nmeaSentence = ""; 		// Переменная для хранения NMEA-строки
...
nmeaSentence += c; 		// Добавить символ к строке NMEA
...

Навіщо зберігати символи в String, якщо потім їх копіювати в char[] ?

ось трохи змінив ...

  String nmeaSentence = "";
  boolean str_read = true;
  
void setup() { Serial.begin(9600); }

void serialEvent() { nmeaSentence = Serial.readStringUntil('n');
if (nmeaSentence.length() > 0 && str_read) { GPS_run(nmeaSentence); }
	}
  
void loop() {

	}

void GPS_run(String nmea) {
str_read = false;	
	// ********************************************
str_read = true;	
	}

#13 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-12 17:45:12

dimich пише:
renoshnik пише:
char fullSpeed[5];
sprintf(fullSpeed, "%03d", speedKmh);

//   чтобы избежать переполнения 

sprintf(fullSpeed, sizeof(fullSpeed), "%03d", speedKmh);

Така конструкція чомусь виводить на екран якісь сторонні символи замість данних ... hmm

snprintf. Я ж поправився вище.
Взагалі комілятор мав би видати попередження. Чи у вас вони вимкнені?

Вже старий, не додивився ...  roll

#14 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-12 16:05:35

char fullSpeed[5];
sprintf(fullSpeed, "%03d", speedKmh);

//   чтобы избежать переполнения 

sprintf(fullSpeed, sizeof(fullSpeed), "%03d", speedKmh);

Така конструкція чомусь виводить на екран якісь сторонні символи замість данних ... hmm

#15 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-10 12:02:23

dimich пише:

Працює, не димить, не іскрить - це вже добре cool
Але перевірку контрольної суми я б таки додав. Хто зна, що там з UART'у може прийти. Так хоч якась валідація.

dimich пише:

sprintf(fullSpeed, sizeof(fullSpeed), "%03d", speedKmh);

Звісно ж, тут snprintf. То я при цитуванні забув поправити.

Я вже зробив заготовку, але поки не перевіряв .... 

	
String nmeaSentence = "$GPRMC,123456.00,A,4916.45,N,12311.12,W,0.05,89.60,030615,,,A*1C";

void setup() {
  Serial.begin(9600);

  if (checkChecksum(nmeaSentence)) {
    Serial.println("Контрольная сумма совпадает.");
  } else {
    Serial.println("Ошибка контрольной суммы.");
  }
}

void loop() {
  // Основной код программы
}

bool checkChecksum(const String& nmea) {
  // Найти индекс символа '*'
  int asteriskIndex = nmea.indexOf('*');
  if (asteriskIndex == -1 || asteriskIndex < 1) {
    return false; // Нет контрольной суммы или неверный формат
  }

  // Извлечь контрольную сумму из строки (после '*')
  String checksumStr = nmea.substring(asteriskIndex + 1);
  int expectedChecksum = strtol(checksumStr.c_str(), nullptr, 16);

  // Вычислить контрольную сумму
  int calculatedChecksum = 0;
  for (int i = 1; i < asteriskIndex; i++) { // Пропускаем '$'
    calculatedChecksum ^= nmea[i];
  }

  return calculatedChecksum == expectedChecksum;
}	
	

#16 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-10 11:30:56

dimich пише:
renoshnik пише:
String nmeaSentence = ""; 		// Переменная для хранения NMEA-строки
...
nmeaSentence += c; 		// Добавить символ к строке NMEA
...
char nmeaCStr[nmea.length() + 1];
nmea.toCharArray(nmeaCStr, nmea.length() + 1);
...

Навіщо зберігати символи в String, якщо потім їх копіювати в char[] ?

renoshnik пише:
if (fieldIndex == 1) {printFormattedTime(token);token = nullptr;}	// выводим время 1
if (fieldIndex == 2) {printFormattedValid(token);token = nullptr;}	// выводим валидность координат 2	
if (fieldIndex == 7) {printFormattedSpeed(token);token = nullptr;}// выводим скорость 7
if (fieldIndex == 9) {printFormattedDate(token);token = nullptr;}	// выводим дату 9

token = commaPos + 1;

Навіщо присвоювати token = nullptr, якщо відразу ж присвоюється token = commaPos + 1?
Раз на то пішло, то хоча б

switch (fieldIndex) {
    case 1: printFormattedTime(token); break;
    case 2: printFormattedValid(token); break;
    case 7: printFormattedSpeed(token); break;
    case 9: printFormattedDate(token); break;
    default: break;
}
token = commaPos + 1;
renoshnik пише:
float Kmh = atof(rawKnot) * 1.852;
int speedKmh = (int)Kmh;

Якщо вже так хочеться float, навіщо проміжна змінна і C-style кастинг? Такий же результат дасть

int speedKmh = atof(rawKnot) * 1.852;

А краще

int speedKmh = round(atof(rawKnot) * 1.8523);
renoshnik пише:
char fullSpeed[5];
sprintf(fullSpeed, "%03d", speedKmh);

У разі невалідних вхідних даних може бути переповнення буфера. Хоча б

sprintf(fullSpeed, sizeof(fullSpeed), "%03d", speedKmh);

Хоча у разі невалідних вхідних даних переповнення буфера буде ще на стадії отримання строки з UART.



1. - Згоден, що додає додатковий крок, але мені так було зручніше працювати з рядками на етапі побудови.
2. - про token = nullptr, то я шукав звідки лізуть деякі баги і забув потім видалити, дійсно то зайве.
3. - дякую виправив
4. - дякую виправив

#18 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-09 22:16:59

Якось так ....

#include <Adafruit_GFX.h>    	// Core graphics library
#include <Adafruit_ST7735.h> 	// Hardware-specific library for ST7735
#include <SPI.h>
#define TFT_CS        10
#define TFT_RST        8 		// Or set to -1 and connect to Arduino RESET pin
#define TFT_DC         9
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
#include <SoftwareSerial.h>
#include <string.h>
SoftwareSerial gpsSerial(4, 3); // (RX, TX Arduino)

String nmeaSentence = ""; 		// Переменная для хранения NMEA-строки
const int timezoneOffset = 3;	// Часовой пояс (например, +3 для EEST)
boolean valid = false;			// флаг валидности координат
boolean drive = false;			// флаг движения
boolean overtime = false;		// флаг время/скорость

//	char tokenKnot[] = "10.5"; 		// Пример тестового значения


void setup() {
//								Serial.begin(9600);
gpsSerial.begin(9600);
tft.initR(INITR_BLACKTAB);   	// initialize a ST7735S chip, black tab
tft.setRotation(3);     		// Установка ориентации экрана
tft.fillScreen(ST77XX_BLACK);	// Установка начального цвета фона
}

void loop() {
  while (gpsSerial.available()) {
    char c = gpsSerial.read(); 	// Считать один символ из GPS
    if (c == 'n') { 			// Проверить, является ли символ концом NMEA-строки
      GPS_run(nmeaSentence); 	// Передать строку в GPS_run() для обработки
      nmeaSentence = ""; 		// Очистить строку для следующей NMEA-строки
    } else if (c != 'r') { 	// Игнорировать символ возврата каретки
      nmeaSentence += c; 		// Добавить символ к строке NMEA
    }
  }
}

void GPS_run(String nmea) {
  if (nmea.startsWith("$GPRMC")) { 					// Проверка на идентификатор строки
//								Serial.println("______________________________"); 
//								Serial.println("_______ вход в $GPRMC ***1*** ");
    char nmeaCStr[nmea.length() + 1];
    nmea.toCharArray(nmeaCStr, nmea.length() + 1);
    int fieldIndex = 0;
    char *token = nmeaCStr;
    char *commaPos = strchr(token, ',');			// Найти первую запятую
    while (fieldIndex <= 13) {
    if (commaPos) {
    *commaPos = ''; 								// Разделяем строку на части

if (fieldIndex == 1) {printFormattedTime(token);token = nullptr;}	// выводим время 1
if (fieldIndex == 2) {printFormattedValid(token);token = nullptr;}	// выводим валидность координат 2	
if (fieldIndex == 7) {printFormattedSpeed(token);token = nullptr;}// выводим скорость 7
if (fieldIndex == 9) {printFormattedDate(token);token = nullptr;}	// выводим дату 9

token = commaPos + 1;
commaPos = strchr(token, ',');} 
else {break;}
      fieldIndex++;}
	}	
	
  if (nmea.startsWith("$GPGGA")) { 					// Проверка на идентификатор строки
//								Serial.println("______________________________");  
//								Serial.println("_______ вход в $GPGGA ***2*** ");
	char nmeaCStr[nmea.length() + 1];
    nmea.toCharArray(nmeaCStr, nmea.length() + 1);
    int fieldIndex = 0;
    char *token = nmeaCStr;
    char *commaPos = strchr(token, ',');			// Найти первую запятую
    while (fieldIndex <= 14) {
    if (commaPos) {
    *commaPos = ''; 								// Разделяем строку на части
 
if (fieldIndex == 7) {printFormattedSatelit(token);token = nullptr;}// выводим спутники 7

token = commaPos + 1;
commaPos = strchr(token, ',');} 
else {break;}
      fieldIndex++;}
	}	
}


// Функция контроля достоверности полученных координат
void printFormattedValid(char* rawValid) {
//									Serial.print("Полученная rawValid       : ");
//	Serial.print(valid); Serial.print(" - "); Serial.println(rawValid);
if (strcmp(rawValid, "V") == 0) {valid = false;}
if (strcmp(rawValid, "A") == 0) {valid = true;}
}


// Функция для форматирования количества спутников
void printFormattedSatelit(char* rawSatel) {
//									Serial.print("Полученная rawSatel       : ");
//									Serial.println(rawSatel);
	static char previousSatel[5];
	if (strcmp(rawSatel, previousSatel) != 0) {
	tft.fillRect(125, 1, 29, 20, ST77XX_BLACK);}
tft.setTextColor(ST7735_WHITE);
tft.setTextSize(1);
tft.setCursor(12, 10);
tft.print("active satellites");
if (valid == false) {tft.setTextColor(ST77XX_RED);}
if (valid == true) {tft.setTextColor(ST77XX_GREEN);}
tft.setTextSize(2); 
tft.setCursor(127, 5);
tft.print(rawSatel);
	strncpy(previousSatel, rawSatel, sizeof(previousSatel) - 1);
    previousSatel[sizeof(previousSatel) - 1] = '';
}


// Функция для форматирования скорости (knot -> km/h)
void printFormattedSpeed(char* rawKnot) {
//    Serial.print("Полученная rawKnot : ");
//    Serial.println(rawKnot);
    tft.setTextColor(ST77XX_ORANGE);
    tft.setTextSize(5);
    tft.setCursor(35, 45);
    float Kmh = atof(rawKnot) * 1.852;
  int speedKmh = (int)Kmh;
  if (speedKmh == 0) {drive = false; return;} 
  else {drive = true;}  
//    Serial.print("Конвертируем узлы в км/ч speedKmh : ");
//    Serial.println(speedKmh);
    char fullSpeed[5];
    sprintf(fullSpeed, "%03d", speedKmh);
	tft.fillRect(5, 40, 155, 45, ST77XX_BLACK);
//  tft.drawRect(5, 40, 155, 45, ST77XX_WHITE);
    tft.print(fullSpeed); 
//    Serial.print("Форматируем число с ведущими нулями fullSpeed: ");
//    Serial.println(fullSpeed);
}


// Функция для форматирования времени с учётом часового пояса (UTC -> ЧЧ:ММ:СС)
void printFormattedTime(char* utcTime) {
//									Serial.print("Полученная utcTime       : ");
//									Serial.println(utcTime);
  char fullTime[9]; 								// Переменная для хранения строки времени в формате "HH:MM:SS"
  char hh[3], mm[3], ss[3];
  strncpy(hh, utcTime, 2); hh[2] = '';
  strncpy(mm, utcTime + 2, 2); mm[2] = '';
  strncpy(ss, utcTime + 4, 2); ss[2] = '';
  int hour = atoi(hh) + timezoneOffset;				// Коррекция часа в зависимости от timezoneOffset
  if (hour < 0) hour += 24; 						// Если час отрицательный, добавляем 24
  if (hour >= 24) hour -= 24; 						// Если час превышает 24, вычитаем 24
  sprintf(fullTime, "%02d:%s:%s", hour, mm, ss);	// Формируем строку времени
// время вверху
	if (drive == false) {
tft.fillRect(5, 40, 155, 45, ST77XX_BLACK);
tft.setTextColor(ST7735_YELLOW);
tft.setTextSize(3);
tft.setCursor(10, 50); tft.print(fullTime); } 
	if (drive == true) { 
tft.fillRect(15, 94, 130, 25, ST77XX_BLACK);
tft.setTextColor(ST7735_YELLOW);
tft.setTextSize(2);
tft.setCursor(30, 100); tft.print(fullTime); 
	overtime = true;}
}


// Функция для форматирования даты (ДД.ММ.ГГГГ)
void printFormattedDate(char* rawDate) {
//									Serial.print("Полученная drive d rawDate : ");
//									Serial.println(drive);
	if (drive == true) {return;}
//									Serial.print("Полученная rawDate       : ");
//									Serial.println(rawDate);
	static char previousDate[11];
	if (strcmp(rawDate, previousDate) != 0 || overtime == true) {
	tft.fillRect(15, 94, 130, 25, ST77XX_BLACK);}
	overtime = false;
char fullDate[11]; 									// Переменная для хранения полной строки даты (формат "DD.MM.YYYY")
char dd[3], mm[3], yy[3]; 							// Обратите внимание, что yy теперь размера 3, а не 5
strncpy(dd, rawDate, 2); dd[2] = '';
strncpy(mm, rawDate + 2, 2); mm[2] = '';
strncpy(yy, rawDate + 4, 2); yy[2] = '';
sprintf(fullDate, "%s.%s.20%s", dd, mm, yy);		// Формируем строку даты
tft.setTextColor(ST77XX_MAGENTA);
tft.setTextSize(2);
tft.setCursor(20, 100);
tft.print(fullDate);
	strncpy(previousDate, rawDate, sizeof(previousDate) - 1);
    previousDate[sizeof(previousDate) - 1] = '';
}

#19 Re: Апаратні питання » Реле для ардуіно 2+КВ » 2025-04-06 16:30:21

Треба робити схему реле + транзистор (паралельно) для такої потужності.

#20 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-05 16:45:50

jokeR пише:

Це не наш шлях ...

arduino-way це використовувати по максимуму вже написаний код.
Ну, хіба що самому цікаво погратися в С wink

Якась ардуінофобія ... hmm

#21 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-05 16:21:08

Дякую всім, вже вийшло те що хотів  big_smile  big_smile  big_smile

Тепер буду нарощувати код ...


dimich пише:
renoshnik пише:

отримую таке

Які поля з яких типів повідомлень вам потрібно витягти?

В мене GPS модуль і треба витягнути данні для роботи (час, дата, швидкість, координати і т.п.)

#22 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-05 16:17:57

jokeR пише:

https://docs.arduino.cc/libraries/nmeaparser/
Все вже кимсь написано wink

Це не наш шлях ...

#23 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-05 14:27:33

dimich пише:
jokeer пише:

Або візьміть приклад з man strtok і переробіть під себе.

strtok() витягає тільки непусті токени. NMEA може містити пусті.

отож бо і воно....

#include <SoftwareSerial.h>
#include <string.h>
SoftwareSerial gpsSerial(4, 3); 
String nmeaSentence = ""; 
void setup() {
  Serial.begin(115200);
  gpsSerial.begin(9600);
  Serial.println("Начало чтения NMEA-строк...");
}

void loop() {
  while (gpsSerial.available()) {
    char c = gpsSerial.read(); 
    if (c == 'n') { 
      GPS_run(nmeaSentence); 
      nmeaSentence = ""; 
    } else if (c != 'r') { 
      nmeaSentence += c; 
    }
  }
}

void GPS_run(String nmea) {
  if (nmea.startsWith("$GPGSA")) { // Проверка на идентификатор строки
    Serial.println("Обработка строки $GPGSA:");
    Serial.println(nmea); // Вывод исходной строки

    char nmeaCStr[nmea.length() + 1];
    nmea.toCharArray(nmeaCStr, nmea.length() + 1);

    char *token = strtok(nmeaCStr, ",");
    int fieldIndex = 1; 

    for (int i = 1; i <= 18; i++) { // для теста обрабатываем ровно 18 полей
      Serial.print("Поле ");
      Serial.print(i);
      Serial.print(": ");
      Serial.println(token);
      token = strtok(NULL, ","); // Переход к следующему значению
    }
  }
}

отримую таке

Начало чтения NMEA-строк...
Обработка строки $GPGSA:
$GPGSA,A,3,31,16,18,26,29,,,,,,,,3.1,1.9,2.4*3D
Поле 1: $GPGSA
Поле 2: A
Поле 3: 3
Поле 4: 31
Поле 5: 16
Поле 6: 18
Поле 7: 26
Поле 8: 29
Поле 9: 3.1
Поле 10: 1.9
Поле 11: 2.4*3D
Поле 12: 
Поле 13: 
Поле 14: 
Поле 15: 
Поле 16: 
Поле 17: 
Поле 18: 
Обработка строки $GPGSA:
$GPGSA,A,3,31,16,18,26,29,,,,,,,,3.1,1.9,2.4*3D

#24 Re: Програмування Arduino » парсинг NMEA **проблема » 2025-04-05 13:00:29

Ось цим подивився що видає блок

#include <SoftwareSerial.h>
SoftwareSerial gpsSerial(4, 3); // RX (к Arduino), TX (к GPS-модулю)
void setup() {
  Serial.begin(115200);
  gpsSerial.begin(9600);
  Serial.println("Начало чтения NMEA-строк...");
}
void loop() {
  if (gpsSerial.available()) {
    static char buffer[128]; 
    static size_t index = 0; 
    char c = gpsSerial.read(); 
    if (c == 'n') { 
      buffer[index] = ''; 
      Serial.println(buffer); 
      index = 0; } 
	else if (index < sizeof(buffer) - 1) {buffer[index++] = c;}
  }
}

отримав такі данні

Начало чтения NMEA-строк...
$GPGGA,085638.000,4829.8262,N,03556.0484,E,1,03,7.9,120.1,M,18.9,M,,0000*57
$GPGSA,A,2,31,29,28,,,,,,,,,,7.9,7.9,1.0*31
$GPRMC,085638.000,A,4829.8262,N,03556.0484,E,0.00,,050425,,,A*72

$GPGGA,085639.000,4829.8262,N,03556.0484,E,1,03,7.9,120.1,M,18.9,M,,0000*56
$GPGSA,A,2,31,29,28,,,,,,,,,,7.9,7.9,1.0*31
$GPGSV,3,1,10,25,82,177,,29,58,268,33,12,46,126,,11,39,054,17*75
$GPGSV,3,2,10,28,37,287,34,20,31,093,23,31,23,312,40,05,17,131,19*79
$GPGSV,3,3,10,06,10,040,,18,09,207,*7E
$GPRMC,085639.000,A,4829.8262,N,03556.0484,E,0.00,,050425,,,A*73

$GPGGA,085640.000,4829.8262,N,03556.0484,E,1,03,7.9,120.1,M,18.9,M,,0000*58
$GPGSA,A,2,31,29,28,,,,,,,,,,7.9,7.9,1.0*31
$GPRMC,085640.000,A,4829.8262,N,03556.0484,E,0.00,,050425,,,A*7D

$GPGGA,085641.000,4829.8262,N,03556.0484,E,1,03,7.9,120.1,M,18.9,M,,0000*59
$GPGSA,A,2,31,29,28,,,,,,,,,,7.9,7.9,1.0*31
$GPRMC,085641.000,A,4829.8262,N,03556.0484,E,0.00,,050425,,,A*7C

$GPGGA,085642.000,4829.8262,N,03556.0484,E,1,03,7.9,120.1,M,18.9,M,,0000*5A
$GPGSA,A,2,31,29,28,,,,,,,,,,7.9,7.9,1.0*31
$GPRMC,085642.000,A,4829.8262,N,03556.0484,E,0.00,,050425,,,A*7F

$GPGGA,085643.000,4829.8262,N,03556.0484,E,1,03,7.9,120.1,M,18.9,M,,0000*5B
$GPGSA,A,2,31,29,28,,,,,,,,,,7.9,7.9,1.0*31
$GPRMC,085643.000,A,4829.8262,N,03556.0484,E,0.00,,050425,,,A*7E

$GPGGA,085644.000,4829.8262,N,03556.0484,E,1,03,7.9,120.1,M,18.9,M,,0000*5C
$GPGSA,A,2,31,29,28,,,,,,,,,,7.9,7.9,1.0*31
$GPGSV,3,1,10,25,82,177,,29,58,268,33,12,46,126,,11,39,054,17*75
$GPGSV,3,2,10,28,37,287,33,20,31,093,22,31,23,312,40,05,17,131,17*71
$GPGSV,3,3,10,06,10,040,,18,09,207,*7E
$GPRMC,085644.000,A,4829.8262,N,03556.0484,E,0.00,,050425,,,A*79

переробив парсер

#include <SoftwareSerial.h>

SoftwareSerial gpsSerial(4, 3); // Пины для подключения GPS (RX, TX)

char value[32];
char buffer[128];
char subBuffer[128]; // Дополнительный буфер для разделения склеенных строк

void parseNMEA(const char* identifier, int commaIndex) {

    while (gpsSerial.available()) {
        memset(buffer, 0, sizeof(buffer)); // Очистка основного буфера
        size_t len = gpsSerial.readBytesUntil('n', buffer, sizeof(buffer) - 1);
        buffer[len] = 'n'; // Завершающий символ строки

        // Проверка на склеенные строки
        if (strstr(buffer, identifier) && strstr(buffer, "$GPGGA")) {
Serial.println("Обнаружена склеенная строка! Разделяем...");
            char* secondPart = strstr(buffer, "$GPGGA"); // Находим начало второй строки
            size_t firstPartLen = secondPart - buffer;   // Вычисляем длину первой строки

            // Копируем первую часть строки в отдельный буфер
            strncpy(subBuffer, buffer, firstPartLen);
            subBuffer[firstPartLen] = 'n';

Serial.print("Первая часть строки: ");
Serial.println(subBuffer);

            // Обрабатываем первую часть строки
            processLine(subBuffer, identifier, commaIndex);

            // Обрабатываем вторую часть строки
Serial.print("Вторая часть строки: ");
Serial.println(secondPart);
            processLine(secondPart, identifier, commaIndex);
            continue;
        }

        // Фильтр: проверяем начало строки
        if (buffer[0] != '$') {
Serial.println("Строка пропущена: некорректный формат");
            continue;
        }

Serial.print("Полученная строка: ");
Serial.println(buffer);

        // Обработка строки с использованием идентификатора
        processLine(buffer, identifier, commaIndex);
    }
}

void processLine(const char* buffer, const char* identifier, int commaIndex) {
    // Проверяем соответствие идентификатору
    if (strncmp(buffer, identifier, strlen(identifier)) == 0) {
        const char* ptr = buffer;
        for (int i = 0; i < commaIndex; i++) {
            ptr = strchr(ptr, ',');
            if (!ptr) {
Serial.println("Ошибка: недостаточно запятых.");
                return;
            }
            ptr++; // Переход к следующему символу после запятой
        }

        // Получаем значение после запятой
        //char value[32];
        size_t i = 0;
        while (*ptr && *ptr != ',' && *ptr != 'r' && *ptr != 'n' && i < sizeof(value) - 1) {
            value[i++] = *ptr++;
        }
        value[i] = 'n';

//Serial.print("Найдено значение: ");
//Serial.println(value);
        return(value);
    }
}

void setup() {
    Serial.begin(115200);
    gpsSerial.begin(9600);
    Serial.println("Инициализация завершена. Ожидаю данные...");
}

void loop() {
    parseNMEA("$GPGSA", 15); // Ищем данные $GPRMC после девятой запятой
Serial.print("-----------Найдено значение  $GPGSA, 15 : ");
Serial.println(value);
    delay(1000); // Увеличенный интервал для предотвращения переполнения
  
    parseNMEA("$GPGGA", 4); // Ищем данные $GPRMC после девятой запятой
Serial.print("-----------Найдено значение  $GPGGA, 4 : ");
Serial.println(value);
    delay(1000); // Увеличенный интервал для предотвращения переполнения
  
  parseNMEA("$GPRMC", 9); // Ищем данные $GPRMC после девятой запятой
Serial.print("-----------Найдено значение  $GPRMC, 9 : ");
Serial.println(value);
    delay(1000); // Увеличенный интервал для предотвращения переполнения

Serial.println("+++++++++++++++++++++++++++++++");
  
}

тепер отримую таке

Инициализация завершена. Ожидаю данные...
Найдено значение  $GPGSA, 15 : 
Обнаружена склеенная строка! Разделяем...
Первая часть строки: 

Вторая часть строки: $GPGGA,095405.000,4829.8325,N,03556.0791,E,1,03,25.2,189.4,M,18$GPGGA,095406.000,4829.8319,N,03556.0755,E,1,03,25.1,187.5,M,18.
,M,,0000*6A
$GPGSA,A,2,26,31,28,,,,,,,,,,25.2,25.1,1.0*3D
$G.9⸮
Строка пропущена: некорректный формат
Полученная строка: $GPGSA,A,2,26,31,28,,,,,,,,,,25.2,25.1,1.0*3D

Полученная строка: $G829.8319,N,0355,E,23.78,275.81,050425,,,A*57

Найдено значение  $GPGGA, 4 : 03556.0791

Полученная строка: $GPGGA,095407.000,4829.8315,N,03556.0725,E,1,03,25.1,185.7,M,18$GPGGA,095408.000,4829.8313,N,03556.0708,E,1,03,25.1,184.3,M,18.
A,2,26,31,3556.0708,E,1,03,25.1,184.3,M,18.9,M,,0000*63
$GPGSA,Y
Строка пропущена: некорректный формат
Полученная строка: $GPGSA,A,2,26,31,28,,,,,,,,,,25.1,25.1,1.0*3E

Полученная строка: $GPRMC,095408.000,A,4829.8313,N,03556.0708,E,21.39,276.20,050425,,,A*54

Найдено значение  $GPRMC, 9 : 050425
791

+++++++++++++++++++++++++++++++
Полученная строка: $GPGGA,095409.000,4829.8307,N,03556.0723,E,1,03,25.1,183.0,M,1818,33,214,,28,31,257,20,31,31,287,26,12,22,139,20*7E

Полученная строка: $GPGSV,3,3,10,26,19,309,26,11,17,048,18*79

Полученная строка: $GPRMC,095409.000,A,4829.8307,N,03556.0723,E,18.97,274.54,050425,,,A*56

Найдено значение  $GPGSA, 15 : 050425
791

Обнаружена склеенная строка! Разделяем...
Первая часть строки: 

Вторая часть строки: $GPGGA,095410.000,4829.8299,N,03556.0744,E,1,03,25.1,181.8,M,18$GPGGA,095411.000,4829.8291,N,03556.0784,E,1,03,25.0,180.7,M,18.
,,,,,25.1,25.0,1.0*3F
$G.9,M,,0000*65
$GPGSA,A,2,26,31,28,,,,,.:
Строка пропущена: некорректный формат
Полученная строка: $GPGSA,A,2,26,31,28,,,,,,,,,,25.1,25.0,1.0*3F

Полученная строка: $G829.8291,N,0354,E,14.19,272.45,050425,,,A*50

Найдено значение  $GPGGA, 4 : 03556.0744

Полученная строка: $GPGGA,095412.000,4829.8293,N,03556.0725,E,6,00,50.0,180.5,M,18$GPGGA,095413.000,4829.8294,N,03556.0665,E,6,00,50.0,180.2,M,18.
,M,18.9,M,,0000*6F
$GPGSA,A,2,,,,,,,,,,,,,50.0,,6,00,50.0,180.2⸮!
Строка пропущена: некорректный формат
Полученная строка: $GPGSA,A,2,,,,,,,,,,,,,50.0,50.0,50.0*06

Полученная строка: $GPRMC,095413.000,V,4829.8294,N,03556.0665,E,14.19,272.45,050425,,,E*4A

Найдено значение  $GPRMC, 9 : 050425
744

+++++++++++++++++++++++++++++++

наче краще але купа якихось артифактів .....

якщо закоментувати перевірочні виводи в монітор то якась маячня виходить...

Инициализация завершена. Ожидаю данные...
Найдено значение  $GPGSA, 15 : 
Найдено значение  $GPGGA, 4 : 

Найдено значение  $GPRMC, 9 : 

+++++++++++++++++++++++++++++++
Найдено значение  $GPGSA, 15 : 

Найдено значение  $GPGGA, 4 : 

Найдено значение  $GPRMC, 9 : 050425

+++++++++++++++++++++++++++++++
Найдено значение  $GPGSA, 15 : 050425

Найдено значение  $GPGGA, 4 : 
50425

Найдено значение  $GPRMC, 9 : 050425

+++++++++++++++++++++++++++++++
Найдено значение  $GPGSA, 15 : 050425

Найдено значение  $GPGGA, 4 : 
50425

Найдено значение  $GPRMC, 9 : 
50425

+++++++++++++++++++++++++++++++
Найдено значение  $GPGSA, 15 : 28
425

Найдено значение  $GPGGA, 4 : 28
425

Найдено значение  $GPRMC, 9 : 050425

+++++++++++++++++++++++++++++++
Найдено значение  $GPGSA, 15 : 050425

Найдено значение  $GPGGA, 4 : 050425

Найдено значение  $GPRMC, 9 : 050425

+++++++++++++++++++++++++++++++

#25 Програмування Arduino » парсинг NMEA **проблема » 2025-04-05 09:06:17

renoshnik
відповідей: 65

Намагаюся розпарсити рядок данних NMEA. Зробив такий скетч.

#include <SoftwareSerial.h>
// Настраиваем пины для подключения GPS-модуля
const int RXPin = 4, TXPin = 3;
SoftwareSerial gpsSerial(RXPin, TXPin);
char nmeaBuffer[88]; // Буфер для строки NMEA
int bufferIndex = 0;
char token_1[88];
char token_2[88]; 
char token_3[88]; 
char token_4[88]; 
char token_5[88]; 
char token_6[88]; 
char token_7[88]; 
char token_8[88]; 
char token_9[88]; 
char token_10[88]; 
char token_11[88]; 

//	$GPRMC,180708.000,A,4829.8325,N,03556.0990,E,4.21,66.09,040425,,,A*5F
//	$GPRMC,180654.000,A,4829.8202,N,03556.0560,E,0.00,,040425,,,A*70
 
void setup() {
  Serial.begin(115200); // Настройка монитора порта
  gpsSerial.begin(9600); // Настройка GPS-модуля
  Serial.println("Ожидание данных...");
}

void loop() {
  while (gpsSerial.available()) {
    char c = gpsSerial.read();
    // Считываем строку, пока не достигнем конца строки
    if (c == 'n') {
      nmeaBuffer[bufferIndex] = ''; // Завершаем строку
      processNMEA(nmeaBuffer); // Обрабатываем строку
      bufferIndex = 0; // Сбрасываем индекс для следующей строки
    } else if (bufferIndex < 87) {
      nmeaBuffer[bufferIndex++] = c; // Сохраняем символ в буфер
    }
  }
}

void processNMEA(char* nmea) {
  // Проверяем, является ли строка строкой $GPRMC
  if (strncmp(nmea, "$GPRMC", 6) == 0) {
    Serial.print("Строка протокола: ");
    Serial.println(nmea); // Вывод всей строки $GPRMC
sscanf(nmea, "%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%[^',']", 
token_1, token_2, token_3, token_4, token_5, token_6, token_7, token_8, token_9, token_10, token_11);
    //Serial.print("Дата: ");
	Serial.print(" token_1 = "); Serial.println(token_1);
	Serial.print(" token_2 = "); Serial.println(token_2);
	Serial.print(" token_3 = "); Serial.println(token_3);
	Serial.print(" token_4 = "); Serial.println(token_4);
	Serial.print(" token_10 = "); Serial.println(token_10);
	Serial.print(" token_11 = "); Serial.println(token_11);
		
    //printFormattedDate(token_10);
  }    }

// Функция для форматирования даты (ДД.ММ.ГГГГ)
void printFormattedDate(char* rawDate) {
  if (strlen(rawDate) < 6) return; // Проверяем длину строки
  char dd[3], mm[3], yy[5];
  strncpy(dd, rawDate, 2); dd[2] = '';
  strncpy(mm, rawDate + 2, 2); mm[2] = '';
  strncpy(yy, rawDate + 4, 2); yy[2] = '';
  Serial.print(dd); Serial.print(".");
  Serial.print(mm); Serial.print(".");
  Serial.print("20"); // Добавляем "20" для полного формата года
  Serial.println(yy);
}

але результат незадовільний

Ожидание данных...
Строка протокола: $GPRMC,055655.062,V,4829.8313,N,03556.0391,E,,,050425,,,N*72

 token_1 = $GPRMC
 token_2 = 055655.062
 token_3 = V
 token_9 = 4829.8313
 token_10 = 
 token_11 = 
Строка протокола: $GPRMC,055656.062,V,4829.8313,N,03556.0391,E,,,050425,,,N*71

 token_1 = $GPRMC
 token_2 = 055656.062
 token_3 = V
 token_9 = 4829.8313
 token_10 = 
 token_11 = 
Строка протокола: $GPRMC,055657.062,V,4829.8313,N,03556.0391,E,,,050425,,,N*70

 token_1 = $GPRMC
 token_2 = 055657.062
 token_3 = V
 token_9 = 4829.8313
 token_10 = 
 token_11 =
Строка протокола: $GPRMC,063155.062,A,4829.8269,N,03556.0546,E,0.30,48.66,050425,,,A*57

 token_1 = $GPRMC
 token_2 = 063155.062
 token_3 = A
 token_9 = 4829.8269
 token_10 = 050425
 token_11 = 
Строка протокола: $GPRMC,063156.062,A,4829.8269,N,03556.0545,E,0.34,41.38,050425,,,A*51

 token_1 = $GPRMC
 token_2 = 063156.062
 token_3 = A
 token_9 = 4829.8269
 token_10 = 050425
 token_11 = 
Строка протокола: $GPRMC,063157.062,A,4829.8270,N,03556.0545,E,0.41,33.89,050425,,,A*55

 token_1 = $GPRMC
 token_2 = 063157.062
 token_3 = A
 token_9 = 4829.8270
 token_10 = 050425
 token_11 = 

Проблема в тому, що серія ком ( ,,, ) функцією sscanf обробляється не корректно ...  sad sad sad

Підвал форуму