Відповісти

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

Назад

Огляд теми (нові повідомленні вгорі)

dimich
2025-04-15 15:09:04
renoshnik пише:

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

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

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

renoshnik
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;	
	}
renoshnik
2025-04-12 17:45:12
dimich пише:
renoshnik пише:
char fullSpeed[5];
sprintf(fullSpeed, "%03d", speedKmh);

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

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

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

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

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

dimich
2025-04-12 17:14:25

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

dimich
2025-04-12 17:07:53
renoshnik пише:
char fullSpeed[5];
sprintf(fullSpeed, "%03d", speedKmh);

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

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

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

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

jokeer
2025-04-12 17:05:54

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

renoshnik
2025-04-12 16:05:35
char fullSpeed[5];
sprintf(fullSpeed, "%03d", speedKmh);

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

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

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

jokeer
2025-04-11 13:51:11

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

dimich
2025-04-11 13:24:04
jokeer пише:

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

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

jokeer пише:

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

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

jokeer
2025-04-11 06:32:59

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

dimich
2025-04-11 00:04:28
jokeer пише:

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

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

jokeer пише:

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

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

jokeer
2025-04-10 23:14:41

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

dimich
2025-04-10 22:39:21
jokeer пише:

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

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

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

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

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

jokeer
2025-04-10 20:46:32

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

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

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