Официальный сайт компании Arduino по адресу arduino.cc
"Чёрная магия" при передаче данный в приложение
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Не знаю к чему это относится. к программированию или вопросам с железом, поэтому в общий.
Создал приложение в Qt, в нем использую библиотеку QSerialPort (позволяет приложению работать с последовательным портом) и QSerialPortInfo (помогает работать с QSerialPort).
Схема взаимодействия ардуины (что уна, что мега одинаково) и приложения:
Приложение отправляет по порту (USB кабель обыкновенный) 0 (стартовое число).
Ардуина принимает данные, переводит в число, увеличивает на 1, отправляет по порту приложению.
Приложение принимает данные (записывает в текстовик данные с ардуины, и также записывает данные которые отправит ей), переводит в число, увеличивает на 1, и отправляет ардуине.
и тд до миллиона.
По идее в текстовике должен быть список от 0 до миллиона но увы происходит чёрная магия. В какой-то момент (максимум где-то с 20000) , случается следующее:
Например число 23456 приходит в компьютер в виде 234, и отдельно 56. естественно всё идёт по известному направлению, внезапные цифры, далее могут вообще начать появляться отрицательные числа. Бывает что ардуина отправляет:
..., 128, 130, 13, 132, 134, ... (приложение вывело 13, и при этом спокойно продолжило счёт как ни в чём не бывало)
Вот тут вообще цирк
402 404 406 408 410 4 (откуда и почему) 412 414 416 418 420 422 424 426 428 4282 4284 42842 (внезапная двойка) -226922 (чёрная магия) -303122 -16554 -165542 -17010 -170082 265282 31402 314042 -136362 -52882 126562 -45082 204562 79562 140282 92122 265882 37402 -281322 -191762 -17066 -170642 259682 -2460 -24602 -246002 161442 303722 -23956 -239562 22584 225842 292362 302202 -254762 7384 73842 8308 83082 17548 175482 -21124 -211242 0 -146322 -1 -152482 0 -214082 -174 -174722 218882 22276 222762 26156 261562 -580 -5802 -5800 -58002 7536 75362 9828 98282 32748 327482 -196 -1962 -1960 -19602 -19600 -196002 60 6082 6084 60842 -4692 -46922 18616 186162 -10444 -104442 4166 41662 -23872 -238722 -27914 -27912 -279122 -16976
Протокол передачи данных по идее должен не допускать подобных ситуаций, но всё таки бывает, и я хз почему так происходит.
Кто знает что с этим делать и почему так происходит прошу, подскажите.
Вот cpp проекта
#include <iostream> #include <QSerialPort> #include <QDebug> //#include <QByteArray> #include <QSerialPortInfo> #include <fstream> QByteArray inputArdPc(QSerialPort *arduinoi); ofstream outputFile("outputFile.txt"); int main() { QSerialPort *arduino = new QSerialPort; static const quint16 arduino_uno_vendor_id = 9025; static const quint16 arduino_uno_product_id = 67; QString arduino_port_name = ""; bool arduino_is_available = false; qDebug() << "Number of available ports: " << QSerialPortInfo::availablePorts().length(); foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){ qDebug()<< endl << "Has vendor ID: " << serialPortInfo.hasVendorIdentifier(); if(serialPortInfo.hasVendorIdentifier()){ qDebug() << "Vendor ID: " << serialPortInfo.vendorIdentifier(); } qDebug() << "Has Product ID: " << serialPortInfo.hasProductIdentifier(); if(serialPortInfo.hasProductIdentifier()){ qDebug() << "Product ID: " << serialPortInfo.productIdentifier(); } } foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){ if(serialPortInfo.hasVendorIdentifier() && serialPortInfo.hasProductIdentifier()){ if(serialPortInfo.vendorIdentifier() == arduino_uno_vendor_id){ if(serialPortInfo.productIdentifier() == arduino_uno_product_id){ arduino_port_name = serialPortInfo.portName(); arduino_is_available = true; qDebug() << "Conect: yes" ; } } } } if(arduino_is_available){ // open and configure the serialport arduino->setPortName(arduino_port_name); arduino->open(QSerialPort::ReadWrite); arduino->setBaudRate(QSerialPort::Baud115200); arduino->setDataBits(QSerialPort::Data8); arduino->setParity(QSerialPort::NoParity); arduino->setStopBits(QSerialPort::OneStop); arduino->setFlowControl(QSerialPort::NoFlowControl); qDebug() << "Inicialization: yes" ; }else{ // give error message if not available qDebug() << "Port error, Couldn't find the Arduino!"; } int h = -1; while(h != 666){ arduino->waitForReadyRead(500); if(arduino->isWritable()){ h = -1; cout << "\nPrint comand\n"; char chararr[10]; cin >> chararr; //QByteArray QBAi = chararr; QByteArray QBAi = QByteArray::number(0); qint64 flag = 0; while (QBAi.toInt() != 1000000){ if(arduino->isWritable()){ flag = arduino->write(QBAi); int udlod = inputArdPc(arduino).toInt(); ++udlod; QBAi = QByteArray::number(udlod); } } //sendCommand(); int f = sendCommand( "command", 3); cout << f; QString che = "fghjk"; std::string tststr = getStringCommand(arduino); if(arduino->isReadable()){ qDebug() << "Get data:"; QByteArray QBAtest; arduino->waitForBytesWritten(1); arduino->flush(); arduino->waitForReadyRead(1); while (arduino->bytesAvailable() || arduino->waitForReadyRead(10)) { while (arduino->bytesAvailable()) { qDebug() << "Buf size: " << arduino->bytesAvailable(); qDebug() << "Set " << arduino->readAll() << endl; } } } } } outputFile.close(); arduino->close(); delete arduino; } QByteArray inputArdPc(QSerialPort *arduinoi){ QByteArray QBAtest = ""; if(arduinoi->isReadable()){ arduinoi->waitForBytesWritten(1); //arduinoi->flush(); arduinoi->waitForReadyRead(1); int bufSize = 0; while(arduinoi->bytesAvailable() || arduinoi->waitForReadyRead(5)){ qint64 intege = arduinoi->bytesAvailable(); bufSize += static_cast<int>(intege); QBAtest += arduinoi->readAll(); arduinoi->waitForReadyRead(1); outputFile << QBAtest.toInt() << endl; } return QBAtest; } return QBAtest; }
//число 23456 приходит в компьютер в виде 234, и отдельно 56
Задумайтесь что значить отдельно? Вы просто в своем коде проверяете принятую информацию в тот момент времени, когда 234 уже приняты а 56 - еще нет. Вероятно проблема на 2-х сторонах обмена. Смотрим на вызов arduinoi->bytesAvailable(), а где проверка сколько там байт принято? Вся остальная магия с отрицательными - отсюда прет. Решение проблемы - придумываем или выбираем протокол, как набор правил для целостной передачи.
ПС. Надо отметить детальное описание проблемы, не часто нас тут радуют этим.
Протокол передачи данных по идее должен не допускать подобных ситуаций.
насколько я вижу из кода, у вас какой-либо "протокол передачи" начисто отсутствует. Протокол должен четко указывать начало и конец передаваемых данных, а по хорошему еще отлавливать ошибки, например при помощи контрольной суммы. Вы же просто шлете в сериал байты, не заботясь о том, где у них начало, где конец.
Например, если вы непрерывно шлете в порт числа 1 2 3 4 - какое это число, по вашему? 1234? а почему не 2341 ? или даже два числа - 34 и 12 ? Как программа на другом конце линии должна различать эти варианты?
придумать свой протокол с маркерами начала и конца сообщения
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
В этих строчках по идее задаются всякие стопбайты, чётность и тд. Но как и что с ними делать я не понял даже поковыряв документацию на оф. сайте.
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
В этих строчках по идее задаются всякие стопбайты, чётность и тд. Но как и что с ними делать я не понял даже поковыряв документацию на оф. сайте.
эти параметры вам трогать не надо. Это нижний уровень передачи, он работает на уровне сборки байта из отдельных битов. Это все уже реализовано в драйвере последовательного порта.
Вам нужно придумать протокол верхнего уровня - как из отдельных байтов собрать число
А можно так: В такой ситуации сначала Serial.flush () - дождаться конца передачи. А потом прочитать строку: Serial.readString() ? Я слабый в программировании (поэтому, титаны, не пинайте пожалуйста), но у меня такая конструкция работает (правда, с проверкой начала, конца и длины строки).
А можно так: В такой ситуации сначала Serial.flush () - дождаться конца передачи. А потом прочитать строку: Serial.readString() ? Я слабый в программировании (поэтому, титаны, не пинайте пожалуйста), но у меня такая конструкция работает (правда, с проверкой начала, конца и длины строки).
Всё правильно, это и есть та самая, ваша личная, высокоуровневая реализация протокола обмена :)
Всё правильно, это и есть та самая, ваша личная, высокоуровневая реализация протокола обмена :)
Я уже упоминал что пока еще новичок, причем, очень даже слабый новичок. Отсюда даже не понял: это поощрение или ирония? В первом случае - спасибо, во втором - очень хотелось бы нормальных комментариев: в чем я не прав? Проблема тут в том, что скетч нормально работает (а без флаша - не нормально). Выскакивала бы ошибка - я б ее нашел и устранил, а тут... А то "художника каждый может обидеть" :)
Гляжу иногда и ваши темы, вы хорошо и быстро учитесь. Это было поощрение.
Ага, это хороший проект, мне тоже нравится :)
Гляжу иногда и ваши темы, вы хорошо и быстро учитесь. Это было поощрение.
Спасибо на добром слове. Но увы, учусь я далеко не так быстро, как надо, да и с "хорошо" - тоже сомнение: за такое "хорошее обучение" я своих курсантов на повторку отправляю :)
//число 23456 приходит в компьютер в виде 234, и отдельно 56
Задумайтесь что значить отдельно? Вы просто в своем коде проверяете принятую информацию в тот момент времени, когда 234 уже приняты а 56 - еще нет. Вероятно проблема на 2-х сторонах обмена. Смотрим на вызов arduinoi->bytesAvailable(), а где проверка сколько там байт принято? Вся остальная магия с отрицательными - отсюда прет. Решение проблемы - придумываем или выбираем протокол, как набор правил для целостной передачи.
ПС. Надо отметить детальное описание проблемы, не часто нас тут радуют этим.
Вот здесь посмотри http://arduino.ru/forum/obshchii/multimetr-arduinoandroid в скетче строки 60-69. Передаются через блютус с андроида. Начало "S" конец "Q" данные "D". Между ними данные.
//число 23456 приходит в компьютер в виде 234, и отдельно 56
Задумайтесь что значить отдельно? Вы просто в своем коде проверяете принятую информацию в тот момент времени, когда 234 уже приняты а 56 - еще нет. Вероятно проблема на 2-х сторонах обмена. Смотрим на вызов arduinoi->bytesAvailable(), а где проверка сколько там байт принято? Вся остальная магия с отрицательными - отсюда прет. Решение проблемы - придумываем или выбираем протокол, как набор правил для целостной передачи.
ПС. Надо отметить детальное описание проблемы, не часто нас тут радуют этим.
Верно кажется. Это называется стек протоколов, в котором каждый сверху опирается на нижний. Это типовой подход.
Признаком завершения данных может быть уникальный набор символов, заведомо отсутствующий в данных или таймаут. Таймаут предпочтительней в том смысле что , его как правило все равно придётся проверять чтоб определять наличие коннекта.
проблема так и не решена, хотя советуют колхозить свой протокол передачи данных. Хотя я думаю есть готовые решения без костылей. Но их ещё никто не высказал
то есть вы считаете, "колхозить свой протокол" - это костыль? - вы ошибаетесь. Никаких простых "готовых решений" не существует, если вас интересует надежность -придется разрабатывать протокол самому или в крайнем случае скопипастить у кого-то готовый
На самом деле протоколов поверх rs232 или RS485 немного. Интернет даёт 3-4. Посмотреть описание можно быстро и прикинуть что больше подходит.
//число 23456 приходит в компьютер в виде 234, и отдельно 56
Задумайтесь что значить отдельно? Вы просто в своем коде проверяете принятую информацию в тот момент времени, когда 234 уже приняты а 56 - еще нет. Вероятно проблема на 2-х сторонах обмена. Смотрим на вызов arduinoi->bytesAvailable(), а где проверка сколько там байт принято? Вся остальная магия с отрицательными - отсюда прет. Решение проблемы - придумываем или выбираем протокол, как набор правил для целостной передачи.
ПС. Надо отметить детальное описание проблемы, не часто нас тут радуют этим.
Верно кажется. Это называется стек протоколов, в котором каждый сверху опирается на нижний. Это типовой подход.
Признаком завершения данных может быть уникальный набор символов, заведомо отсутствующий в данных или таймаут. Таймаут предпочтительней в том смысле что , его как правило все равно придётся проверять чтоб определять наличие коннекта.
А не получится так что я своим протоколом перебью их протокол, он точно не полезет смотреть данные в которых может найти какой то символ особый который сочтет за команду. Хотя щас думаю что нет.
Мдамуж конечно, протокол ascii тогда чем занимается? Я вот смотрел его описание, вроде там все есть, закрывающие и тд вещи. Или у меня он по 1 символу передает?
а можно увидеть ссылку на описание "протокола ascii" ? - жутко интересно
а можно увидеть ссылку на описание "протокола ascii" ? - жутко интересно
Фак, запутали. https://rusautomation.ru/omx-380pm вот тут я увидел что по рске485 он поддерживает аски, и подумал что это протокол.
Есть если я правильно щас понял то это коробка просто отправляет символы в виде чисел на аски таблице? И ардуинка также работает с приложением? Просто это както совсем не явно описано это, то что рска у ардуины 232 это есть, а вот что она шлет неизвестно, есть там какие-то протоколы, нету?
На всякий лучше сделаю свой протокол с контрольной суммой и символами. Есть мысль переводить данные в коды аски таблицы, складывать их и отправлять первой цифровой которую устройство схватит и глянет сходится или нет, ну и спец.символов закрывающих добавить. Модбас например почти как хтмл все тегами делает
//А не получится так что я своим протоколом перебью их протокол, он точно не полезет смотреть данные в которых может найти какой то символ особый который сочтет за команду
Да. Это одна из проблем которую решают при проектировании протоколов. Придуманы несколько подходов
.
//Мдамуж конечно, протокол ascii тогда чем занимается? Я вот смотрел его описание, вроде там все есть, закрывающие и тд вещи.
Это не совсем протокол, но один из.подходов иллюстрирует. Для передачи текста годится. В тексте нет символов совпадающих с этими управляющими. И потому путаница исключена. А как быть с произвольными двоичными данными? Например перекодировать их в текст некоторым образом. Читаем Base64. А можно и другими хитрыми путями.
старайтесь использовать общепринятые термины, если хотите, чтобы вас кто-то понял. Что такое "рска у ардуины 232" -о чем вы вообще? Какое отношение имеет эта ссылка к вашей программе на QT ?
ничего не понял
ничего не понял
Потому что у тебя модбас не тегами.
Можно такой вариант