Как собрать string от Com порта?

2ball
Offline
Зарегистрирован: 15.04.2012

 Всем доброго!
 Вопрос таков: Delphi через Com порт отсылает PWideChar (в теории, да и на практике происходит это посимвольно). Как собрать слово в Arduino и считать его? Я понимаю, как это реализовать в Delphi, но как в Arduino что-то не догоняю...

Заранее спасибо за ответы

maksim
Offline
Зарегистрирован: 12.02.2012

Примерно как-то так:

while (Serial.available() > 0) {
  int inChar = Serial.read();
    inString += (char)inChar; 
  if (inChar == '\n') {
    Serial.print("String: ");
    Serial.println(inString);
    inString = ""; 
  }
}

 

mixail844
Offline
Зарегистрирован: 30.04.2012

если посимвольно,то удобно в конце оправки поставить какой то "флажок" окончания пердачи,например '\0'

а в ардуине прописать

char buffer[100];
int i;
for(i=0;i<100;i++)
{
 buffer[i]=Serial.Read();
 Serial.flush();
 if(buffer[i]=='\0')
  break;
}
 

как то так,это только пример.я так принимал данные с Rx  когда принимал данные посылаемые через bluetooth терминал с Andriod смартфона.

maksim
Offline
Зарегистрирован: 12.02.2012

В этом случае у вас из всей отправленной строки прочитается только первый символ, а все остальное потеряется. И зачем создавать какой-то свой буфер и при этом очищать аппаратный? 

mixail844
Offline
Зарегистрирован: 30.04.2012

потому что при связи через BT с андроид терминалом,я столкнулся с проблемой что принимаетья только первый символ бесконечное количество раз,а не вся строка.хотя это может только печатлся в IDE терминале первый символ.тем неменее мне такое решение помогло передавать с Андроид терминала строчки и расшифровывать их в команды на ардуине.

вот мое точное решение

 for(i=0;i<9;i++)
  {
    while(Serial.available()==0);
    val[i]=Serial.read();
    Serial.flush();
    if(val[i]=='\n'){val[i]=0;break;}
  }

в качестве флажка окончания используеться '\n' - то есть ASCII код Enter'a

без Serial.flush() тоже сработало бы?

maksim
Offline
Зарегистрирован: 12.02.2012

Это скорее всего какие-то особенности вашего ВТ-модуля или глюк. 

2ball
Offline
Зарегистрирован: 15.04.2012

Если я правильно понял inString += (char)inChar; равносильно inString := inString + inChar; ?
Вот только я засек объявление inChar, а inString отчего-то нет.

Судя по сайту, string объявляется через Char массив.

2maksim, спасибо, вечером попробую...

2mixail844 - разумеется посимвольно, и через аски, так надежнее. Флаги стоят уже, хоть они особо и не нужны. Наверняка есть какой-нибудь SizeOf(Serial.available()); По нему и засекать размер передаваймого потока, а дальше в цикл цифирь посылать.

З.Ы. - Тяжко после Паскаля на С переползать...


 

leshak
Offline
Зарегистрирован: 29.09.2011

2ball пишет:

Наверняка есть какой-нибудь SizeOf(Serial.available()); По нему и засекать размер передаваймого потока, а дальше в цикл цифирь посылать. 

Нет. И быть не может. Откуда этому гипотетеческому SizeOf знать сколько байт данных СОБИРАЕТСЯ послать передающий? Функций возвращающих значения из будущего - не существует. Так что при вычитывании потока есть три подхода:

  1. Вы всегда работаете с пакетами одинакоковй длинны. Например 100 байт. Передающий обязан всегда посылать 100 байт, а принимающий всегда вычитывает 100 байт (но тут встанет вопрос "синхронизации").
  2. Вы используете какой-то маркер "конца пакета" (символ \n, \0 и т.п.)
  3. Передающий, первыми байтами сообщает какая длинна будет у всего пакета данных. То есть вначале посылает длинну строки, а уж потом саму строку.

 

2ball
Offline
Зарегистрирован: 15.04.2012

 Среда Arduino не в состоянии прочесть буфер порта и узнать сколько данных готовы к приему?

step962
Offline
Зарегистрирован: 23.05.2011

 Что вы понимаете под средой Arduino?

Если IDE, то естественно не в состоянии.

Если исполняемую программу, то она способна определить количество ПРИНЯТЫХ данных (Serial.Available()), уже находящихся в приемном буфере UART/USART.

Сколько данных еще поступит ("сколько данных готовы к приему"), одной лишь передающей программе известно. И никакой другой супер-пупер-контроллер не в состоянии это предсказать.

О чем вам leshak и сказал.

2ball
Offline
Зарегистрирован: 15.04.2012

 мдас.... а память ограничена....

2ball
Offline
Зарегистрирован: 15.04.2012

maksim - не вышло. Даже через Serial Monitor выдает пустой результат. Переделал так:

while (Serial.available() > 0) {
       one_char = Serial.read();
       final_string += one_char;
  //int inChar = Serial.read();
    //inString += (char)inChar;
  //if (Serial.available() < 0) {
    Serial.print("String: ");
    Serial.println(final_string);
  //}
}

Теперь при отсылке Low мне Serial Monitor выписывает:

String: L
String: »
String: 2
String: ?
String: I

Первая проблема - декодинг отсылаемой команды.
Вторая проблема - программа не объединяет символы в строку

По прежнему требуется помощь. Заранее спасибо за ответы.

maksim
Offline
Зарегистрирован: 12.02.2012

Так естественно не вышло, для того что бы в сериал монитор вернулась собранная строка нужно что бы в конце отправляемой строки был символ '\n' - переход на новую строку, в сериал мониторе в правом нижнем углу вместо "No line ending" выбираете "Newline" и тогда все будет работать. Если хотите, то можете использовать какой-нибудь другой символ для определения конца сообщения.

2ball
Offline
Зарегистрирован: 15.04.2012

 Ну смотрите:

1) По прежнему ругается на inString. Помогло char объявление переменной в начале.
2) inString = ""; не пашет. Переписал на inString = 0;
3) Сменил метод отправки на Newline в Serial Monitor, в итоге на команду Low мне программа выдала вот что: 
String: <

????????

Я так понимаю из-за char пересылается последний символ... Но выдача все равно кривая... 

maksim
Offline
Зарегистрирован: 12.02.2012

Так обЪявите переменную inString как String, а не как char и все у вас получится.

String inString;

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

void loop() {
  while (Serial.available()) {
    char inChar = Serial.read();
    inString += inChar; 
    if (inChar == '\n') {
      Serial.print("String: ");
      Serial.println(inString);
      inString = ""; 
    }
  }
}

 Ну а если нужен именно char, то примерно как то так:

char inString[10];

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

void loop() {
  int i = 0;
  while (Serial.available()) {
    delay(1);
    inString[i] = Serial.read();
    if (inString[i] == '\n') {      
      Serial.print("String: ");
      Serial.println(inString);
      int i = 0;
      while(i < 10){
        inString[i] = '\0';
        i++; 
      }
    }
    i++;
  }
}

 

2ball
Offline
Зарегистрирован: 15.04.2012

 т.е. тут меня жестоко обманули и тип string таки объявляется через string?

leshak
Offline
Зарегистрирован: 29.09.2011

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

Есть string - обычные C-шный строки. Которые суть массив чаров с последним нулем, а есть String (с большой буквы). Который суть "объект", утилита-обертка упрощающий работу со строками. Как-бы такая маленькая "библиотека для строк".

2ball
Offline
Зарегистрирован: 15.04.2012

 ясно, в общем юзать можно - самое главное. Спасибо. Вечером попробую - отпишусь. А вообще, на мой взгляд, исходников по таким вещам остро не хватает. Допишу минималку, скину сюда, пускай пользуются люди.

Alexander
Offline
Зарегистрирован: 25.04.2010

 Каюсь, упустили, перевод делался к версии 0.18, где еще не было String как объект, а только string массив char. Вскорости допереводим.

2ball
Offline
Зарегистрирован: 15.04.2012

 Во, а то я чуть с ума не сошел)). Как так - нет строк)))

leshak
Offline
Зарегистрирован: 29.09.2011

Alexander пишет:

 Каюсь, упустили, перевод делался к версии 0.18, где еще не было String как объект, а только string массив char. Вскорости допереводим.

Если можно, то начните "доперевод" с раздела "Bitwise Operators". Регулярно на форуме всплывают вопросы, где нужно отослать к этому разделу, а приходится слать на.... оригинал :) Все-таки это одна из базовых и часто используемых "фичей языка".

 

CatWhoCode
Offline
Зарегистрирован: 15.02.2014

Ведь все очень просто - у Arduino есть класс замечательный класс Stream, с функцией readString(). Она есть в Ethernet и Serial библиотеках. Однако, почему-то в Serial вариации первый символ всегда игнорируется. И весь код получается таким:
 

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

void loop() {
  while(Serial.read() > 0) {
    String ttydata = Serial.readString(); // ttyData - информация с серийного порта
  }
}

 

frostegater
Offline
Зарегистрирован: 18.04.2015

Serial.read() сжирает первый символ

правильный код

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

void loop() {
  while(Serial.available()) {
    String ttydata = Serial.readString(); // ttyData - информация с серийного порта
  }
}

 

egorka39
Offline
Зарегистрирован: 16.08.2015

frostegater пишет:

Serial.read() сжирает первый символ

правильный код

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

void loop() {
  while(Serial.available()) {
    String ttydata = Serial.readString(); // ttyData - информация с серийного порта
  }
}

 

Код то правильный, но когда в порт приходит байт = 0, то происходит выход из цикла. Как быть в такой ситуации?

Спрашиваю потому что есть необходимость в устройстве которое получает инфу из программы. А единственный способ ее получить, это эмуляция принтера Epson TM-88. А там при инициализации 5 байтом приходит 0.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
String inString;
void setup() {
Serial.begin(9600);
}

void loop() {
while (Serial.available()) {
char inChar = Serial.read();
inString += inChar; 
if (inChar == '#') {
if (inString=="temp#"){
Serial.println("Temperatura");
}
else if (inString=="davl#"){
Serial.println("Davlenie");
}
else
{
Serial.println("Net komandy");
}
 inString = ""; 
}
}
}

 

Почему условия у меня срабатывают только один раз?

В порт отправляю temp#

в мониторе получаю

Temperatura
ещё раз отправляю temp#
в мониторе получаю
Net komandy
 

 

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

Irinka пишет:

Почему условия у меня срабатывают только один раз?

Потому что inString надо очищать вовремя - сразу после обработки команд "температура" и "давление"
xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

Предположу что в сериале остаются символ(ы) перевода строки, коретки которые ложаться в начало переменной inString . После принятия символа '#' надо подчистить сериал.

в 19 строке выведите значение inString, все станет понятно.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

b707 пишет:

Irinka пишет:

Почему условия у меня срабатывают только один раз?

Потому что inString надо очищать вовремя - сразу после обработки команд "температура" и "давление"

на что это повлияет если оно чистися в конце ?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

код так читается намного легче

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

void loop() {
  while (Serial.available()) {
    char inChar = Serial.read();
    inString += inChar;
    if (inChar == '#') {
      if (inString == "temp#") {
        Serial.println("Temperatura");
      }
      else if (inString == "davl#") {
        Serial.println("Davlenie");
      }
      else
      {
        Serial.println("Net komandy");
        Serial.println(inString);
      }
      inString = "";
    }
  }
}

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
Temperatura
Net komandy

temp#

Как убрать символ перевода строки?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015
String inString;
void setup() {
  Serial.begin(9600);
}

void loop() {
  while (Serial.available()) {
    char inChar = Serial.read();
    inString += inChar;
    if (inChar == '#') {
      if (inString == "temp#") {
        Serial.println("Temperatura");
      }
      else if (inString == "davl#") {
        Serial.println("Davlenie");
      }
      else
      {
        Serial.println("Net komandy");
      }
      inString = "";
      while (Serial.available()) Serial.read();
    }
  }
}

 

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

xDriver пишет:

b707 пишет:

Irinka пишет:

Почему условия у меня срабатывают только один раз?

Потому что inString надо очищать вовремя - сразу после обработки команд "температура" и "давление"

на что это повлияет если оно чистися в конце ?

прав. Сослепу показалось. что очистка inString происходит в последнем If

Согласен насчет символов перевода строки.

Irinka, искать команды во входящим потоке жесткой операцией сравнения (str == "temperature") - плохой метод. Один лишний символ в Сериале - и условие уже не работает. Правильнее - искать вхождение нужной строки функцией indexOf

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

xDriver пишет:

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

void loop() {
  while (Serial.available()) {
    char inChar = Serial.read();
    inString += inChar;
    if (inChar == '#') {
      if (inString == "temp#") {
        Serial.println("Temperatura");
      }
      else if (inString == "davl#") {
        Serial.println("Davlenie");
      }
      else
      {
        Serial.println("Net komandy");
      }
      inString = "";
      while (Serial.available()) Serial.read();
    }
  }
}

 

Temperatura
Net komandy
 
temp#
Net komandy
Всё так же символы остаются.
 

 

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

Irinka пишет:

Как убрать символ перевода строки?

 

его не надо убирать

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Irinka, искать команды во входящим потоке жесткой операцией сравнения (str == "temperature") - плохой метод. Один лишний символ в Сериале - и условие уже не работает. Правильнее - искать вхождение нужной строки функцией indexOf

Осваиваю потихоньку, всё интересно, всё хочу попробовать

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

xDriver пишет:

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

void loop() {
  while (Serial.available()) {
    char inChar = Serial.read();
    inString += inChar;
    if (inChar == '#') {
      if (inString == "temp#") {
        Serial.println("Temperatura");
      }
      else if (inString == "davl#") {
        Serial.println("Davlenie");
      }
      else
      {
        Serial.println("Net komandy");
      }
      inString = "";
      while (Serial.available()) Serial.read();
    }
  }
}

это неверно. Совершенно не факт, что к моменту выполнения строки 22 у васв сериале будут только символы перевода строки. Вы так нужные символы потрете.

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

пошел ардуину откапаю...

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

xDriver пишет:

пошел ардуину откапаю...

мне лень за ардуиной лезть - я и так скажу.

Алгоритм:

1. Читаем сериал посимвольно, прибавляем к строке Str

2. Если символ "#" - ищем в строке Str нужные команды методом Str.indexOf(). После обнуляем строку

3. Если символ == конец строки => обнуляем строку Str

Все, ничего специально чистить не надо.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
String inString;
void setup() {
  Serial.begin(9600);
}

void loop() {
  while (Serial.available()) {
    char inChar = Serial.read();
    inString += inChar;
    if (inChar == '#') {
  int te = inString.indexOf('temp');
  int da = inString.indexOf('davl'); 
   if (te>0) {
        Serial.println("Temperatura");
      }
      else if (da>0) {
        Serial.println("Davlenie");
      }
      else
      {
        Serial.println("Net komandy");
      }
    inString="";
    }
  }
}

Работает, НО:

Почему если отправляю t1e1m1p# получаю Temperatura,а не Net komandy

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

Irinka, все верно.

В строках 11 и 12 лучше искать "temp#"и  "davl#".

Чтобы понять, почему ищется не то - добавьте вывод значения inString в сериал при совпадении температуры. давления и "нет команд"

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

b707 пишет:

Irinka, все верно.

В строках 11 и 12 лучше искать "temp#"и  "davl#".

Чтобы понять, почему ищется не то - добавьте вывод значения inString в сериал при совпадении температуры. давления и "нет команд"

Если ищу "temp#"и  "davl#" то при вводе temp# или davl# одинаково получаю Temperatura

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

void loop() {
  while (Serial.available()) {
    char inChar = Serial.read();
    inString += inChar;
    if (inChar == '#') {

   if (inString.indexOf('temp#')>0) {
        Serial.println("Temperatura");
      }
      else if (inString.indexOf('davl#')>0) {
        Serial.println("Davlenie");
      }
      else
      {
        Serial.println("Net komandy");
      }
    inString="";
    }
  }
}

Как так?

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

кавычки нужны двойные !

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Упустила из виду, спасибо. Получилось, работает.

Разобралась как принимать/передавать в ардуино, теперь нужно разобраться с esp

Может тоже подскажите?

http://arduino.ru/forum/apparatnye-voprosy/podklyuchenie-hc-06-k-nodemcu

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

А меня удивляет другое, я чищу сериал, а 13/10 все равно цепляется в начало строки inString

igorlab
Offline
Зарегистрирован: 11.11.2015

Народ, привет! подскажите пожалуйстакак решить проблему - отправляю в порт строку 

ND#SA=0&SB=1&ST=0&SC=0&PS=0&TW=255&TA=271&HD=34&PHA=834&PHB=700&UF=0

далалее читаю ее из порта и парсю, так вот парсится нормально, а вот с отправкой проблема - отправляется только часть строки, вот что в мониторе после отправки строки:

ND#SA=0&SB=1&ST=0&SC=0&PS=0&TW=255&TA=271&HD=34&P
SA = 0
SB = 1
ST = 0
SC = 0
PS = 0
TW = 255
TA = 271
HD = 34
P = 0
 
 
String readfromport_st;
  while(Serial.available()) 
    {
       readfromport_st = Serial.readString(); // ttyData - информация с серийного порта
    }
    if (readfromport_st.startsWith("ND#")) 
    {
      char  str[50];
      readfromport_st.toCharArray(str,50);
      char* ptr = str;
      parseParams(ptr); // парсим
      delay(500);
    }
void parseParams(char* inputString){
  Serial.println(inputString);
  parsedParams=0; // пока ничего не напарсили
 char* buffer = strtok(inputString,"#"); // лучше так проверять/пропускать вопросилово
 
  if(buffer!=NULL){
    for(buffer=strtok(NULL,"&"); buffer!=NULL;     buffer=strtok(NULL,"&") ) 
    {
  String buffer1= String(buffer);
    //params[parsedParams].name= buffer1.substring(0,buffer1.indexOf('='));   
    //params[parsedParams].value=strtoint(buffer1.substring(buffer1.indexOf('=')+1));   
    //parsedParams++; // отмечаем сколько удалось распарсить
        Serial.print(buffer1.substring(0,buffer1.indexOf('=')));
        Serial.print(" = ");
        Serial.println(strtoint(buffer1.substring(buffer1.indexOf('=')+1)));
     }
         if(parsedParams>MAX_PARAMS-1)
         {
          Serial.println("больше нет места куда сохранять парсенное.");
          return; // больше нет места куда сохранять парсенное
         } 
  }
  
}

Заранее спасибо!

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

А что у Вас означает число 50 в 9-й строке?

И вообще, какой длины строку Вы, по Вашему мнению, хотите отправить?

igorlab
Offline
Зарегистрирован: 11.11.2015

andriano, понял, спасибо! :)

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Что-то я туплю...

Отправляю "ping#" через микросхему MAX485 

Считываю:

String inString;

void loop() {

if (Serial.available()){
softSerial.println("Ok"); 
delay(5);
 

while (Serial.available()) {
char inChar = Serial.read();
inString += inChar;

if (inChar == '#') {
if (inString.indexOf('ping#')>0) {
softSerial.println("Temperatura");
}else{
softSerial.println("Net komandy");
}
inString="";
inChar="";
}


}//while (Serial.available()) {
}//if (Serial.available(){



}

Если ставлю двойные кавычки, то поллучаю в ответ только Ок

Если кавычки одинырные, то неыважно что отравляю, получаю только Temperatura

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

#13 Serial.println(inString); 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

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

Значит никакой "ping#" не приходит. И то, что в одинарных кавычках - не строка. Применение такой конструкции может дать любые результаты.