Как сравнить строку
Как сравнить строку, поступающую из последовательного монитора, с некоторым предопределенным текстом, хранящимся в локальной переменной? Если я скажу:
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);
}
}
просто в качестве примера, этот код не будет компилироваться, потому что на последовательном я получаю байты и хочу сравнить со строкой. Так что мой вопрос... как это сделать?
@Iulian Chirvasa, 👍3
Обсуждение5 ответов
Лучший ответ:
версия с использованием строки (не рекомендуется, но это упрощает понимание следующей версии 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
Если вы выполните поиск в Google по "Строке Arduino", вы должны найти ссылку на класс в классе String. https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
В нем есть функция compareTo ()
, которая должна делать то, что вам нужно.
В C есть функция strcmp (), которая используется для сравнения двух строк. Он вернет ноль, если две строки равны ненулевым, когда нет.
Я начал предлагать то же самое, а затем заметил, что операция использует строковые объекты Arduino, а не строки C., @Duncan C
Вот тестовый скетч, в котором используется массив символов
ВМЕСТО объекта 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
Вот код цикла() из примера 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
- Использование строки вместо строки C, еще одна попытка затронуть загруженную проблему
- Как реализовать обратное перечисление?
- Смешанная структура с int и string
- Не удается скомпилировать макрос F() с помощью R "string"
- Как отправить данные ads1115 через spi на master arduino
- Добавить char с интервалами в строку
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
Для какой платы arduino? Большинство из нас пытаются избежать класса String для arduino uno. Как только символ доступен, вы добавляете его в буфер или в строку. Иногда данные из последовательного порта закрываются с помощью подачи строки, тогда вы можете обрабатывать текст в буфере или в строке при чтении подачи строки., @Jot