SoftwareSerial получает начало искаженных данных

Я использую SoftwareSerial для связи с модулем Sigfox. В документации по функции read ее значение присваивается char. Однако, используя его, я получаю искаженные символы, а также прочитал в другом вопросе, что я должен назначить его int, поскольку он может возвращать -1 без данных и [0 ;255] для полученного символа.

Это мой основной пример устранения неполадок:

#include <SoftwareSerial.h>
SoftwareSerial Sigfox(11,10);

void setup() {
  Serial.begin(9600); // аппаратный серийный номер
  Sigfox.begin(9600); // Серийный номер ПО --> сигфокс
}

void loop() {
  if(Sigfox.available()) {
    int c = Sigfox.read();
    Serial.write(c);
  }
  if(Serial.available()) Sigfox.write(Serial.read());
}

Когда c равно char, я получаю -5 вместо OK. Также другой вывод искажен. Когда c имеет значение int, он получает данные в порядке.

Мой вопрос: почему они используют char в примере в документации? Почему char подписан в Arduino?

Я хочу прочитать всю строку текста из последовательного порта и сохранить ее в массиве. Как определить этот массив? Я нашел пример в Интернете, который использует char buffer[32], но опять же я получаю искаженные данные, когда я назначаю ему. Если я использую массив byte/int/unsigned char, я не могу распечатать его как Serial.write(SF_buffer); не будет компилироваться из-за нет подходящей функции для вызова 'write(unsigned char [32])'.

Итак, какие типы переменных следует использовать для правильного получения и сохранения текста из SoftwareSerial?

Вот моя функция для чтения всей строки:

unsigned char SF_buffer [32]; // максимальная длина строки для чтения из серийного номера
bool SigfoxReadine() { // возвращаем true, когда целая строка получена и находится в буфере
  static int SF_cnt=0;
  while (Sigfox.available()) {
    int c = Sigfox.read();
    SF_buffer[SF_cnt++] = c;
    if ((c == '\n') || (SF_cnt == sizeof(SF_buffer)-1)) {
       SF_buffer[SF_cnt] = '\0';
       SF_cnt = 0;
       return(true);
    }
  }
  return(false);
}

ОБНОВЛЕНИЕ:

Попытка readBytesUntil — тот же результат, но я обнаружил, что проблема возникает только тогда, когда я отправляю данные в модуль с помощью println, как в этом примере:

#include <SoftwareSerial.h>
SoftwareSerial Sigfox(11,10);

void setup() {
  Serial.begin(9600); // аппаратный серийный номер
  Sigfox.begin(9600); // Серийный номер ПО --> сигфокс
  Sigfox.println("AT$I=11");
}

void loop() {
  if(Serial.available()) Sigfox.write(Serial.read());
  SF_read();
}

void SF_read() {
  if (Sigfox.available()) {
    char buff[32];
    int l = Sigfox.readBytesUntil('\n', buff, sizeof(buff));
    if (l > 0 && buff[l - 1] == '\r') {
      l--; // удалить \r, если он есть
    }
    buff[l] = 0; // завершаем строку
    Serial.println(buff);
  }
}

Ответ на первую команду (в настройках) искажен. Ответ на ту же AT-команду, вручную записанную в последовательный монитор (и отправленную в модуль через Sigfox.write в цикле), в порядке.

ӂ*⸮FBB1E27EE7

3430E2FBB1E27EE7

Также, возможно, я немного не понимаю, когда использовать print и когда писать... Пример говорит использовать write() для отправки обратно символа, который был read(). Ответ Джурай использует println() для печати буфера с завершающим нулем. Какая разница, когда я пишу/распечатываю этот буфер?

, 👍1

Обсуждение

обратитесь к этому при работе с типом данных char... http://www.asciitable.com/, @jsotola

да, рекомендуется использовать тип данных int... если вы используете тип данных byte, тогда возникает конфликт между данными и флагом ошибки... -1 эквивалентно шестнадцатеричному 0xff, который представляет собой десятичное число 255 .... для типа int десятичное число 255 представлено как 0x00ff, а -1 представлено как 0xffff... нет конфликта между этими двумя.... обратите внимание, что только один байт передается через последовательный порт... двухбайтовый int создается последовательной библиотекой, так что ваш скетч может получать статус ошибки из библиотеки, @jsotola

Serial.write(SF_buffer, length); или для массива символов с нулевым завершением Serial.print(SF_buffer);, @Juraj

@Juraj, если SF_buffer имеет тип char, я получаю искаженный вывод (SF_buffer[SF_cnt++]=c;). Как правильно присвоить int c массиву char?, @Marki555

использовать байт. отправляют ли устройства символы с кодами ascii выше 127?, @Juraj

@Юрай обычно нет. Но с char я исказил, например, исходное «ОК» в «-5». Я думаю, что вчера попробовал byte, но попробую еще раз, когда вернусь домой., @Marki555

ты заземлил? Serial.write(Sigfox.read()); должен работать, @Juraj

@Juraj да, я сделал :) Это работает. Он ломается, когда я сохраняю значение из чтения в переменную и пытаюсь записать эту переменную обратно. Если я сохраню его в char, «ОК» будет напечатано как «-5». Если я сохраню его как byte или int, он напечатает OK, но тогда у меня возникнет проблема, как сохранить всю строку в массив символов., @Marki555

какой Ардуино ты используешь?, @Juraj

@Juraj Arduino Pro Mini, последовательный порт подключен к FTDI и USB. SoftwareSerial — это модуль Sigfox Wisol. Ардуино 1.8.9., @Marki555


2 ответа


2

Мне нравится функция readBytes или readBytesUntil. Он не заканчивается на небольшом промежутке между полученными байтами и заполняет буфер. Эти функции блокируются с тайм-аутом, но при чтении с какого-либо другого устройства ввод обычно выполняется быстро и надежно завершается.

пример для readBytesUntil:

if (Serial.available()) {
  char buff[32];
  int l = Serial.readBytesUntil('\n', buff, sizeof(buff));
  if (l > 0 && buff[l - 1] == '\r') {
    l--; // удалить \r, если он есть
  }
  buff[l] = 0; // завершаем строку
  Serial.println(buff);
}
,

существует ли readBytes также для SoftwareSerial? В документации это упоминается только для Serial, @Marki555

это в базовом классе Stream, @Juraj

@Marki555, помогло?, @Juraj

тестирование... теперь кажется более странным :) вчерашняя проблема теперь, кажется, существует только при отправке данных через Sigfox.println, а не при использовании Sigfox.write..., @Marki555

отредактировал вопрос с новыми выводами, @Marki555

Нашел проблему! Спасибо за помощь в устранении неполадок., @Marki555


1

Последний тест показал, что он искажает данные только при использовании println() и не зависит от типа char. Затем я вспомнил кое-что о CRLF в таблице данных Sigfox:

Рекомендуется использовать полнодуплексный UART. В случае использования полудуплекса, AT команды должны заканчиваться только одним из '\r' или '\n', а не обоими. Потому что если вы отправите «AT\r\n» комплект разработчика Sigfox начинает отправлять «ОК» сразу после получения «\r», но микроконтроллер по-прежнему отправляет байт '\n'.

SoftwareSerial на самом деле только полудуплексный (хотя я не t найти его в справочной документации), а println() отправляет как '\r', так и '\n', поэтому при отправке позже модуль Sigfox уже пытается отправить ответ, который получает искажено SoftwareSerial.

Вы можете добавить свой ответ, чтобы объяснить, почему char подписан в Arduino и когда использовать print() и когда write() с последовательным портом.

,