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()
для печати буфера с завершающим нулем. Какая разница, когда я пишу/распечатываю этот буфер?
@Marki555, 👍1
Обсуждение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
Последний тест показал, что он искажает данные только при использовании 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()
с последовательным портом.
- Не выводится на serial monitor, отправляя строку на serial.print
- Как получить тип данных переменной?
- Преобразование в Unix Timestamp и обратно
- AT-команда не отвечает на последовательный монитор
- Получить данные с сайта с помощью ESP8266 с помощью AT-команд
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- Как остановить SoftwareSerial от получения данных и повторно включить его в какой-то другой момент?
- SIM800L не регистрируется в сети
обратитесь к этому при работе с типом данных char... http://www.asciitable.com/, @jsotola
да, рекомендуется использовать тип данных
int
... если вы используете тип данныхbyte
, тогда возникает конфликт между данными и флагом ошибки...-1
эквивалентно шестнадцатеричному0xff
, который представляет собой десятичное число255
.... для типаint
десятичное число 255 представлено как0x00ff
, а-1
представлено как 0xffff... нет конфликта между этими двумя.... обратите внимание, что только один байт передается через последовательный порт... двухбайтовыйint
создается последовательной библиотекой, так что ваш скетч может получать статус ошибки из библиотеки, @jsotolaSerial.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