Как сравнить строку

Как сравнить строку, поступающую из последовательного монитора, с некоторым предопределенным текстом, хранящимся в локальной переменной? Если я скажу:

int led = 2;
String a = " abcds";

void setup(){
  Serial.begin(9600);
}

void loop() {
  String b = Serial.read();
  Serial.println(b);

  if (b != a) {
    digitalWrite(2,LOW);
  }
  else
  {
    digitalWrite(2,HIGH);
  }
}

просто в качестве примера, этот код не будет компилироваться, потому что на последовательном я получаю байты и хочу сравнить со строкой. Так что мой вопрос... как это сделать?

, 👍3

Обсуждение

Для какой платы arduino? Большинство из нас пытаются избежать класса String для arduino uno. Как только символ доступен, вы добавляете его в буфер или в строку. Иногда данные из последовательного порта закрываются с помощью подачи строки, тогда вы можете обрабатывать текст в буфере или в строке при чтении подачи строки., @Jot


5 ответов


Лучший ответ:

6

версия с использованием строки (не рекомендуется, но это упрощает понимание следующей версии C-строки)

#define LED 2
const char* a = "abcd";

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
}

void loop() {
  if (Serial.available()) {
    String s = Serial.readStringUntil('\n');
    s.trim();
    if (s == a) {
      digitalWrite(LED, HIGH);
    } else {
      digitalWrite(LED, LOW);
    }
  }
}

версия со строкой C:

#define LED 2
const char* a = "abcd";
char buffer[32];

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
}

void loop() {
  if (Serial.available()) {
    size_t l = Serial.readBytesUntil('\n', buffer, sizeof(buffer - 1));
    if (buffer[l - 1] == '\r') {
      l--;
    }
    buffer[l] = 0; // the terminating zero
    Serial.println(buffer);
    if (strcmp(buffer, a) == 0) {
      digitalWrite(LED, HIGH);
    } else {
      digitalWrite(LED, LOW);
    }
  }
}
,

Как я уже прокомментировал сообщение VE7JRO, "Stream::readBytesUntil ()" будет ждать завершающего символа, пока он не получит его или не истечет время ожидания, что может привести к длительным задержкам, во время которых скетч не отвечает. Лучшее решение-читать только то, что доступно, и обрабатывать буфер при чтении LF. C. f. сообщение в блоге [Чтение последовательного на Arduino](https://majenko.co.uk/blog/reading-serial-arduino), Майенко, для лучшего решения., @Edgar Bonet

Версия "Строка" работает отлично, но я не могу заставить версию "C-строка" работать. Для меня последовательный монитор показывает "abcd", записанный в 2 строки: строка 1 печатает "ab", строка 2 печатает "cd". Возможно, это старая версия IDE, которую я использую (1.0.6.2). Мне нравится, что вы предоставили 2 примера скетчей, чтобы операционная система могла видеть разницу в размере компиляции: "Строка" 4364 байта ПРОТИВ " C-строки` 2746 байт., @VE7JRO

@EdgarBonet, он будет ждать только в том случае, если завершающий символ отсутствует. время ожидания может быть установлено, например, на 10 миллисекунд с помощью параметра setTimeout. во многих случаях лучше дождаться потока, так как продолжайте выполнять другие действия в цикле, а затем вернитесь, чтобы прочитать переполненный буфер, @Juraj

Если ваш "цикл ()" занимает так много времени, что последовательный буфер переполняется, то вы, вероятно, сделали что-то очень неправильное. Вы можете позволить себе ждать получения всего сообщения только в том случае, если у вас нет кода, чувствительного ко времени, вне контекста прерывания. Stream::readBytesUntil() и delay() работают в одной команде: они могут помочь вам написать более простой код, если вы можете позволить себе не отвлекать процессор, ничего не делая, но их использование в целом не является хорошей привычкой программирования., @Edgar Bonet

@EdgarBonet, если промежутки между полученными байтами малы в микросекундах, но функция available() иногда возвращает 0, каков хороший способ прочитать команду из потока? Скетч ничего не должен делать, пока не будет получена эта команда. Другой случай: при создании сетей во внешних модулях и с библиотеками Arduino у вас не может быть цикла "в реальном времени". это может занять несколько секунд, пока веб-сервер не отправит ответ, но затем байты поступают быстро и всегда превышают размер последовательного буфера., @Juraj


1

Если вы выполните поиск в Google по "Строке Arduino", вы должны найти ссылку на класс в классе String. https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/

В нем есть функция compareTo (), которая должна делать то, что вам нужно.

,

1

В C есть функция strcmp (), которая используется для сравнения двух строк. Он вернет ноль, если две строки равны ненулевым, когда нет.

,

Я начал предлагать то же самое, а затем заметил, что операция использует строковые объекты Arduino, а не строки C., @Duncan C


0

Вот тестовый скетч, в котором используется массив символов ВМЕСТО объекта String. Пожалуйста, не забудьте настроить последовательный монитор на отправку только новой строки.

char inputBuffer[16];
char compareToThisString[] = "test string";

void setup(){
  Serial.begin(9600);
}

void loop(){

  if(Serial.available() > 0){

    Serial.readBytesUntil('\n', inputBuffer, 16);

    if(strcmp(compareToThisString, inputBuffer) == 0){
      Serial.println("Matches");
    }
    else{
      Serial.println("No Match");
    }
  }
  memset(inputBuffer, 0, sizeof(inputBuffer));
}

Как упоминает Эгар Бонет в своих комментариях, до завершения Serial.readBytesUntil () существует задержка (до) одной секунды. Это не относится к скетчу, который я написал, потому что функция завершается, как только она получает символ \n. Serial.readBytesUntil () - это код блокировки, но это другой вопрос, который может быть или не быть проблемой для вас, в зависимости от того, что вы создаете и сколько данных отправляете. Чтобы сократить время ожидания, существует функция Serial.setTimeout (), которую можно установить на все, что вы хотите, но она вступает в игру только в том случае, если вы не отправляете символ \n.

,

Я использую "memset ()" для "обнуления" входного буфера после каждого использования. Без memset(), если вы введете правильную строку, она совпадет. Если затем вы введете только первые 4 буквы строки, они совпадут, что неверно. Использование "memset ()" обходится только в дополнительные 10 байтов размера компиляции., @VE7JRO

Функция Stream::readBytesUntil () будет ждать завершающего символа до тех пор, пока он не получит его или не истечет время ожидания, что может привести к длительным задержкам, в течение которых скетч не отвечает. Лучшее решение-читать только то, что доступно, и обрабатывать буфер при чтении LF. C. f. сообщение в блоге [Чтение последовательного на Arduino](https://majenko.co.uk/blog/reading-serial-arduino), Майенко, для лучшего решения., @Edgar Bonet

"прочитайте максимум 15, чтобы в массиве остался один ноль". Я только что попробовал, и это не работает :( Замена memset() на это: InputBuffer[0] = '\0'; тоже не работает., @VE7JRO

readBytesUntil возвращает количество прочитанных байтов. это положение, в котором должен находиться 0, @Juraj


0

Вот код цикла() из примера SafeString_ReadCmdsTimed.ino в библиотеке SafeString, доступной в диспетчере библиотек Arduino. Он не блокируется, то есть не вызывает задержек.

Существует обширный учебник и примеры, доступные для SafeStrings. SafeStrings имеет встроенную проверку и отладку ошибок. SafeStrings обеспечивает функциональность строк без проблем фрагментации памяти, связанных с динамическим распределением памяти.

Если вы читаете из telnet, в SafeStrings также есть метод processbackspaces() для обработки исправлений ввода терминала. Разделители-это все, что вам нужно. В примере рассматриваются конечные строки Windows, Unix и Mac.

char delimiters[] = " .,\r\n"; // space dot comma CR NL are cmd delimiters

void loop() {
  if (input.read(Serial)) {  // read from Serial, returns true if at least one character was added to SafeString input
    input.debug("after read => ");
    timeout.start(TIMEOUT_MS); // restart a 0.1sec timer every time something is read
  }

  if (input.nextToken(token, delimiters)) { // process at most one token per loop does not return tokens longer than input.capacity()
    token.debug("after nextToken => ");

    if (token == startCmdStr) {
      running = true;  Serial.print(F("start at ")); Serial.println(loopCounter);

    } else if (token == stopCmdStr) {
      running = false; Serial.print(F("stop at ")); Serial.println(loopCounter);

    } else if (token == resetCmdStr) {
      loopCounter = 0; Serial.print(F("reset Counter:")); Serial.println(loopCounter);

    }// else  // not a valid cmd ignore
  }
  if (timeout.justFinished()) { // nothing received for 0.1secs, terminated last chars so token will be processed.
    input += delimiters[0]; // any delimiter will do
    SafeString::Output.print(F("Input timed out"));
  }
  // rest of code here is executed while the user typing in commands
  if (running) {
    loopCounter++;
    if ((loopCounter % 100000) == 0) {
      Serial.print(F("Counter:")); Serial.println(loopCounter);
    }
  }
}
,

Пожалуйста, сообщите о своей принадлежности, вы, по-видимому, являетесь автором сайта, на который вы ссылались несколько раз., @Mast

Обязательно добавлю "мое" в будущие посты. На моем сайте есть ряд других бесплатных библиотек/учебных пособий, но эта конкретная ссылка относится к подробному учебнику по безопасному тестированию.который я выдвигаю в качестве "безопасной" замены строк Arduino. Ознакомьтесь с руководством по всем причинам, по которым вы должны использовать SafeString вместо строк Arduino, @drmpf