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

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Добрый день всем! Сразу скажу, что я не С++, а Delphi прогер, но жизнь заставляет изучать С++ и начал я сразу с языка для Ардуино... Открыл на днях коробочку с платкой и написал небольшой скетч. Суть в том, чтобы АрдуинаМега приняла данные с USB порта, а потом разобрала что нужно ей сделать. ВРоде все просто звучит, получил строковый код 1 - включил порт, получил 0 - отключил порт, но не могу заставить ее сравить строки )))

мой пример:

String inputString = "";   
int ledpin=13; 
boolean stringComplete = false;

void setup() {
Serial.begin(9600);
pinMode(ledpin,OUTPUT); // устанавливаем порт как выход
String inputString = "";
}

void loop() {
 
  serialEvent();

if (stringComplete)  // этот момент срабатывает четко... проверено.
{
Serial.println(inputString); // для моего контроля - смотрю что получила ардуино

if (inputString.substring(1)=="1") // вот тут загвоздка... не хочет никак переходить сюда... уже и просто  inputString=="1" сравнивал, и никак
 {
   Serial.println("Led is ON");
   digitalWrite(ledpin,HIGH);   
 }

 inputString="";
 stringComplete = false;
}

}

void serialEvent() {
  while (Serial.available()) {  // пока есть данные - делаем
    char inChar = (char)Serial.read(); // читаем порт
    inputString += inChar; // собираем в глобальную переменную полученные данные
    if (inChar == '\n') { // если получили символ #10, то считаем что закончили прием
       stringComplete = true;
    }
  }
}

На сколько мне позволяют знания Delphi применить к С++ я уже пробовал разное... чую, что тут все просто должно быть... а не выходит..

Клапауций 321
Offline
Зарегистрирован: 17.12.2015

вот тебе рабочий код - адаптируй с DigiUSB на Serial


#include <DigiUSB.h>

void setup() {

pinMode(14, OUTPUT); // LED_01
digitalWrite(14, 1);
pinMode(15, OUTPUT); // LED_02
digitalWrite(15, 1);

DigiUSB.begin();

}

void loop() {

if (DigiUSB.available()) { // в USB что-то есть.

char a = DigiUSB.read(); // считать символ из USB в переменную.
static String b = ""; // объявление переменной строки.

if (a != '\b') {b = b + a;               } // дописать символ в конец строки, если это не символ клавиши Backspace.
if (a == '\b') {b.remove(b.length() - 1);} // удалить последний символ строки, если получен символ клавиши Backspace.
if (a == '\n') {                           // если получен символ клавиши Enter.

// эхо строки. (необязательная часть кода, используется для отладки)
if (DigiUSB.tx_remaining() > (b.length() + 1)) { // проверка места в буфере USB для строки длиной + 1 символ.
DigiUSB.print(b); // печать в DigiUSB собранной строки.
}

// что-то делаем, после получения символа клавиши Enter.
if (b == "LED_01 on\n") {digitalWrite(14, 0);} // зажечь светодиод, если принята строка ххх\n.
if (b == "LED_01 of\n") {digitalWrite(14, 1);} // погасить светодиод, если принята строка ххх\n.
if (b == "LED_02 on\n") {digitalWrite(15, 0);} // зажечь светодиод, если принята строка ххх\n.
if (b == "LED_02 of\n") {digitalWrite(15, 1);} // погасить светодиод, если принята строка ххх\n.

b = ""; // очистка строки.

}

}

DigiUSB.delay(1);

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, сравнить-то их несложно, только зачем? Вам надо числа вводить? Так и вводите Serial.parseInt() - и введёт и к инту преобразует. Нафига Вам строки вообще?

Valera19701
Valera19701 аватар
Онлайн
Зарегистрирован: 18.10.2015

Dr_grizzly пишет:

Добрый день всем! Сразу скажу, что я не С++, а Delphi прогер, но жизнь заставляет изучать С++ и начал я сразу с языка для Ардуино... Открыл на днях коробочку с платкой и написал небольшой скетч. Суть в том, чтобы АрдуинаМега приняла данные с USB порта, а потом разобрала что нужно ей сделать. ВРоде все просто звучит, получил строковый код 1 - включил порт, получил 0 - отключил порт, но не могу заставить ее сравить строки )))

На сколько мне позволяют знания Delphi применить к С++ я уже пробовал разное... чую, что тут все просто должно быть... а не выходит..

попробуйте так

http://arduino.ru/Reference/StringCompareTo

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

ЕвгенийП пишет:

Ну, сравнить-то их несложно, только зачем? Вам надо числа вводить? Так и вводите Serial.parseInt() - и введёт и к инту преобразует. Нафига Вам строки вообще?

Я чуток забегаю вперед, мне надо в дальнейшем посылать команду в виде кода функции и ее параметра в ардуино. Например 1х100  где 1 - это код фукции, а 100 ее параметр. К примеру задержка мерцания светодиода. Поэтому в чистом виде цифровой код сюда думаю не подойдет

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

if (b == "LED_01 of\n"

Вот в чем похоже собака зарыта, \n ведь я не учел в конце строки.... А за код большое спасибо! То что надо для разбора данных полученных в порт по кускам...

Клапауций 321
Offline
Зарегистрирован: 17.12.2015

Dr_grizzly пишет:

if (b == "LED_01 on\n")  - вот похоже в чем зарыта была собака... \n при сравнении строк не учел... А за пример большое спасибо! Удобно полученную строку разбивать по кускам

там не по кускам - строка собирается из отправленных символов, после получения \n (нажатия Enter) что-то делается - это не обязательно: что-то может исполнится и просто при получении LED_01 on

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Ура господа!!! У меня все заработало как надо! ))) Вот мой рабочий пример:

int ledpin=13; // глобальная переменная со значением 13
boolean mig=false;
String inputString = "";        // Строковая переменная
String delfun = "";
boolean stringComplete = false;  // Флажок на окончание приема данных
int fdelay =500; // переменная для задержки мерцания

void setup() {
Serial.begin(9600);
pinMode(ledpin,OUTPUT); // устанавливаем порт как выход
String inputString = "";
String delfun = "";
}

void loop() {
    serialEvent(); // переходим в процедуру опроса порта

if (stringComplete) {  // если мы получили данные

Serial.println("Command: " + inputString); // для проверки того, что ардуино получил
Serial.println("Function: " + delfun);

if (inputString=="1")
{
  Serial.println("Led is ON");
  digitalWrite(ledpin,HIGH);   
  mig=false;
}

if (inputString=="0")
{
  Serial.println("Led is OFF");
  digitalWrite(ledpin,LOW);   
  mig=false;
}

if (inputString=="2")
{
  Serial.println("Led is Flash");
  mig=true;
}

if (inputString=="clr\n") 
{
  Serial.flush();
  Serial.println("Port is clear");
}
 delfun="";
 inputString="";
 stringComplete = false;
 fdelint=0;
}

if (mig==true)
{
  digitalWrite(ledpin,HIGH); 
  delay(fdelay);
  digitalWrite(ledpin,LOW);   
  delay(fdelay);
}

}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read(); // получаем данные с порта
 
     inputString += inChar;  // собираем всю строку
    if (inChar == '\n')  // если наткнулись на перевод коретки 
    {
      for (int i=1; i<=inputString.length()-1; i++ ) // собираем строку после первого символа, т.е читаем значение переданного параметра
      {
      delfun = delfun + inputString.charAt(i); // собираем наш полученный параметр
      }
      if (inputString != "clr\n") // исключение команды очистки порта
      {
      inputString=inputString.charAt(0); // берем наш первый символ, который определяет функцию
      fdelay = atoi(delfun.c_str());  // преобразуем наш параметр в число
      }
      stringComplete = true;
    }
  }
}

 

Спасибо Вам большое!

Pacient
Offline
Зарегистрирован: 21.09.2017

Спасибо за пример, но в моём случае не работает.

Задача принять строку по UART и сравнить с константой.

Как и вы использовал модифицированный пример SerialEvent из https://www.arduino.cc/en/Tutorial/SerialEvent

String inputString = "";         // a String to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {
  Serial.begin(19200);
  inputString.reserve(200);
}

void loop() {
  if (stringComplete) {
    Serial.println(inputString);
    if (inputString.equals("Hello")) {
      Serial.println("WIN1!");
    }
    if (inputString == ("Hello")) {
      Serial.println("WIN2!");
    }
    inputString = "";
    stringComplete = false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    if (inChar != '\n') {
      inputString += inChar;
    }
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

 

 
WIN в ответ на Hello не получаю.
И ваш пример подредактировал - аналогично:
String inputString = "";        // Строковая переменная
String delfun = "";
boolean stringComplete = false;  // Флажок на окончание приема данных


void setup() {
Serial.begin(19200);
String inputString = "";
String delfun = "";
}

void loop() {
    serialEvent(); // переходим в процедуру опроса порта

    if (stringComplete) {  // если мы получили данные

    Serial.println("Input: " + delfun); // для проверки того, что ардуино получил
    if (delfun=="Hello")
       {
        Serial.println("WIN");
        }
    if (inputString=="clr\n") 
    {
     Serial.flush();
     Serial.println("Port is clear");
    }
    delfun="";
    inputString="";
    stringComplete = false;
    }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read(); // получаем данные с порта
 
     inputString += inChar;  // собираем всю строку
    if (inChar == '\n')  // если наткнулись на перевод коретки 
    {
      for (int i=0; i<=inputString.length()-1; i++ ) // собираем строку 
        {
         delfun = delfun + inputString.charAt(i); // собираем наш полученный параметр
        }
      stringComplete = true;
    }
  }
}

 

Прошу помощи в решении этой простой для вас задачи.

b707
Offline
Зарегистрирован: 26.05.2017

В первом случае все вроде верно, только скобки вокруг сравниваемой строки (строка 15) - я бы убрал. Не знаю, мешают они или нет, но так писать не принято.

Почему не выдается WIN? Думаю. в конце строки еще есть спецсимволы. зависящие от режима терминала - а вы их не учитываете

Pacient
Offline
Зарегистрирован: 21.09.2017

Спасибо за ответ.

Я тоже подумал о спец. символах, но и это не сработало:

String inputString = "";         // a String to hold incoming data
boolean stringComplete = false;  // whether the string is complete

void setup() {
  Serial.begin(19200);
  inputString.reserve(200);
}

void loop() {
  if (stringComplete) {
    Serial.println(inputString);
    if (inputString.equals("Hello")) {
      Serial.println("WIN1!");
    }
    if (inputString == "Hello") {
      Serial.println("WIN2!");
    }
    if (inputString.substring(0,4) == "Hello") {
      Serial.println("WIN3!");
    }
    inputString = "";
    stringComplete = false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    if (inChar != '\n') {
      inputString += inChar;
    }
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

 

Pacient
Offline
Зарегистрирован: 21.09.2017

Код Клапауций 321 тоже не работает(

Какая-то причина для опытных программистов ясная, а мне не понятная.

Почему это не работает:

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

void loop() {

    if (Serial.available()) { // в Serial что-то есть.

        char a = (char)Serial.read(); // считать символ из UART в переменную.
        static String b = ""; // объявление переменной строки.

        if (a != '\b') {b = b + a;} // дописать символ в конец строки, если это не символ клавиши Backspace.
        if (a == '\b') { b.remove(b.length() - 1);} // удалить последний символ строки, если получен символ клавиши Backspace.
        if (a == '\n') {                           // если получен символ клавиши Enter.
            // эхо строки. (необязательная часть кода, используется для отладки)
            if (Serial.availableForWrite() > (b.length() + 1)) { // проверка места в буфере Serial для строки длиной + 1 символ.
                Serial.print(b); // печать в DigiUSB собранной строки.
            }
            // что-то делаем, после получения символа клавиши Enter.
            if (b == "Hello\n") {Serial.print("Klapauciy 321 WIN!");} // если принята строка ххх\n.
            b = ""; // очистка строки.
        }
    }
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Pacient, напечатать посимвольно получившуюся строку b религия не позволила?

Хрустальный Шар подсказывает, что если Вы в 20-ой строке замените "Hello\n" на "Hello\r\n", то Вам будет много счастья. Но так нельзя работать. При любых непонятках, надо сначала вызывать скорую, а уж потом выкладывать в инстаграмм печатать переменные и смотреть на них, а только потом, если непонятки остались, постить вопросы.

Кстати, на обычных указателях char * эта задача решается существенно короче по строкам кода и неизмеримо эффективнее по времени и памяти.

b707
Offline
Зарегистрирован: 26.05.2017

Pacient пишет:

Спасибо за ответ.

Я тоже подумал о спец. символах, но и это не сработало:


    if (inputString.substring(0,4) == "Hello") {
      Serial.println("WIN3!");
   

 

похоже, кто-то просто не умеет считать. Сколько букв в слове  "Hello"? Четыре? :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

В посте №11 уже нет этой четвёрки, но не помогло :)

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

В посте №11 уже нет этой четвёрки, но не помогло :)

 

Зато код из #10 заработал бы :) и автор ушел бы довольный....

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

ЕвгенийП пишет:

Хрустальный Шар подсказывает, что если Вы в 20-ой строке замените "Hello\n" на "Hello\r\n", то Вам будет много счастья. 

откуда у него там \r берётся, если он его не отсылает по сериалу?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Клапауций 112 пишет:

откуда у него там \r берётся, если он его не отсылает по сериалу?

Там в окне монитора внизу можно установить что отсылать: ничего, \n или \r\n. Что там установлено у ТС одному Богу ведомо, но раз не работает, то скорее всего проблема в том, что \r\n стоит, а он голого \n ожидает.

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Первый код, из сообщения номер 8 работает и печатает и Вин1 и Вин2.

Кончайте бредить!

1. в "Мониторе порта" нужно поставить КОНЕЦ СТРОКИ - NL (это в нижней строке справа). Проверка-то идет на '\n'.

2. на arduino.cc АГЛИЦКИМ _ПО_БЕЛОМУ написано, что это самый сериа-евент - работает только на УНО и НАНО (на меге - с номерами).

Так вот на Нанке - код от вопрошающего запускается и работает сразу и без размышлений.

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

ЕвгенийП пишет:

Там в окне монитора внизу можно установить что отсылать: ничего, \n или \r\n. Что там установлено у ТС одному Богу ведомо, но раз не работает, то скорее всего проблема в том, что \r\n стоит, а он голого \n ожидает.

нда. кароче, всем потерпевшим от сериал монитора - код #1 подразумевает, что по сериалу летят символы введённые клавой, а не отправленные каким-то сериал-понитором и прочей шнягой калечащей инфу.

 

Pacient
Offline
Зарегистрирован: 21.09.2017

wdrakula пишет:

Первый код, из сообщения номер 8 работает и печатает и Вин1 и Вин2.

Кончайте бредить!

1. в "Мониторе порта" нужно поставить КОНЕЦ СТРОКИ - NL (это в нижней строке справа). Проверка-то идет на '\n'.

2. на arduino.cc АГЛИЦКИМ _ПО_БЕЛОМУ написано, что это самый сериа-евент - работает только на УНО и НАНО (на меге - с номерами).

Так вот на Нанке - код от вопрошающего запускается и работает сразу и без размышлений.

Всё верно. Работает без CR (возврат каретки).

Вопрос закрыт, спасибо!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, слава Богу! Человеческий разум в очередной раз восторжествовал! :)

des808
Offline
Зарегистрирован: 26.01.2019
 
if (Serial.available()) {
    char in = Serial.read();// считать символ из serial в переменную.
    static String b = ""; // объявление переменной строки.
    b = b + in;            // дописать символ в конец строки

    if (b == "Led1 On Led2 Off") {
        Led1Enable();
            b = "";
       }
    if (b == "Led2 On Led1 Off") {
        Led2Enable(); 
            b = "";
       } 
  }

 

 
Drago28
Offline
Зарегистрирован: 16.05.2019

Друзья! я кажется нашел решение! Представляю на Ваш суд:

String inputString = "";
boolean stringComplete = false;


void setup() {
Serial.begin(9600);
String inputString = "";
}

void loop() {

while (Serial.available()) {  // пока есть данные - делаем
  char inChar = (char)Serial.read(); // читаем порт
  if (inChar == '\n')  // если получили символ #10, то считаем что закончили прием
  {
    inChar = 0;
    stringComplete = true;
  }
  inputString += inChar; // собираем в глобальную переменную полученные данные

}
if (stringComplete){
Serial.println(inputString);
if(inputString == "hello"){
  Serial.println("Good Work!");
}
inputString="";
}
stringComplete = false;
}

Это работает если в сериал-мониторе в правом нижнем углу выставлено NL(Новая строка)!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Drago28 пишет:

Друзья! я кажется нашел решение! Представляю на Ваш суд:

Это что за решение? Какой задачи? В смысле, что делать-то хотели?

sadman41
Offline
Зарегистрирован: 19.10.2016

Думаю, что это ответ на главный вопрос жизни, вселенной и всего такого.

Drago28
Offline
Зарегистрирован: 16.05.2019

у меня была таже проблема и задача, что и у автора - на UART  приходят команды, в мооем случае  типа: Е02,  Y1, AE, HS0 и т.д. И все не работало как нужно, выше все описано. У меня не работало сравнение строк, и Good Work никак не приходило в ответ, а все из-за гребаного \n  в конце любой комбинации символов переданных по UART. Под Good Work естественно подразумевается выполнение полезной работы.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Drago28 пишет:

У меня не работало сравнение строк, и Good Work никак не приходило в ответ, а все из-за гребаного \n  в конце 

Понятно, т.е. на самом деле, у Вас правильно работало сравнение строк, когда они были не равны, программа и говорила, что они не равны. А понять почему они не равны и сделать их равными Вы не могли. ну, так и говорите.

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

sadman41 пишет:

Думаю, что это ответ на главный вопрос жизни, вселенной и всего такого.

Ты забыл? Там "42"! ;)))

Slonekb
Offline
Зарегистрирован: 01.05.2020

Добрый день!
Уже который день пытаюсь подружить ардуино, датчик давления и реле через последовательный порт. Давление воды с датчика приходит без проблем и показывается на мониторе порта. А вот управлять нагрузкой (реле для закрывания / открывания линии воды) пока получается с трудом. Единственное, чего я смог пока добиться - управление нагрузкой (светодиодом, а впоследствии транзистором и реле) через команды 0 и 1. Т. е. в случае 0 13 диод не горит, а при 1 диод загорается. По моей задумке, в проекте реле будет не одно, а несколько. И как ими управлять? Я думал сделать на открытие / закрытие каждого клапана команды от 0 до 13. Но вот незадача - ардуино через порт принимает число 10 не как десять, а как один ноль. И поэтому сначала зажигает диод, а по прошествии времени задержки его тушит. Если послать на порт 10101010, то микросхема мигает соответствующее количество раз. Я думал, что было бы идеально высылать команду LED1ON для зажигания диода №1 и команду типа LED4OFF для гашения диода 4. Но как ни бился - не получается. Помогите, пожалуйста!


/*
  Программа для прошивки ардуино под снятие данных с датчика давления и управлением реле
*/

// y = k * x + b
// Давление (Па) = k * Напряжение (В) + b

const float  b = 0.586, k = 0.000009;
String val;
float U, P;

void setup()
{
  Serial.begin(115200);        // open serial port, set the baud rate to 9600 bps
  Serial.println("/** Измерение давления датчиком **/");
  pinMode (13,OUTPUT);

}
void loop()
{
  //Connect sensor to Analog 0
  U = analogRead(0) * 5.00 / 1024;     // Считывание напряжение (0-5 В) через аналоговый вход
  P = 106939 * U - 61062 + 492;      // Расчёт избыточного давления в Па

  Serial.print(" Напряжение:");
  Serial.print(U, 3);
  Serial.println(" В");

  Serial.print(" Избыточное давление:");
  Serial.print(P, 0);
  Serial.println(" Па");
  Serial.println();

  val=Serial.readString();
  if(val=='1on')
  {digitalWrite(13,HIGH);}
  else
    if (val=='1off') 
    {digitalWrite (13,LOW);}
    else (val==val);
 
  delay(500);
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

'1on' - это не строка, строка - это "1on".

Slonekb
Offline
Зарегистрирован: 01.05.2020

Спасибо! Добавил ещё символ Enter и всё заработало!


/*
  Программа для прошивки ардуино под снятие данных с датчика давления
*/

// y = k * x + b
// Давление (Па) = k * Напряжение (В) + b

const float  b = 0.586, k = 0.000009;
String val;
float U, P;

void setup()
{
  Serial.begin(9600);        // open serial port, set the baud rate to 9600 bps
  Serial.println("/** Измерение давления датчиком **/");
  pinMode (13,OUTPUT);

}
void loop()
{
  //Connect sensor to Analog 0
  U = analogRead(0) * 5.00 / 1024;     // Считывание напряжение (0-5 В) через аналоговый вход
  P = 106939 * U - 61062 + 492;      // Расчёт избыточного давления в Па

  Serial.print(" Напряжение:");
  Serial.print(U, 3);
  Serial.println(" В");

  Serial.print(" Избыточное давление:");
  Serial.print(P, 0);
  Serial.println(" Па");
  Serial.println();

  val=Serial.readString();
  if(val=="1on\n")
  {digitalWrite(13,HIGH);}
  else
    if (val=="1off\n") 
    {digitalWrite (13,LOW);}
    else (val==val);