#51 2025-04-10 11:49:46

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 377

Re: парсинг NMEA **проблема

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

dimich пише:

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

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

Неактивний

#52 2025-04-10 12:02:23

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,057

Re: парсинг NMEA **проблема

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;
}	
	

Неактивний

#53 2025-04-10 20:46:32

jokeer
Гість

Re: парсинг NMEA **проблема

Дійсно, динамічно виділяти пам'ять під масив можна wink Вік живи.. Але я б такого категорично не рекомендував.В мікроконтролері, де пам'яті  небагато, треба по максимуму виділяти пам'ять статично -: якщо її не вистачить - програма тупо не скомпілюється. А якщо не вистачить пам'яті при роботі.. Дрон впаде, регулятор обертів спалить двигун, самогонний апарат перегріється.. Воно вам треба? wink

#54 2025-04-10 22:39:21

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 377

Re: парсинг NMEA **проблема

jokeer пише:

Дійсно, динамічно виділяти пам'ять під масив можна wink

Це не динамічне виділення в сенсі з купи, як malloc() або оператор new. Тут памʼять виділяється на стеку, як для звичайної локальної змінної. Компілятору нема різниці, чи віднімати від вказівника вершини стека константу, чи значення якого-небудь регістра.
Те ж саме можна зробити "класичним" методом:

char *array = alloca(strlen(str) + 1);
jokeer пише:

А якщо не вистачить пам'яті при роботі..

Проблема не стільки в тому, що памʼяті може не вистачити, а в тому, що нема можливості це перевірити навіть в рантаймі. При динамічному виділенні є можливіть перевірити успішність результата (і грамотно написаний код має це перевіряти). Хоча в ардуіно фреймворку це теж не дає 100% гарантії, бо хто знає, скільки байтів ще напхає в стек який-небуть обробник переривання умовної бібліотеки Wire. Може і для ардуіни є якісь реалізації runtime stack guard, але мені не зустрічались.

Неактивний

#55 2025-04-10 23:14:41

jokeer
Гість

Re: парсинг NMEA **проблема

Для перевірки, можливо, підійде sizeof. Але це стрьомне. Ну, і якщо пам'яті таки не вистачило, то навіть незрозуміло що гірше, просто ребутнутися, чи щось там обробляти.

#56 2025-04-11 00:04:28

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 377

Re: парсинг NMEA **проблема

jokeer пише:

Для перевірки, можливо, підійде sizeof.

Ем, оператор sizeof повертає розмір обʼєкта під час компіляції. Яким він тут боком?

jokeer пише:

Ну, і якщо пам'яті таки не вистачило, то навіть незрозуміло що гірше, просто ребутнутися, чи щось там обробляти.

Так це одна з умов постановки задачі - як обробляти ту чи іншу ситуацію. Можна показати повідомлення, можна ребутнутись, можна "зависнути", але поведінка має бути визначена. Гірше (точніше, неприпустимо), коли поведінка не визначена. Наприклад, виконається довільний код, який перемкне піни в недопустимий стан або перепише важливі дані в EEPROM.

Неактивний

#57 2025-04-11 06:32:59

jokeer
Гість

Re: парсинг NMEA **проблема

Для динамічно створеного масиву sizeof теж щось повертає. і це не відомо під час компіляції.
Ну і автоматика, яка в деяких умовах сама ребутиться, виглядає стрьомно. Це трохи краще ніж перезапис eeprom wink

#58 2025-04-11 13:24:04

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 377

Re: парсинг NMEA **проблема

jokeer пише:

Для динамічно створеного масиву sizeof теж щось повертає. і це не відомо під час компіляції.

Він повертає те ж значення, що вказане в квадратних дужках при обʼявлені масиву, помножене на розмір елемента. Це ніяк не відображає, чи не виліз стек за дозволені межі, і чи не вилізе при подальшому виклику функцій або обробників переривань.

jokeer пише:

Ну і автоматика, яка в деяких умовах сама ребутиться, виглядає стрьомно.

Від постановки задачі залежить. Іноді ребут - єдина правильна дія. Іноді має сенс додатково зберігати діагностичну інформацію, яка саме умова спричинила фолт.

Остання редакція dimich (2025-04-11 13:26:43)

Неактивний

#59 2025-04-11 13:51:11

jokeer
Гість

Re: парсинг NMEA **проблема

Ок. Ну тоді це досить стрьомна конструкція

#60 2025-04-12 16:05:35

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,057

Re: парсинг NMEA **проблема

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

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

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

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

Неактивний

#61 2025-04-12 17:05:54

jokeer
Гість

Re: парсинг NMEA **проблема

ця конструкція щось виводить у буфер. А що там у вас виводиться на екран - звідси не видно wink

#62 2025-04-12 17:07:53

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 377

Re: парсинг NMEA **проблема

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

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

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

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

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

Неактивний

#63 2025-04-12 17:14:25

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 377

Re: парсинг NMEA **проблема

Arduino IDE, як проект для навчання, мав би компілювати з -Wall -Wextra -Werror -pedantic-errors. А у них навіть "Show verbose output during: compile" за замовчуванням вимкнене. Бояться, що багатобуков злякає школярів?

Неактивний

#64 2025-04-12 17:45:12

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,057

Re: парсинг NMEA **проблема

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

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

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

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

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

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

Неактивний

#65 2025-04-15 14:27:28

renoshnik
Учасник
Зареєстрований: 2017-04-03
Повідомлень: 1,057

Re: парсинг NMEA **проблема

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;	
	}

Остання редакція renoshnik (2025-04-15 14:28:07)

Неактивний

#66 2025-04-15 15:09:04

dimich
Учасник
Зареєстрований: 2023-12-01
Повідомлень: 377

Re: парсинг NMEA **проблема

renoshnik пише:

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

Не дуже розумію, навіщо взагалі використовувати String. Це обгортка над динамічним масивом char. Вона зручна, коли потрібно обʼєднувати рядки та маніпулювати літералами що зберігаються на флеші. У вас рядок фіксованої максимальної довжини, читайте одразу в статичний масив.

Вище я наводив приклад реалізації токенайзера, який видає char* на токен по індексу, або на пустий рядок, якщо токена з таким індексом нема.

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

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