ArduinoJson читает `null` из последовательного порта

У меня есть установка, которая считывает данные из последовательного порта, когда я чувствую, что есть что-то, что нужно прочитать (и всегда предполагаю, что то, что отправляется на Arduino, является действительным json):

void setup(){
    Serial.begin(9600);
    while (!Serial) continue;
}

void loop() {

    if(Serial.available()){
        StaticJsonDocument<256> doc;

        deserializeJson(doc, Serial);

        serializeJson(doc, Serial);
        Serial.println();
    }
}

Учитывая следующий ввод от последовательного монитора ArduinoIDE (установите настройку newline, 9600 бод):

{"hello": "world"}

Это приводит к следующему:

{"hello": "world"}
null

У меня два вопроса:

  • Правильна ли эта настройка/как мне следует ждать и получать JSON из последовательного порта?
  • Зачем нужен дополнительный ввод null? Похоже, что-то еще осталось в последовательном буфере даже после первой итерации?
  • Как обнаружить второй случай, когда результирующий документ повторно сериализуется как null? Сравнение с 0, NULL и nullptr, кажется, не работает Разобрался с этим, узнал о DeserializationError

При использовании DeserializationError похоже, что при синтаксическом анализе null произошла ошибка EmptyInput

, 👍1

Обсуждение

что отправляет данные? ... каковы фактические данные, которые отправляются?, @jsotola

Последовательная консоль Arduino IDE, @Snappawapa

тогда данные ручного ввода.... каковы настройки последовательной консоли? ... существует более одной настройки, @jsotola

Обновлено, чтобы показать функцию настройки., @Snappawapa

Я сказал настройки «последовательной консоли», @jsotola

Обновлено для отображения настроек (новая строка, 9600 бод)., @Snappawapa


1 ответ


1

Как видно в настройках последовательной консоли, здесь упоминаются как новая строка, так и 9600 бод. Давайте разберемся:

Проблема с последовательным соединением

  1. Частичная полезная нагрузка. В настоящее время вы предполагаете, что когда Serial.available() возвращает true, вся полезная нагрузка JSON была полученный. Однако из-за особенностей последовательной связи (особенно при скорости 9600 бод) данные могут поступать фрагментированными частями. Вызов deserializeJson() для части полезных данных JSON может привести к неполным или поврежденным данным.

  2. Неоднозначность конца сообщения. Отсутствие четкого маркера конца сообщения затрудняет определение момента получения полной полезной нагрузки JSON. Например, при отправке {"hello": "world" с последовательного монитора Arduino IDE он автоматически добавляет новую строку (или возврат каретки в зависимости от вашей конфигурации). Эта новая строка затем ошибочно интерпретируется как другая полезная нагрузка JSON, что приводит к нежелательному выводу null.

Как это решить:

  1. Использовать разделитель. Выберите определенный символ или последовательность, которая будет использоваться в качестве разделителя конца сообщения. Символ новой строки (\n) является типичным выбором, особенно если данные передаются исключительно с последовательного монитора Arduino IDE. Тем не менее, если вы ожидаете появления новых строк в своих данных JSON, вы можете использовать другой отдельный символ, например #.

  2. Читать до разделителя: настройте свой код так, чтобы он непрерывно считывал символы из последовательного порта до тех пор, пока не встретится выбранный разделитель. После получения всего сообщения его можно проанализировать.

Пример кода

Вот пример кода, в котором в качестве разделителя используется символ новой строки:

const int maxBuffer = 256;
char serialBuffer[maxBuffer];
int bufferPos = 0;

void setup() {
    Serial.begin(9600);
    while (!Serial) continue;
}

void loop() {
    if (Serial.available()) {
        char inChar = Serial.read();

        if (inChar == '\n') {  // EOM
            serialBuffer[bufferPos] = '\0';
            processMessage(serialBuffer);
            bufferPos = 0;  // Сброс позиции буфера
        } else if (bufferPos < maxBuffer - 1) {  // Избегаем переполнения буфера
            serialBuffer[bufferPos++] = inChar;
        }
    }
}

void processMessage(char* message) {
    StaticJsonDocument<256> doc;

    DeserializationError error = deserializeJson(doc, message);

    if (error) {
        Serial.println("Failed to parse JSON");
    } else {
        serializeJson(doc, Serial);
        Serial.println();
    }
}

Таким образом, вы гарантируете, что сообщение будет проанализировано и получено целиком и, следовательно, избежите нежелательных выводов null.

Надеюсь, это поможет ^_^

,