ARDUINO Чтение из Serial

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
Помогите пожалуйста разобраться с Serial в Ардуино
Получаю в Serial1 данные от преобразователя частоты используя TTL-RS485, в порт поступают данные, вывожу в монитор порта

C++:
while(Serial1.available()){
    Serial.println(Serial1.read(), HEX);
}
Например в монитор порта вывелось: 162000542913203F845
Это данные стандарта Modbus-RTU, единственное что Serial1.read() вычитывает и отправляемые данные, приведу ниже как идет отправка и прием:
1620005429 - Это то что отправил контроллер
13203F845 - Это то что получил контроллер от частотника

Приведя к стандарту Modbus-RTU получим
{ 0х01, 0х06, 0х20, 0х00, 0х00, 0х05, 0х42, 0х90 } и { 0х01, 0х03, 0х20, 0х00, 0х00, 0х03, 0хF8, 0х45 } соответственно.

Так вот мне нужно то, что Serial1.read() вычитывает побайтно например 162000542913203F845 получить только ответ, а из самого ответа требуются только два предпоследних байта { 0х01, 0х03, 0х20, 0х00, 0х00, 0х03, 0хF8, 0х45 }

Перерыл гугл ничего не понял:)

Все еще усугубляется тем, что ответ может быть другой длины, например 16100271097361321388B512 и тупой парсинг уже не проканает, ибо если искомые байты в этом ответе это 16100271097361321388B512, то в этом 162000542913203F845
Есть определенное постоянство конечно в виде того, что значение ответа расположено всегда перед двумя байтами последними, последние два байта это контрольная сумма,
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Сначала откидываете запрос, который отправляли сами - а потом разбираете ответ по протоколу Модбас. Просто "вытащить один или два байта перед двумя последними" - так не делают. Нужно разобрать весь пакет, сверить контрольную сумму - и только если она сойдется, читать данные
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@bort707,
Как его откинуть?
Я выяснил и удивился, что длина Serial1.available() всегда равна 15, вне зависимости пришло это 162000542913203F845 или это 16100271097361321388B512

Я кажется вообще не понимаю как работать с Serial1.read()
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Я выяснил и удивился, что длина Serial1.available() всегда равна 15,
Как вы это выяснили?

вне зависимости пришло это 162000542913203F845 или это 16100271097361321388B512
Скорее всего эти строчки одинаковой длины, просто вы их печатаете неправильно. У вас лидирующие нули в байтах потеряны. На самом деле это запрос из 8 байт и ответ из 8 байт. Соответственно, длина того, что вы прочитали - всегда должна быть 16.
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
C++:
if(Serial1.available() > 0){
    int16_t i = 0;
    int16_t l = Serial1.available();
    Serial.println(l);
    while(Serial1.available()){
      i++;
      Serial.println(Serial1.read(), HEX);
    }
    Serial.println(i);
}

Нет мне то конечно заранее известно, что отправляется 8 байт и приходят 8 байт, так что Serial1.available() равен 15
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
while(Serial1.available()){ Serial.println(Serial1.read(), HEX); }
Вот тут вот не надо сразу отправлять на печать. Прочитайте байт в переменную, и если результат меньше 16 - выведите перед переменной "0"

Слушайте, что вы мне морочите голову?
У вас в обоих случаях строчки начинаются с цифры 16, я ее вам специально выделил.
пришло это 16 2000542913203F845 или это 16 100271097361321388B512
Это и есть ваша длина строки, напечатанная в строке 4 (по коду из сообщения #6)

Зачем же вы мне прям в глаза... выдумываете, что вы принимаете 15 байт????
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@bort707,
Да обе переменной всегда 15

Мне вообще в Serial выводить не нужно, это я так туда вывожу дабы поглядеть. Может я Вам заплачу за помощь в написании функции которая скушает из Serial1 пришедшие байты и в зависимости от полученного аргумента вернет либо этот байт преобразованный в число 162000542913203F845 либо вернет 16100271097361321388B512 преобразованное в число ну 0x1388 это 5000 должно быть
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@bort707,
Нет, 16 это { 0х01, 0х06, 0х20, 0х00, 0х00, 0х05, 0х42, 0х90 } без лидирующих нолей

@bort707,

Изображение WhatsApp 2024-08-31 в 15.57.09_3df17e05.jpg

Лживая Ардуино :)
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Лживый кто-то другой. Картинка не соответствует коду.
Покажите ИМЕННО ТОТ КОД, который вы запускаете, иначе разговора не будет.
И напечатайте принимаемое сообщение так, чтобы было понятно - с лидирующими нулями и пробелами между отдельными байтами.

И вообще, нельзя так браться за дело - провода к переходнику "в спешке" закоротили, байты в сообщениях валите в кучу - а потом и в том и в другом случае кто-то должен разбирать ваши косяки?


ЗЫ сегодня суббота, хорошая погода, нет смысла киснуть за компом. Вернусь вечером, если никто до того не поможет, продолжим.
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@bort707,

а нет!

Должно быть так 01 06 20 00 05 04 29 01 03 20 00 00 03 F8 45 в монитор печатает так 162000542913203F845
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Дальше печатайте только с пробелами.
Какой запрос отсылали, что получить ответ в последнем сообщении?
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@bort707,

Вот в общем окончательно верный

Запрос - 01 06 20 00 00 05 04 29
Ответ - 01 03 20 00 00 03 F8 45

В глазах уже рябит от этих байт, прошу прощения
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Вроде нет сомнений, что их 16 , а не 15?:)
Если у вас всегда запрос и ответ одной длины, то извлечь нужные вам значения можно просто по порядковому номеру.
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@bort707,

но счет же с 0 начинается поэтому 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 = 16 или я не прав?

@bort707,
Я не пойму как мне например из этого 01 06 20 00 00 05 04 29 01 03 20 00 00 03 F8 45 извлечь 14 байт который равне 03 и превратить его в 3, или
01 03 70 01 00 01 97 36 01 03 20 00 13 88 B5 12 извлечь 13 и 14 байт и превратить их 5000
 

Zuker

★✩✩✩✩✩✩
10 Янв 2024
56
12
Складывайте вывод в массив, а потом работайте с ним.
В строке 209 добавьте пробел, чтобы легче читать байты в выводе:
C++:
Serial.print(Serial1.read(), HEX);
Serial.print(' ');
 
Изменено:

bort707

★★★★★★✩
21 Сен 2020
3,058
910
не пойму как мне например из этого 01 06 20 00 00 05 04 29 01 03 20 00 00 03 F8 45 извлечь 14 байт который равне 03
Не работайте со строкой, работайте с байтами. Байт 0х03 и равен трем и никак преобразовывать его не нужно. С двумя байтами чуть сложнее, но тоже бином ньютона
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@Zuker,
Это то понятно, запихал в массив проблем нет

@bort707,
0х03 - Понятное дело, что 3 и в Африке 3

Теперь извлекая из массива нужные два байта, как их превращать в число?
 

Zuker

★✩✩✩✩✩✩
10 Янв 2024
56
12
Не стесняйтесь напрягать нейросети для написания кода (https://beta.theb.ai- gtp 3.5 бесплатно, но нужен рег почты). Ниже первый результат GPT:

Пример для двух байт
C++:
void setup() {
  // put your setup code here, to run once:

Serial.begin(9600); // Настройка последовательного порта

  // Пример двух байтов в формате HEX
  String hex1 = "13"; // Первый байт
  String hex2 = "88"; // Второй байт

  // Объединяем два байта
  String combinedHex = hex1 + hex2;

  // Преобразуем объединённую строку в целое число
  long combinedValue = strtol(combinedHex.c_str(), NULL, 16);

  // Вывод результата
  Serial.print("Объединение: ");
  Serial.print(hex1);
  Serial.print(" и ");
  Serial.print(hex2);
  Serial.print(" = ");
  Serial.print(combinedHex); // Вывод объединенного HEX
  Serial.print(" (десятичное: ");
  Serial.print(combinedValue);
  Serial.println(")");
}

void loop() {
  // put your main code here, to run repeatedly:

}
Пример сборки массива:
C++:
const int BUFFER_SIZE = 16;
uint8_t buffer[BUFFER_SIZE]; // Массив для хранения данных
int bytesRead = 0;           // Счетчик прочитанных байтов

void setup() {
  Serial1.begin(9600); // Настройка скорости порта
  Serial.begin(9600);  // Настройка порта последовательной передачи для отладки
}

void loop() {
  while (Serial1.available() && bytesRead < BUFFER_SIZE) {
    // Чтение байта из Serial1
    buffer[bytesRead] = Serial1.read();
    bytesRead++;
  }

  if (bytesRead == BUFFER_SIZE) {
    // Достаточно байт для обработки
    Serial.println("Полученные данные:");
    for (int i = 0; i < BUFFER_SIZE; i++) {
      Serial.print(buffer[i], HEX);
      Serial.print(" ");
    }
    Serial.println();

    // Сброс счетчика после обработки
    bytesRead = 0;
  }
}
 

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Не стесняйтесь напрягать нейросети
Не стесняйтесь напрягать свои мозги, а если без искусственного интеллекта не знаете ответа - то лучше промолчать.
На мировом форуме Ардуино arduino.cc ответы от AI вообще запрещены, за это банят.
И это не просто так. Вот в вашем случае в первом примере написана полная чушь. Зачем превращать байты сначала в строки, потом сшивать, а потом преобразовывать - когда сборка значения инт из двух байт делается в одно действие:

int x = (high_byte <<8) | low_byte;
 
  • Лойс +1
Реакции: koreets61

Zuker

★✩✩✩✩✩✩
10 Янв 2024
56
12
@bort707,
ИИ говнокод представлен примером, с акцентом на поиск ответов у нейросетей.
Никто не мешает поднапрячь мозги и составить запрос ИИ более правильный и получить оптимизированный ответ "в одно действие".
Но кому какое дело до этого, за бесплатно, тем более старожилам.
Времени на изучение нет, а фичу сделать хочется. Что ИИ, что ардуино - гомно и палки.
 

koreets61

✩✩✩✩✩✩✩
30 Авг 2024
20
0
@Zuker,

Ардуино неплохая отладочная плата, то что на ней пытаются enterprise проекты собрать в "Сколково" Ардуино не виновата

@Zuker,

Мне вот нафиг STM не нужен для тривиальной задачи, собрать на коленке некий преобразователь интерфейсов дабы запустить из WEB трехфазный асинхронный электродвигатель с определенными оборотами, и небольшую обратную связь. Atmega куда быстрее, проще и дешевле чем STM
 

Zuker

★✩✩✩✩✩✩
10 Янв 2024
56
12
@koreets61,
Ваш топик довольно простой для GPT. Смотря на то, как "ищущие" топчутся на месте от сухих ответов, хочется послать хотя бы на GPT.
Общение с GPT это тоже вариант самообучения - покрутить, повертеть, понять. Оптимизация потом.

GPT тоже знает об этой строке:
C++:
int x = (high_byte <<8) | low_byte;
 
  • Лойс +1
Реакции: bort707