Помогите в очередной раз разобрать строку

MihaNN52
Offline
Зарегистрирован: 22.01.2017

Традиционное спасибо) седня займусь.

MihaNN52
Offline
Зарегистрирован: 22.01.2017

Работает. Данные идут. Все одной отправкой отправляю и получаю.

Круто!

a31.64
b24.52
c738.63
d26.40
e26.20
f29.50
g28.50
h1762.45
i28.10

Смотрю логи за 5 минут, потерь 0%.

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

Ну, и слава Богу.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Подписался

MihaNN52
Offline
Зарегистрирован: 22.01.2017

Данные летят через ESP по MQTT 

vgk_com
Offline
Зарегистрирован: 02.03.2017

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

Ну, можно и так. 

Ну, а приём тоже проще некуда. Вы бы могли и сами по образцу, что был. 

Первым делом надо понимать, что любой разборщик - конечный автомат. Вот и давайте выделять его состояния. Читайте внимательно и Вы всё поймёте. 

1. Ждёт символа '&' при этом игнорирует все остальные символы. Получив символ '&' переходит в состояние 2
2. Ждёт имени переменной, получив байт проверяется яляется ли он латинской буквой. Если да, переходит в состояние 3, иначе в состояние 1
3. Ждёт начала числа, получив что-то, пытается прочитать как число и после этого выдаёт результат (имя - число) и переходит в состояние 1.

Изначально автомат находится в состоянии 1.

Вот и всё, осталось это написать. Но тут всё просто - пишем буквально как есть, прямо по этим пунктам.

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

enum AUTOMATA_STATE { // Возможные состояния разборщика
	WAITING_AMPERSAND,	// ожидание начала пакета
	WAITING_NAME, 	//	ожидание имени
	WAITING_NUMBER	//	ожидание числа
};

#define	PACKET_BEGIN	'&'

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

void loop(void) {
	// Изначально автомат в состоянии ожидания
	static AUTOMATA_STATE state = WAITING_AMPERSAND;
	static char variableName;
	
	if (! Serial.available()) return;	// не пришёл символ? Ну, и нечего тут делать
	//
	// Что делать дальше определяется состоянием автомата
	switch (state) {
		case WAITING_AMPERSAND:
			// В состоянии ожидания мы ждём символа PACKET_BEGIN и игнорируем любые другие
			if (Serial.read() != PACKET_BEGIN) return;
			// Пришёл символ начала пакета. Переходим в состояние PARSING
			state = WAITING_NAME;
			break;
		case WAITING_NAME:
			// В состоянии ожидания имени мы мы должны получить латинскую букву. 
			// Если получили - переходим в состояние ввода числа
			// Если пришло что-то другое - ошибка, переходим обратно в ожидание &
			variableName = Serial.read();
			state = isalpha(variableName) ? WAITING_NUMBER : WAITING_AMPERSAND;
			break;
		case WAITING_NUMBER:
			// читаем число
			float value;
			Serial.readBytes((byte *) & value, sizeof(value));
			///////////////////////////
			//	В этом месте мы имеем результат !!!!
			//	Имя находится в переменной variableName, а значение - в переменной value
			//	Что с ними делать решайте сам - сериал-то у нас занят другим устройством
			//	так что печатать результат некуда
			///////////////////////////
			state = WAITING_AMPERSAND;
			break;
	}
}

Сравните текст с написанными выше правилами - всё переписано 1 к 1. Текст коротенький - комментариев больше.

Возможно, я в чём-то ошибся, проверить сейчас не на чем. Но идейно всё правильно, а если будут мелкие ошибки - пишите, посмотрим, поправим.

Добрый день! Я хочу использовать этот код, но при посылке пакета $&a29.72&b20.44&c748.35&d26.20# 

ответ приходит:

a=0.00
b=0.00
c=0.00
d=0.00
не могу понять в чем дело, помогите пожалуйста.
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, в изначальной задаче, насколько я понимаю число шло во внутреннем представлении, а у Вас число идёт в текстовом виде. Поэтому вместо строки 40 попробуйте написать

value = Serial.parseFloat();

Должно помочь.

Добрался до ардуины и попробовал. да, всё нормально. Вот код с исправлением

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

enum AUTOMATA_STATE { // Возможные состояния разборщика
	WAITING_AMPERSAND,	// ожидание начала пакета
	WAITING_NAME, 	//	ожидание имени
	WAITING_NUMBER	//	ожидание числа
};

#define	PACKET_BEGIN	'&'

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

void loop(void) {
	// Изначально автомат в состоянии ожидания
	static AUTOMATA_STATE state = WAITING_AMPERSAND;
	static char variableName;
	
	if (! Serial.available()) return;	// не пришёл символ? Ну, и нечего тут делать
	//
	// Что делать дальше определяется состоянием автомата
	switch (state) {
		case WAITING_AMPERSAND:
			// В состоянии ожидания мы ждём символа PACKET_BEGIN и игнорируем любые другие
			if (Serial.read() != PACKET_BEGIN) return;
			// Пришёл символ начала пакета. Переходим в состояние PARSING
			state = WAITING_NAME;
			break;
		case WAITING_NAME:
			// В состоянии ожидания имени мы мы должны получить латинскую букву. 
			// Если получили - переходим в состояние ввода числа
			// Если пришло что-то другое - ошибка, переходим обратно в ожидание &
			variableName = Serial.read();
			state = isalpha(variableName) ? WAITING_NUMBER : WAITING_AMPERSAND;
			break;
		case WAITING_NUMBER:
			// читаем число
			float value = Serial.parseFloat();
			Serial << variableName << "=" << value << '\n';
			///////////////////////////
			//	В этом месте мы имеем результат !!!!
			//	Имя находится в переменной variableName, а значение - в переменной value
			//	Что с ними делать решайте сам - сериал-то у нас занят другим устройством
			//	так что печатать результат некуда
			///////////////////////////
			state = WAITING_AMPERSAND;
			break;
	}
}

Если в сериал ввести строку

$&a29.72&b20.44&c748.35&d26.20#

то печатает

a=29.72
b=20.44
c=748.35
d=26.20

 

vgk_com
Offline
Зарегистрирован: 02.03.2017

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

Ну, в изначальной задаче, насколько я понимаю число шло во внутреннем представлении, а у Вас число идёт в текстовом виде. Поэтому вместо строки 40 попробуйте написать

value = Serial.parseFloat();

Должно помочь.

Добрался до ардуины и попробовал. да, всё нормально. Вот код с исправлением

template <typename T> inline Print & operator << (Print &s, T n) { s.print(n); return s; }

enum AUTOMATA_STATE { // Возможные состояния разборщика
	WAITING_AMPERSAND,	// ожидание начала пакета
	WAITING_NAME, 	//	ожидание имени
	WAITING_NUMBER	//	ожидание числа
};

#define	PACKET_BEGIN	'&'

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

void loop(void) {
	// Изначально автомат в состоянии ожидания
	static AUTOMATA_STATE state = WAITING_AMPERSAND;
	static char variableName;
	
	if (! Serial.available()) return;	// не пришёл символ? Ну, и нечего тут делать
	//
	// Что делать дальше определяется состоянием автомата
	switch (state) {
		case WAITING_AMPERSAND:
			// В состоянии ожидания мы ждём символа PACKET_BEGIN и игнорируем любые другие
			if (Serial.read() != PACKET_BEGIN) return;
			// Пришёл символ начала пакета. Переходим в состояние PARSING
			state = WAITING_NAME;
			break;
		case WAITING_NAME:
			// В состоянии ожидания имени мы мы должны получить латинскую букву. 
			// Если получили - переходим в состояние ввода числа
			// Если пришло что-то другое - ошибка, переходим обратно в ожидание &
			variableName = Serial.read();
			state = isalpha(variableName) ? WAITING_NUMBER : WAITING_AMPERSAND;
			break;
		case WAITING_NUMBER:
			// читаем число
			float value = Serial.parseFloat();
			Serial << variableName << "=" << value << '\n';
			///////////////////////////
			//	В этом месте мы имеем результат !!!!
			//	Имя находится в переменной variableName, а значение - в переменной value
			//	Что с ними делать решайте сам - сериал-то у нас занят другим устройством
			//	так что печатать результат некуда
			///////////////////////////
			state = WAITING_AMPERSAND;
			break;
	}
}

Если в сериал ввести строку

$&a29.72&b20.44&c748.35&d26.20#

то печатает

a=29.72
b=20.44
c=748.35
d=26.20

 

Спасибо большое, работает.

MihaNN52
Offline
Зарегистрирован: 22.01.2017

...минуту)

ivanchekalov
Offline
Зарегистрирован: 25.08.2016

Подписался

vgk_com
Offline
Зарегистрирован: 02.03.2017

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

void SerialRead() {
  // прием сообщений типа    ?a18.95;eon;fon3;#  начинаться должен  с ? и заканчиваться #,
  // внутри данные a18.95;   eon3;  fon;  и т.д. где а=18.95, е=on? e = on3 и т.д. Количество ограничивается только длинной передаваемого сообщения.
 //   и может быть хоть одно или несколько байтов в любой последовательности, то есть сперва ?a18.95; и сразу fon3;#  (?a18.95;fon3;#)
  while (Serial.available() > 0) {
    if (sFlag) {
      serialReq = "";
      sFlag = false;
    }
    char c = Serial.read();
    if (serialReq.length() >= MAX_SERIAL_REQ) {   // объявляйте в начале MAX_SERIAL_REQ 128 (число байтов сообщения)
      serialReq = "";
      Serial.println ("Error MAX_SERIAL_REQ");
    }
    if (serialReq.length() < MAX_SERIAL_REQ) {
      serialReq += c;
      

      if (serialReq.lastIndexOf(F("#")) >= 0)  {  
        serialReq = serialReq.substring(0, serialReq.length() - 1); // удаляем последний символ
        parseSerialCmd();
        sFlag = true;
      }
    }
  }
}

void parseSerialCmd () {  фунция разбора сообщения
  String command;
  String parameter;
  Serial.println (serialReq);
  // ?a20.02;b25.78;c-5.00;d+12.00;e220DA;fakkum;g6666;h9999;j77777;i33333;# это примеры для передачи
  // ?a18.95;eon;fon;#   ?a18.95;eoff;foff;# примеры

  if (serialReq.indexOf(F("?")) >= 0) { // проверяем первый символ ?, если совпадает то продолжаем
    int lastIndex = 1;
       //Serial.println (serialReq.length()); //  считаем количество символов в переменной serialReq
    for (int i = 0; i < serialReq.length(); i++) {  // запускаем цикл по количеству символов
      if (serialReq.substring(i, i + 1) == ";") {    // перебераем символы до первого разделителя ";"
        if (serialReq.substring(lastIndex, lastIndex + 1) == String ("a")) { //сверяем первый символ "а"
          // Serial.print ("a=");
          value1 = serialReq.substring(lastIndex + 1, i); // присаиваем значение после символа "а" до первого разделителя ";"
          //Serial.println (value1);
          lastIndex = i + 1;

        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("b")) {
            //Serial.print ("b=");
            value2 = serialReq.substring(lastIndex + 1, i);
            //Serial.println (value2);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("c")) {
            // Serial.print ("с=");
            value3 = serialReq.substring(lastIndex + 1, i);
            //Serial.println (value3);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("d")) {
            // Serial.print ("d=");
            value4 = serialReq.substring(lastIndex + 1, i);
            // Serial.println (value4);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("e")) {
            //Serial.print ("e=");
            value5 = serialReq.substring(lastIndex + 1, i);
            // Serial.println (value5);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("f")) {
            //Serial.print ("f=");
            value6 = serialReq.substring(lastIndex + 1, i);
            //Serial.println (value6);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("g")) {
             Serial.print ("g=");
            value7 = serialReq.substring(lastIndex + 1, i);
            Serial.println (value7);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("h")) {
             Serial.print ("h=");
            value8 = serialReq.substring(lastIndex + 1, i);
             Serial.println (value8);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("i")) {
            //Serial.print ("i=");
            value9 = serialReq.substring(lastIndex + 1, i);
            // Serial.println (value9);
            lastIndex = i + 1;
          }
        }
        if (i >= lastIndex) {
          if (serialReq.substring(lastIndex, lastIndex + 1) == String ("j")) {
            // Serial.print ("j=");
            value10 = serialReq.substring(lastIndex + 1, i);
            // Serial.println (value10);
            lastIndex = i + 1;
          }
        }
      }
    }
  }
}

void megaCommand() {  // пример функции для передачи
  
  String a = String ("a") + String (status1) + String (";");
  String b = String ("b") + String (status2) + String (";");
  String c = String ("c") + String (status3) + String (";");
   
  String comandMega = String("?") + String(a) + String(b) + String(c) + String("#");
  
  Serial.print ("comandMega =" + comandMega);
  Serial.write(comandMega.c_str());
  delay (100);
  
}

 

MihaNN52
Offline
Зарегистрирован: 22.01.2017

Тема актуальная, передача инфы между МК.

Ты пробовал его в обе стороны т.е чтоб один мк и принимал и отправлял.

Строки для новичков понятней. Заценим, отпишем.

vgk_com
Offline
Зарегистрирован: 02.03.2017

Да у меня работает между мегой и esp.  Правда интервал между сообщениями поставил 10 секунд, меня вполне устраивает. Я дамаю можно и меньше поставить, для экономии трафика пойдет.

DarkGenius
Offline
Зарегистрирован: 09.07.2015

Мой вариант. Пример строки:d14,e16,f8,a38.9,c17,b14,#
 

while (Serial.available() > 0) {
    String str = Serial.readStringUntil('#');
    int str_len = str.length() + 1;
    char char_array[str_len];
    str.toCharArray(char_array, str_len);
    char *pch = char_array;
    pch = strtok (pch,",");
    while (pch != NULL){
      String str2 = pch;
      String myValue = str2.substring(0, 1);
      if (myValue == String ('a')) {
        cpuTempValue = str2.substring(1).toFloat();
      }
      if (myValue == String ('b')) {
        cpuLoadValue = str2.substring(1).toInt();
      }
      if (myValue == String ('c')) {
        cpuCore1Value = str2.substring(1).toInt();
      }
      if (myValue == String ('d')) {
        cpuCore2Value = str2.substring(1).toInt();
      }
      if (myValue == String ('e')) {
        cpuCore3Value = str2.substring(1).toInt();
      }
      if (myValue == String ('f')) {
        cpuCore4Value = str2.substring(1).toInt();
      }
      pch = strtok (NULL, ",");
    }
}