Дождаться получения ВСЕХ последовательных данных.
Есть ли способ заставить Arduino ждать, пока не будут получены все последовательные данные? Допустим, я отправляю строку длиной 32 байта по последовательному порту (длина на самом деле случайна), как мне заставить Arduino ждать, пока не будут получены все 32 байта?
Если я сразу выполню Serial.readBytes
, он прочитает только один символ. В данный момент я использую delay, но я беспокоюсь, что это тратит время на Arduino, так как я хотел бы, чтобы он обрабатывался немедленно. Я хочу, чтобы я подключал свой Arduino, вводил имя входного и выходного файла, и он начал копировать входной файл в выходной. Я не хочу повторно загружать каждый раз, когда хочу изменить файлы, поэтому я хотел бы выбрать, какие из них использовать, а не serial. Однако иногда в конце не будет отправлено \r
или \n
, что обрезает часть имени файла.
Вот мой код:
#include <SoftReset.h>
#include <SPI.h>
#include <SdFat.h>
#define csPin 4
SdFat SD;
File sourceFile;
File outputFile;
int bufSize;
uint32_t lastPos = 0, timeLast, timeNow;
//исправить это (ошибка: устаревшее преобразование из строковой константы в 'char*')
//char *outputFileName = "output.wav";
#define outputFileName "output.wav"
byte avail;
void setup() {
// Открываем последовательную связь и ждем открытия порта:
Serial.begin(115200);
while (!Serial) {
}
Serial.print(F("Initializing SD card..."));
// проверяем, присутствует ли карта и может ли она быть инициализирована:
if (!SD.begin(csPin, SPI_FULL_SPEED)) {
Serial.println(F("Card failed, or not present"));
soft_restart();
}
Serial.println("Card initialized.");
enterInputFileName:
Serial.println(F("Enter input file name:"));
while (!Serial.available()); // ждем, пока серийный номер станет доступен
delay(100);
avail = Serial.available() - 2; // лишние '\n' и '\r', которые нам не нужны
char inbuf[avail];
Serial.readBytes(inbuf, avail);
Serial.read(); // удалить '\n' из буфера
Serial.read(); //удалить '\r' из буфера
inbuf[avail] = '\0';
char inputFileName[avail];
strcpy(inputFileName, inbuf);
confirmInputFileName:
Serial.print(F("Select file '"));
Serial.print(inputFileName);
Serial.println(F("'? Y/N"));
while (!Serial.available()); // ждем, пока серийный номер станет доступен
delay(100); //ждем получения всех символов
avail = Serial.available() - 2;
if (avail > 1) {
Serial.println(F("Enter 1 character"));
while (Serial.available()) { //очистить последовательный буфер
Serial.read();
}
goto confirmInputFileName;
}
char confirm = Serial.read();
Serial.read();
Serial.read();
switch (confirm) {
case 'Y': break;
case 'y': break;
case 'N': goto enterInputFileName; break;
case 'n': goto enterInputFileName; break;
default: Serial.println(F("Enter Y/N")); goto confirmInputFileName; break;
}
//до сих пор работает
Serial.println(SD.exists(inputFileName));
SD.remove(outputFileName);
outputFile = SD.open(outputFileName, FILE_WRITE);
outputFile.close();
//прочитать исходный код и записать в выходной файл
sourceFile = SD.open(inputFileName);
timeLast = micros();
if (sourceFile) {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
Serial.println(F("Copying"));
while (sourceFile.available()) {
//сделать размер буфера равным 50% от свободной оперативной памяти или количеству оставшихся байтов, если меньше
bufSize = min((freeRam() * 0.5 ), sourceFile.available());
byte data[bufSize];
sourceFile.readBytes(data, bufSize);
lastPos = sourceFile.position();
sourceFile.close();
outputFile = SD.open(outputFileName, O_APPEND | O_WRITE);
outputFile.write(data, bufSize);
printStats();
outputFile.close();
sourceFile = SD.open(inputFileName);
sourceFile.seek(lastPos);
}
sourceFile.close();
outputFile.close();
Serial.println(F("Finished"));
unsigned int sec = millis() / 1000;
unsigned int mins = sec / 60;
sec -= mins * 60;
Serial.print(F("Time taken: "));
Serial.print(mins);
Serial.print(':');
Serial.print(sec);
Serial.print(F("Speed: "));
Serial.print((sourceFile.size() / 1000) / (millis() / 1000));
Serial.print(F(" KB/s"));
}
// если файл не открыт, вывести ошибку:
else {
Serial.print("error opening files");
SD.initErrorHalt();
}
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
void printStats() {
timeNow = micros();
uint32_t timeTaken = timeNow - timeLast;
float sent = sourceFile.position() / 1000.0;
float fileSize = sourceFile.size() / 1000.0;
float left = fileSize - sent;
float speed;
speed = 1000000UL / timeTaken * bufSize;
speed /= 1000;
unsigned int sec = millis() / 1000;
unsigned int mins = sec / 60;
sec -= mins * 60;
int estSec = (left / speed);
int estMin = estSec / 60;
estSec -= estMin * 60;
Serial.print(F("\tSent (KB): ")); Serial.print(sent);
Serial.print(F("\tLeft (KB): ")); Serial.print(left);
Serial.print(F("\tSize (KB): ")); Serial.print(fileSize);
Serial.print(F("\tTime: ")); Serial.print(mins); Serial.print(':'); Serial.print(sec);
Serial.print(F("\tSpeed (KB/sec): ")); Serial.print(speed);
Serial.print(F("\tFree: ")); Serial.print(freeRam() - bufSize);
Serial.print(F("\tBuf: ")); Serial.print(bufSize);
Serial.print(F("\tEST: ")); Serial.print(estMin); Serial.print(':'); Serial.print(estSec);
//todo исправить эту строку
//Serial.print(F("\tExists(I,O): ")); Serial.print(SD.exists(inputFileName)); Serial.print(SD.exists(outputFileName));
Serial.print('\n');
timeLast = micros();
}
@, 👍-1
3 ответа
Лучший ответ:
Вам необходимо отформатировать сообщение так, чтобы получатель знал, где заканчивается сообщение и начинается новое.
Затем на принимающей стороне вы заполняете буфер до тех пор, пока не будет получено полное сообщение, а затем обрабатываете сообщение.
Более продвинутая тактика — обрабатывать байты по мере их получения. Это требует построения конечного автомата, но означает, что вам не нужно хранить копию всего сообщения.
Недавно я беспокоился о том же, когда работал над проектом, в котором нужно было считывать последовательные данные (полученные через Bluetooth HC-05).
Мой цикл loop() выполняет большую часть работы для моего проекта (Никогда больше не вводите пароль (устройство с сенсорным экраном на базе Arduino @ CodeProject.com ), но чтение последовательных данных также является большой частью работы.
Я реализовал следующий код, и он работает буквально несколько недель без каких-либо проблем.
if (Serial1.available() > 0) {
incomingByte = Serial1.read();
while (incomingByte > 0){
if (incomingByte == 0x01){
Keyboard.press(KEY_LEFT_CTRL);
Keyboard.press(KEY_LEFT_ALT);
Keyboard.write(KEY_DELETE);
Keyboard.release(KEY_LEFT_ALT);
Keyboard.release(KEY_LEFT_CTRL);
}
else{
Keyboard.write(incomingByte);
}
incomingByte = Serial1.read();
}
}
Вы можете видеть, что он считывает байты, пока они доступны, что может привести к мысли о его блокировке, но он справляется с этим очень хорошо.
Довольно много работы
Он выполняет довольно большую работу, поскольку захватывает все байты, поступающие через Bluetooth (а затем печатает их на подключенном компьютере — это долгая история, подробнее читайте в статье).
Довольно несколько байт
Он также считывает не менее 64 байтов (длина пароля + специальные байты управляющих символов), но справляется с этим довольно хорошо.
после добавления исходного кода к вопросу:
Вы неправильно используете функцию readBytes. Если вы установите параметр размера равным количеству доступных байтов, она будет считывать количество доступных байтов.
выделите буфер и установите второй параметр как размер буфера. readBytes попытается заполнить буфер, ожидая максимум одну секунду для следующего символа, чего достаточно для чтения всей строки, отправленной из Serial Monitor.
if (Serial.available()) {
char buff[50];
int length = Serial.readBytes(buff, sizeof(buff) - 1);
buff[length] = 0; // завершающий ноль c-строки
Serial.println(buff);
}
Примечание: readBytes будет ждать одну секунду после получения последнего символа. Лучше использовать readBytesUntil с ожидаемым терминатором. Или вы можете установить меньшее время ожидания для Serial с помощью Serial.setTimeout(200)
- Как разделить входящую строку?
- Какова максимальная длина провода для последовательной связи между двумя Arduino?
- Последовательная связь между двумя Arduino (запрос и получение)
- Не нашел датчик отпечатков пальцев :( Arduino Mega 2560 Adafruit Fingerprint Sensor
- Модуль SIM808: команда определения местоположения GSM (AT+CIPGSMLOC=1,1) дает неверное значение после выполнения команды отправки сообщения (AT+CMGS=+91xxxxxxxx)
- Как правильно получить MIDI с Arduino, с 6n138?
- Bluetooth-модуль HC-05 не принимает AT-команды
- Сбой Arduino во время последовательной печати без очевидной причины