Устойчивость передачи данных по Serial

Евгений, этот метод вылавливает ошибки при передаче. Худо-бедно у меня есть контрольный байт. Битые данные должно отсечь, и цветы, и квартиру не зальет. А у меня пропадает весь пакет. Попробую добавить еще ветку, чтобы выводило в Телеграм даже битые данные (без обработки конечно), а правильные - в дело.

UART плох при помехах в линии связи, при длинных линиях, при несовпадении скоростей. Ну а тут?
Тут именно неаккуратное программирование. Где то что то не учитываем, где то отвлекаемся, где то пропускаем. Протокол отчасти может решить проблему, только нужен ли он тут? Нужно убрать явные баги сначала.

“А что, так можно было ?”(с) Типа компилятор сам разберётся: раз настроен как выход - будешь цифровым, а вообще не настроен - аналоговым? Сам столкнулся недавно, а программа работала корректно уже несколько лет. :thinking: Был удивлён, но на всякий добавил “А” перед номером

Данные со всех аналогов считываются корректно.
Цифровой 4 исправно подает питание на датчики, пятый также исправно подает питание на насос.

P.S. По дурости надеялся на чудо. “А” не помогло.

Добавил в ESP ветку, чтобы слушать все.

if(wifiConnected())
	{
		timeClient.update();  
		int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
		handleNewMessages(numNewMessages);
		if (Serial.available())
		{
			if (Serial.readBytes((byte*)&bufOutArduino, sizeof(bufOutArduino)))
			{
				byte crc = crc8_bytes((byte*)&bufOutArduino, sizeof(bufOutArduino));
				delay(2);
				if (crc == 0)
				{
					messg = F("Ответ получен\n");
				}
				else
				{
					messg = F("data is damaged\n");
				}

				// здесь полезный код из предыдущих постов
			}
			else
			{
				while(Serial.available())
				{
					messg += Serial.read();
					messg += F(" - ");
				}
			}
		}

Команды выполняются не все, в эфире тишина. Решил поймать хоть байт:

if (Serial.available())
		{
			if (Serial.readBytes((byte*)&bufOutArduino, sizeof(bufOutArduino)))
			{
                                    //полезный код
			}
			else
			{
				messg += Serial.read();
			}
		}

Опять тишина. Получается данные вообще не приходят на ESP. И опять выборочно.

Не всегда функции работают так как вы ожидаете. Понять что вы ожидаете - можно только догадываться, комментариев в коде нет.
Например (из последнего кода):
1 if (Serial.available()) - если это истина, то
3 (Serial.readBytes((byte*)&bufOutArduino, sizeof(bufOutArduino))) всегда вернет не нулевое значение и соответственно
7 else никогда не выполнится.

Serial.readBytes возвращает количество полученных байт, а не проверку того, что он считал столько сколько его просили. Получение одного байта вместо полного пакета - должно быть ошибкой, но Serial.readBytes вернет 1, что является истиной.

Не связано с предыдущим
На всякий случай напомню, что SoftwareSerial не может одновременно отправлять и принимать данные - только по очереди т.е полудуплекс.

1 лайк

Да.

См. текст analogRead

@Unimat2809, Вы вообще, читаете, что Вам пишут? Или Вы сюда просто потрындеть зашли?

Ну, сколько раз Вам уже повторяли, что вот так писать нельзя?

По-русски, здесь написано: если пришёл хотя бы один байт, то читаем сразу всю пачку и пох сколько там пришло на самом деле!

Вам ведь про это уже не раз говорили! А Вы всё не переделали. На что Вы надеетесь?

1 лайк

а вот мне интересно почему в микроконтроллерах буфер на юарт всего один байт, увеличить до 16, а то аж до 64 и проблем бы не было!?

Человеку восемь рук тоже было бы норм. И почему их только две…

Вот это интересный кусок

почему вы уверены, что равенство crc нулю означает удачную приемку данных?

А в целом вся программа - типичный “спагетти-код” - то есть невероятное число повторов одинаковых по сути операторов…

Если у вас шесть экземпляров класса Channels и так уже собраны в массив - так зачем писать каждый экземпляр на свое строке, что за дикость?

Почему не так, хотя бы:

esp.print("#");
esp.print("k");
for (int k = 0; k < 6; k++)
      esp.print(Channels[k].number);
      esp.print(" - ");
      }

глядишь и программу станет легче читать

Не знаю, как там с общематематической точки зрения, но с далласом так - вычисляешь crc по всему массиву, включая принятое crc, и получаешь 0.
Есть, правда, засада - если закоротило, то принимаешь все нули, crc сходится, температура неверная и газовый котел летит на марс ))

1 лайк

да, ты прав, не учел что ТС вычисляет контрольную сумму, включая саму сумму…

и кстати, просто из занудства - это отнюдь не “одиночный” цикл, он у вас выполняется дважды

1 лайк

А, ну да, я вспомнил - если в расчете crc участвует xor, то на последней итерации хорятся одинаковые числа при совпадении crc. В результате, по таблице истинности, получается нуль.

Зачем? Туда же ещё газопровод не протянули! Или уже, просто я отстал?

Вроде только частники летают из российских деревень. Проект Кибердеревня - слышали?

в IBM PC XT буфер был 16 байт, или я что-то путаю?
PS ты случайно с астрономами не связан, а то их всех разогнать надо за профнепригодность, у них расстояние до полярной звезды постоянно скачет более чем на 100 световых лет, 100 световых лет Карл )))

Спасибо, исправил. Тупанул к вечеру.

Спойлер
if (Serial.available())
{
	//Это добавил позже, чтобы хоть что-то услышать
	messg += Serial.peek();
}
//Считываем из порта структуру данных
if (Serial.readBytes((byte*)&bufOutArduino, sizeof(bufOutArduino)))
{
	//считаем контрольный байт
	byte crc = crc8_bytes((byte*)&bufOutArduino, sizeof(bufOutArduino));
	if (crc == 0)
	{
		//если контроль пройден, перебираем значения идентификатра структуры
		if(bufOutArduino.val_id == 105)
		{
			//готовим сообщение в соответствии с идентификатором
			messg += F("Канал ");
			messg += bufOutArduino.val_1;
			messg += F(": Влажность - ");
			messg += bufOutArduino.val_2;
			messg += F("%. Порог - ");
			messg += bufOutArduino.val_3;
			messg += F("%. Ожидание - ");
			messg += bufOutArduino.val_4;
			messg += F(":");
			messg += bufOutArduino.val_5;
			messg += F(":");
			messg += bufOutArduino.val_6;
			//очищаем структуру данных
			clearData();
		}
		//else if(bufOutArduino.val_id == 107)
		//{  подготовка аналогичных сообщений под другие идентификаторы
	}
	else
	{
		//если контрольный байт неверен - данные повреждены
		//добавляем в сообщение все, что удалось принять
		messg = F("data is damaged \n");
		messg += bufOutArduino.val_id;
		messg += F(" - ");
		messg += bufOutArduino.val_1;
		messg += F(" - ");
		messg += bufOutArduino.val_2;
		messg += F(" - ");
		messg += bufOutArduino.val_3;
		messg += F(" - ");
		messg += bufOutArduino.val_4;
		messg += F(" - ");
		messg += bufOutArduino.val_5;
		messg += F(" - ");
		messg += bufOutArduino.val_6;
		//очищаем структуру данных
		clearData();
	}
}
// выводим сообщение messg в телеграм-бот

Опять по сбоям ничего не приходит, редкие 1-2 байта при старте.
Но решение (костыль?) я нашел.