Serial.read: почему разбивается строка приема?
- Войдите на сайт для отправки комментариев
Чт, 20/09/2018 - 09:50
Никак не при ходит в голову почему так. Отправляю в Serial строку, программа выдает два результата: первый байт как отдельную строку и остаток строки отдельно. А нужна строка целиком.
uint8_t bytes;
char buffer[255];
void setup() {
Serial.begin (115200);
delay(3000);
Serial.println ("Ready!");
buffer[0] = 0;
}
void loop() {
bytes = Serial.available();
if (bytes > 0) {
Serial.println ();
Serial.print (">>> Bytes: ");
Serial.println (bytes);
uint8_t i = 0;
while (i < bytes) {
buffer[i] = (char) Serial.read();
Serial.print (">>> Copying ");
Serial.print (i);
Serial.print (" byte ");
Serial.println (buffer[i]);
i++;
delay (10);
}
buffer[i] = 0;
Serial.print (">>> Buffer: ");
Serial.println (buffer);
Serial.println();
}
}
Простое совпадение.
Поставьте скорость меньше, уберите delay(), переставьте операторы местами - картина изменится. RX буфер объекта Serial заполняется по прерыванию. Поэтому он может быть дополнен на середине любой операции не блокирующей прерывания.
Нужна строка целиком - используйте терминатор строки или ловите паузу (за секунду не увеличился буфер - значит передача окончена).
или используйте строки фиксированной длинны, и вычитывайте буфер когда в нем уже накопилось необходимое количество байт.
Возможно пока вы что-то "обрабатываете" приходят ешё данные?
То есть вы не всю сторку считали.....
Попробуйте всавить после 23 строчки две вот таких:
Serial.println (bytes);
Serial.println (Serial.available());
Отправляю в Serial строку
Надо для себя ответить на вопрос: что есть строка. Например, если вы отправляете "Hello, world!", а в буфер на момент проверки попало только "Hell" - это строка? Формально - да, т.к. строка - это набор символов. Понимаете, о чём я? Надо иметь признак - что вот, данные ПОЛНОСТЬЮ упали в приёмный буфер. Что будет этим признаком - выбирать вам, например, этим признаком может служить символ перевода строки '\n', или ещё чего.
Сделал так:
void loop() { bytes = Serial.available(); if (bytes > 0) { Serial.println (); Serial.print (">>> Bytes: "); Serial.println (bytes); uint8_t i = 0; while (Serial.available()) { while (i < bytes) { buffer[i] = (char) Serial.read(); Serial.print (">>> Copying "); Serial.print (i); Serial.print (" byte "); Serial.println (buffer[i]); i++; delay (10); } if (Serial.available()) { bytes += Serial.available(); } } buffer[i] = 0; Serial.print (">>> Buffer: "); Serial.println (buffer); Serial.println(); } }Сделал так:
void loop() { bytes = Serial.available(); if (bytes > 0) { Serial.println (); Serial.print (">>> Bytes: "); Serial.println (bytes); uint8_t i = 0; while (Serial.available()) { while (i < bytes) { buffer[i] = (char) Serial.read(); Serial.print (">>> Copying "); Serial.print (i); Serial.print (" byte "); Serial.println (buffer[i]); i++; delay (10); } if (Serial.available()) { bytes += Serial.available(); } } buffer[i] = 0; Serial.print (">>> Buffer: "); Serial.println (buffer); Serial.println(); } }по-моему, никакой разницы с первоначальным - строка ровно точно так же может биться на части.
Вы поняли, что вам писал DIYMan о признаке конца строки? И где это в коде?
Работает однако. Serial.available() возвращает нужное количество байт, их количество и читаем.
Работает однако. Serial.available() возвращает нужное количество байт, их количество и читаем.
Случайность. Идея все равно неверная. 100% потом будет глючить.
Serial.available() у вас возвращает то количество байт, которое уже лежит в буфере. Если строка к этому моменту еще не пришла целиком - получите только часть.
Единственный рабочий метод - тот. что описал DIYMan.
Единственный рабочий метод - тот. что описал DIYMan.
категорично !
я уже писал как делаю, шлю (допустим) 0х55,0хАА это типа синхронизации, далее байт с длиной пакета, далее данные.
этот метод не рабочий ?
Единственный рабочий метод - тот. что описал DIYMan.
категорично !
я уже писал как делаю, шлю (допустим) 0х55,0хАА это типа синхронизации, далее байт с длиной пакета, далее данные.
этот метод не рабочий ?
Это ровно то же самое, что описал я: у тебя признак конца пакета - вычисляемый от "байт с длиной пакета". Но - признак конца пакета - ЕСТЬ. У ТС - нет. В твоём случае код будет таким, навскидку:
#pragma pack(push,1) typedef struct { uint8_t stx1; uint8_t stx2; uint8_t dataLen; } PacketHeader; #pragma pack(pop) PacketHeader packet; void loop() { if(Serial.available() >= sizeof(packet)) { packet.stx1 = Serial.read(); packet.stx2 = Serial.read(); packet.dataLen = Serial.read(); if(packet.stx1 == 0x55 && packet.stx2 == 0xAA) { uint8_t readed = 0; uint8_t* data = new uint8_t[packet.dataLen]; while(readed < packet.dataLen) { if(!Serial.available()) continue; data[readed++] = Serial.read(); } // тут работаем с данными delete[] data; } } }Чисто для демонстрации, что и при таком подходе есть ОДНОЗНАЧНЫЙ признак конца пакета с данными. О чём я и писал.
Работает однако. Serial.available() возвращает нужное количество байт, их количество и читаем.
Это до чтения, а после чтения должен быть ноль.
прочитал еще раз, ключевые слова "Что будет этим признаком - выбирать вам,"
согласен ! :)
Более того: в продвинутых случаях (например, при включении устройства в шину с данными в любой момент времени) - зачастую требуется синхронизация по началу пакета, т.е.: мы должны однозначно синхронизироваться так, чтобы буть уверенными - мы на начале пакета с данными. Для этого тоже есть простые механизмы поиска фрейма синхронизации в потоке принятых данных. Иначе - легко получить поведение, когда вроде бы устройство в сети, получает данные - но, не реагирует, потому что при включении просохатило первые два байта.