Связь Arduino-C++ не читать Arduino

У меня есть следующий код:

QSerialPort arduPort("COM5");
arduPort.setBaudRate(QSerialPort::Baud9600);
arduPort.setDataBits(QSerialPort::Data8);
arduPort.setParity(QSerialPort::NoParity);
arduPort.setStopBits(QSerialPort::OneStop);
arduPort.setFlowControl(QSerialPort::NoFlowControl);
arduPort.open(QSerialPort::ReadWrite);
cout<<arduPort.isReadable()<<endl;
cout<<arduPort.isWritable()<<endl;
arduPort.write("a");
QByteArray s=arduPort.readAll();

cout<<QString(s).toStdString()<<endl;

И следующий код в Arduino:

int inByte = 0;

void setup()
{
    Serial.begin(9600);
    while(!Serial){;}
    int i=0;
}

void loop()
{
     if(Serial.read()=='a')
         Serial.write('b');  
}

Сначала я посылаю Arduino «a», а ARduino должен ответить «b». Но когда я читаю порт Arduino, я получаю только ''.

Кто-нибудь знает, почему я получаю '' вместо 'b'? Спасибо за ваше время.


person Elseine    schedule 16.09.2013    source источник
comment
Во-первых, попробуйте это с последовательным монитором IDE. После этого теста вы узнаете, является ли виновником код Arduino или код вашего ПК.   -  person Udo Klein    schedule 16.09.2013
comment
Тогда это не проблема Arduino, а проблема с вашим кодом C++. Поскольку вы не даете много подробностей об этом, никто без ясновидения не сможет ответить на этот вопрос. Очевидно, что это должно иметь какое-то отношение к классу QSerialPort и тому, как вы его вызываете.   -  person Udo Klein    schedule 18.09.2013
comment
а какие детали нужны?   -  person Elseine    schedule 19.09.2013
comment
Вы можете установить параметры последовательного порта только после открытия порта, точно так же, как ведут себя собственные операции. Мы можем рассмотреть возможность кэширования этого для релиза следующим летом, но это было бы слишком навязчиво для Qt 5.1. если я что-то упустил, как будет реализовано кеширование. По общему признанию, мы могли бы документировать статус-кво немного лучше. Я постараюсь вскоре внести изменения в документацию для gerrit. :) Вот соответствующий отчет для отслеживания этого случая: bugreports.qt-project.org/ browse/QTBUG-33774 Приносим извинения за неудобства.   -  person lpapp    schedule 01.10.2013


Ответы (3)


Обновление: ответ см. в нижней части этого ответа. TL;DR: вы установили скорость передачи данных (и, предположительно, все остальные настройки) после открытия порта.

Я считаю, что это ошибка в реализации QSerialPort для Windows. Я еще не смог сузить причину, но у меня есть следующие симптомы:

  1. Загрузите в Arduino (в моем случае Uno; Leonardo может вести себя совсем по-другому) демо ASCII. Отключите и снова подключите Arduino. Обратите внимание, что индикатор TX не загорается.

  2. Подключитесь к нему с помощью Putty или монитора последовательного порта Arduino. Это сбрасывает Arduino, а затем печатает таблицу ASCII. Индикатор TX горит постоянно, как и ожидалось.

  3. Отключите/переподключите Arduino и на этот раз подключитесь к нему с помощью программы QSerialPort. На этот раз, несмотря на то, что порт открыт нормально, индикатор TX никогда не загорается, а readyRead() никогда не срабатывает. Также обратите внимание, что Arduino не сбрасывается, потому что по умолчанию QSerialPort не изменяет DTR. Если вы сделаете QSerialPort::setDataTerminalReady(false);, затем сделаете паузу на 10 мс, а затем установите true, он будет перезагружать Arduino, как и ожидалось, но он все еще не передает.

  4. Обратите внимание, что если у вас есть программа Arduino, которая непрерывно передает данные (пример ASCII останавливается), если вы откроете порт с помощью putty, чтобы он начал передачу, а затем откроете его с помощью QSerialPort, не отсоединяя кабель, он будет работать. ! Однако, как только вы отключаете/подключаете кабель, он снова перестает работать.

Это заставляет меня подозревать, что замазка устанавливает какой-то параметр последовательного порта, который требуется Arduino, и сбрасывается при повторном подключении кабеля. QSerialPort, очевидно, не изменяет это значение.

Насколько я могу судить, вот настройки, используемые Putty:

dcb.fBinary = TRUE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fDsrSensitivity = FALSE;
dcb.fTXContinueOnXoff = FALSE;
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
dcb.fAbortOnError = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.BaudRate = ...;
dcb.ByteSize = ...;

И QSerialPort:

dcb.fBinary = TRUE;
dcb.fDtrControl = unchanged!
dcb.fDsrSensitivity = unchanged!
dcb.fTXContinueOnXoff = unchanged!
dcb.fOutX = FALSE;
dcb.fInX = FALSE;
dcb.fErrorChar = FALSE;
dcb.fNull = FALSE;
dcb.fRtsControl = RTS_CONTROL_DISABLE;
dcb.fAbortOnError = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fOutxDsrFlow = unchanged!
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.BaudRate = ...;
dcb.ByteSize = ...;

Поэтому я думаю, что это должно быть одно из тех неизменных значений, которые заставляют Arduino думать, что он не подключен. Из документации DCB Подозреваю fTxContinueOnXoff.

Хорошо, я собираюсь написать небольшую программу, чтобы прочитать эти настройки и посмотреть, что изменится.

Обновление 1

Хорошо, я написал свою программу и сделал следующее открытие. Различия после запуска putty и только моей программы Qt:

  • BaudRate: ЭТО БЫЛО УСТАНОВЛЕНО НЕ QT!!!!!!! Оказывается, вы можете установить скорость передачи только после открытия порта. В противном случае при первом подключении кабеля остается предыдущее значение, равное 0.
  • fDtrControl: установите значение 1 для Putty, оставив значение 0 для Qt.
  • fOutX и fInX: Оба также установлены в 1 Putty и оставлены в 0 Qt.

После перемещения всех моих вызовов функций set...() после открытия все заработало отлично. Мне не пришлось возиться с DtrControl или Out/InX. (Хотя я также установил высокое значение DTR вручную.)

Обновление 2

При настройке всех параметров я подумал, что было бы неплохо установить политику ошибок на «пропустить». НЕ ДЕЛАЙТЕ ЭТОГО! ОСТАВЬТЕ ЭТО В ИГНОРЕ! В противном случае это все испортит и добавит странные задержки ко всем вашим сообщениям.

person Timmmm    schedule 01.10.2013

Установка портов перед открытием не совсем возможна до Qt 5.2. Причина в том, что первоначальный дизайн был слишком низкоуровневым для класса, достаточно объектно-ориентированного. Я долго думал, менять ли его, и в конце концов я действительно решил это сделать.

Я только что представил изменение, которое сейчас находится на рассмотрении кода, которое также заставит вашу первоначальную концепцию работать.

Здесь вы можете найти подробности:

Сделайте возможность установки значений порта перед открытием

Резюме можно прочитать здесь для изменения:

Сделать возможность установки значений портов перед открытием

Этот патч также изменяет поведение открытого метода. Мы больше не используем обнаружение портов навсегда. Это была сломанная концепция, и очень маловероятно, что кто-то когда-либо полагался на нее. Если бы кто-то это сделал, у него все равно были бы проблемы, ненужные шумные предупреждения и все такое.

Другой вариант также рассматривался, чтобы оставить это поведение необязательным по умолчанию, но это слишком усложнило бы API без особого выигрыша.

Настройки порта по умолчанию теперь также нормальные 9600,8,N,1 и без управления потоком. Также обратите внимание, что последовательный порт автоматически закрывается в открытом методе, если какая-либо из настроек не удалась.

Пожалуйста, обновите свою версию Qt (по крайней мере, до Qt 5.2) или вы можете сделать это самостоятельно. Тогда можно написать такой код и даже рекомендуется:

QSerialPort arduPort("COM5");
arduPort.setBaudRate(QSerialPort::Baud9600);
arduPort.setDataBits(QSerialPort::Data8);
arduPort.setParity(QSerialPort::NoParity);
arduPort.setStopBits(QSerialPort::OneStop);
arduPort.setFlowControl(QSerialPort::NoFlowControl);
arduPort.open(QSerialPort::ReadWrite);
person lpapp    schedule 03.03.2014
comment
lpapp, я не понизил голос, этот комментарий является результатом процесса проверки SO, и когда я его просмотрел, это было два предложения о запросе на изменение, который вы отправили, второе, которое было ссылкой (теперь пункты 2- 4 вашего текущего ответа), который мне показался не ответом на вопрос (причина только ссылки была не моей, а Макиена, и ответы должны быть как можно более автономными). Так что я не могу удалить отрицательный голос, но, учитывая, что теперь вы предоставили больше мяса в ответе, он выглядит лучше. - person paxdiablo; 24.12.2014

BaudRate: ЭТО БЫЛО УСТАНОВЛЕНО НЕ QT!!!!!!! Оказывается, вы можете установить скорость передачи данных только после того, как откроете порт. В противном случае она остается на предыдущем значении, равном 0, когда вы впервые подключаете кабель.

Да, это правда. Но это было исправлено и будет доступно в Qt 5.3.

fDtrControl: установите значение 1 для Putty, оставив значение 0 для Qt.

Нет. Qt не трогайте сигнал DTR при открытии. Этот сигнал будет очищен, только если для него установлено значение DTR_CONTROL_HANDSHAKE. Поскольку QtSerialPort не поддерживает управление потоком DTR/DSR. Так что в любом случае вы можете управлять DTR с помощью QSerialPort::setDataTerminalReady(bool).

PS: я имею в виду текущую версию Qt 5.3

fOutX и fInX: Оба также установлены в 1 Putty и оставлены в 0 Qt.

Этот флаг используется только тогда, когда вы используете управление потоком QSerialPort::Software (Xon/Xoff). Но вы используете QSerialPort::NoFlowControl (как я вижу из вашего фрагмента кода), так что все в порядке. Поэтому убедитесь, что вы также используете Putty с управлением потоком «Нет».

При настройке всех параметров я подумал, что было бы неплохо установить политику ошибок на «пропустить».

Используйте только политику QSerialPort::Ignore (по умолчанию). Поскольку другие политики устарели (все политики) и будут удалены в будущем.

УПД:

dcb.fRtsControl = RTS_CONTROL_ENABLE;

Ах, кажется, ваш Arduino ожидает, что сигнал RTS должен быть включен по умолчанию. В этом случае вы должны использовать QSerialPort::setRequestToSend(bool). Но это возможно только в режиме QSerialPort::NoFlowControl.

т.е. RTS всегда будет в состоянии RTS_CONTROL_DISABLE или RTS_CONTROL_HANDSHAKE после открытия порта (зависит от ваших настроек FlowControl, QSerialPort::setFlowControl() ).

person Denis Shienkov    schedule 21.04.2014