Я работаю над приложением Windows, которое получает данные от датчика на частоте 600 Гц. В двух из пяти случаев мой поток ввода-вывода успешно считывает 4 байта данных с датчика и передает их в поток графического интерфейса.
Проблема в трех из пяти раз, QSerialPort имеет необъяснимые тайм-ауты, где waitForReadyRead () QSerialPort возвращает false, а serial.errorString () имеет ошибку тайм-аута. В этом случае он никогда не будет читать данные. Если я читаю с последовательного порта, несмотря на ошибку тайм-аута, я буду читать 2000+ байтов данных в следующем waitForReadyRead, который будет доставлен кусками, что делает аспект приема данных в реальном времени моего приложения устаревшим.
Я попытался использовать сигнал readyRead () последовательного порта, но он демонстрирует то же поведение, т.е. если появляется ошибка тайм-аута, сигнал readyRead () никогда не срабатывает.
ОБНОВИТЬ: Я могу воспроизвести проблему с примером терминала Qt ([QT_INSTALL_EXAMPLES] / serialport / терминал), который использует неблокирующее чтение. Частота появления ошибки значительно меньше, но она определенно есть.
ОБНОВИТЬ: Используя Serial Port Monitor, я вижу, что когда он застревает, пример терминала Qt застревает на IOCTL_SERIAL_WAIT_ON_MASK, мой пример застревает на IRP_MJ_WRITE DOWN сразу после IOCT_SERIAL_WAIT_ON_MASK. Этого никогда не происходит с другими терминальными программами, что наводит меня на мысль, что проблема определенно в Qt.
Pastebin выхода монитора последовательного порта
void IOThread::run(){
QSerialPort serial;
serial.setPortName(portname)
serial.setBaudRage(QSerialPort::Baud115200);
serial.setStopBits(QSerialPort::OneStop)
serial.setParity(QSerialPort::NoParity);
serial.setDataBits(QSerialPort::Data8);
serial.setFlowControl(QSerialPort::NoFlowControl);
if(!serial.open(QIODevice::ReadWrite)
{
qDebug() << "Error Opening Port";
return;
}
else
{
qDebug() << "Error Message: " << serial.errorString() // prints "Unknown Error"}
while(true)
{
if(serial.waitForReadyRead(1000))
{
qDebug() << "Normal read";
reception_buffer = serial.readAll();
}
else
{
qDebug() << "Timeout";
/* serial.readAll() here will read nothing but force next read to read huge chunk of data */
continue;
}
}
// Process data...
}
1
Решение
Попробуйте, если это имеет какое-либо значение:
while (true) {
QByteArray reception_buffer;
if (serial.waitForReadyRead(1000)) {
reception_buffer = serial.readAll();
while (serial.waitForReadyRead(10)) {
reception_buffer += serial.readAll();
}
qDebug() << "reception_buffer ready";
}
else {
qDebug() << "Timeout";
}
}
Если вы хотите предотвратить таймаут от waitForReadyRead
Вы можете установить:
if(serial.waitForReadyRead(-1))
bool QSerialPort :: waitForReadyRead (int msecs = 30000) время ожидания истечет через миллисекунды; время ожидания по умолчанию составляет 30000 миллисекунд. Если msecs равен -1, функция не будет иметь тайм-аут.
0
Другие решения
застревает на IOCTL_SERIAL_WAIT_ON_MASK
Скорее всего, проблема в вашем HW или драйвере. QSP использует асинхронное уведомление, основанное на WaitCommEvent. Если WaitCommEvent застревает — проблема в вашем устройстве или драйвере (скорее всего).
0
Спасибо ребятам из QSerialPort, эта ошибка в Qt 5.10.1 решается путем применения этого патча: https://codereview.qt-project.org/#/c/225277/
«QSP может игнорировать все события чтения, когда данные поступают на устройство
в открытии. В этом случае даже повторное открытие устройства не
Помогите. Причина в том, что QWinOverlappedIoNotifier включен после
чем вызывается startAsyncCommunication (), что, вероятно, приводит к
игнорирование для всех событий EV_RXCHAR. Обходной путь должен включить
уведомитель раньше, чем какая-либо из операций ввода / вывода. «- Денис Шиенков, QSerialPort Maintainer
0
Автор | Тема: Проблема с получением данных с помощью QSerialPort::waitForReadyRead() (Прочитано 2993 раз) |
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
|
||||||
Предоставляет функции для доступа к последовательным портам. Больше…
Header: | #include <QSerialPort> |
CMake: | find_package(Qt6 COMPONENTS SerialPort REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::SerialPort) |
qmake: | QT +=последовательный порт |
Since: | Qt 5.1 |
Inherits: | QIODevice |
- Список всех членов,включая унаследованных членов
Примечание. Все функции этого класса реентерабельны .
Public Types
enum | BaudRate { Бод1200, Бод2400, Бод4800, Бод9600, Бод19200, …, Бод115200} |
enum | Биты данных {Данные5, Данные6, Данные7, Данные8} |
enum | Направление {вход, выход, все направления} |
flags | Directions |
enum | FlowControl { NoFlowControl, HardwareControl, SoftwareControl } |
enum | Четность { NoParity, EvenParity, OddParity, SpaceParity, MarkParity} |
enum | PinoutSignal { NoSignal, DataTerminalReadySignal, DataCarrierDetectSignal, DataSetReadySignal, RingIndicatorSignal, …, SecondaryReceivedDataSignal } |
flags | PinoutSignals |
enum | SerialPortError { NoError, DeviceNotFoundError, PermissionError, OpenError, NotOpenError, …, UnknownError } |
enum | StopBits { OneStop, OneAndHalfStop, TwoStop } |
Properties
|
|
Public Functions
Реализованные общественные функции
Signals
Реализованные защищенные функции
virtual qint64 | readData(char *data, qint64maxSize) override |
virtual qint64 | readLineData(char *data, qint64maxSize) override |
virtual qint64 | writeData(const char *data, qint64maxSize) override |
Detailed Description
Вы можете получить информацию о доступных последовательных портах, используя вспомогательный класс QSerialPortInfo , который позволяет перечислить все последовательные порты в системе. Это полезно для получения правильного имени последовательного порта, который вы хотите использовать. Вы можете передать объект вспомогательного класса в качестве аргумента методам setPort () или setPortName () для назначения нужного последовательного устройства.
После настройки порта его можно открыть в режиме только чтения (r/o), только записи (w/o) или чтения-записи (r/w) с помощью метода open ().
Примечание. Последовательный порт всегда открывается с монопольным доступом (то есть никакой другой процесс или поток не может получить доступ к уже открытому последовательному порту).
Используйте метод close (), чтобы закрыть порт и отменить операции ввода-вывода.
После успешного открытия QSerialPort пытается определить текущую конфигурацию порта и инициализируется. Вы можете перенастроить порт на нужный параметр с помощью методов setBaudRate (), setDataBits (), setParity (), setStopBits () и setFlowControl ().
Есть несколько свойств для работы с сигналами распиновки, а именно: QSerialPort::dataTerminalReady , QSerialPort::requestToSend . Также можно использовать метод pinoutSignals () для запроса текущего набора сигналов распиновки.
Как только вы узнаете, что порты готовы к чтению или записи, вы можете использовать методы чтения () или записи (). В качестве альтернативы также могут быть вызваны удобные методы readLine () и readAll (). Если не все данные считываются сразу, оставшиеся данные будут доступны позже, когда новые входящие данные будут добавлены во внутренний буфер чтения QSerialPort. Вы можете ограничить размер буфера чтения с помощью setReadBufferSize ().
QSerialPort предоставляет набор функций,которые приостанавливают вызывающий поток до появления определенных сигналов.Эти функции можно использовать для реализации блокирующих последовательных портов:
- waitForReadyRead () блокирует вызовы, пока новые данные не станут доступны для чтения.
- waitForBytesWritten () блокирует вызовы до тех пор, пока одна полезная нагрузка данных не будет записана в последовательный порт.
См.следующий пример:
int numRead = 0, numReadTotal = 0; char buffer[50]; for (;;) { numRead = serial.read(buffer, 50); numReadTotal += numRead; if (numRead == 0 && !serial.waitForReadyRead()) break; }
Если waitForReadyRead () возвращает false
, соединение закрыто или произошла ошибка.
Если в какой-то момент времени произойдет ошибка, QSerialPort выдаст сигнал errorOccurred (). Вы также можете вызвать error (), чтобы найти тип ошибки, которая произошла последней.
Программирование с блокирующим последовательным портом радикально отличается от программирования с неблокирующим последовательным портом.Блокирующий последовательный порт не требует цикла обработки событий и обычно приводит к более простому коду.Тем не менее,в приложении с графическим интерфейсом пользователя блокирующий последовательный порт должен использоваться только в неграфических потоках,чтобы избежать замораживания пользовательского интерфейса.
Дополнительные сведения об этих подходах см. в примерах приложений.
Класс QSerialPort также можно использовать с потоковыми операторами QTextStream и QDataStream (operator<<() и operator>>()). Однако есть одна проблема, о которой следует помнить: убедитесь, что доступно достаточно данных, прежде чем пытаться читать с помощью перегруженного оператора operator>>().
См. Также QSerialPortInfo .
Тип члена Документация
enum QSerialPort::BaudRate
Это перечисление описывает скорость передачи данных,с которой работает устройство связи.
Примечание. В этом списке перечислены только наиболее распространенные стандартные скорости передачи данных.
Constant | Value | Description |
---|---|---|
QSerialPort::Baud1200 |
1200 |
1200 baud. |
QSerialPort::Baud2400 |
2400 |
2400 baud. |
QSerialPort::Baud4800 |
4800 |
4800 baud. |
QSerialPort::Baud9600 |
9600 |
9600 baud. |
QSerialPort::Baud19200 |
19200 |
19200 baud. |
QSerialPort::Baud38400 |
38400 |
38400 baud. |
QSerialPort::Baud57600 |
57600 |
57600 baud. |
QSerialPort::Baud115200 |
115200 |
115200 baud. |
См. также QSerialPort::baudRate .
enum QSerialPort::DataBits
Это перечисление описывает количество используемых битов данных.
Constant | Value | Description |
---|---|---|
QSerialPort::Data5 |
5 |
Количество бит данных в каждом символе-5.Используется для кода Baudot.Как правило,это имеет смысл только при использовании старого оборудования,такого как телепринтеры. |
QSerialPort::Data6 |
6 |
Количество бит данных в каждом символе-6.Используется редко. |
QSerialPort::Data7 |
7 |
Количество бит данных в каждом символе-7,используется для истинного ASCII.Обычно это имеет смысл только для старого оборудования,такого как телепринтеры. |
QSerialPort::Data8 |
8 |
Количество бит данных в каждом символе-8.Используется для большинства типов данных,так как этот размер соответствует размеру байта.Он почти повсеместно используется в новых приложениях. |
См. также QSerialPort::dataBits .
enum QSerialPort::Направления флагов QSerialPort::Направления
Это перечисление описывает возможные направления передачи данных.
Примечание. Это перечисление используется для установки скорости передачи данных устройства отдельно для каждого направления в некоторых операционных системах (например, в POSIX-подобных).
Constant | Value | Description |
---|---|---|
QSerialPort::Input |
1 |
Input direction. |
QSerialPort::Output |
2 |
Output direction. |
QSerialPort::AllDirections |
Input | Output |
Одновременно в двух направлениях. |
Тип Directions — это typedef для QFlags <Direction>. Он хранит комбинацию значений направления ИЛИ.
enum QSerialPort::FlowControl
Это перечисление описывает используемое управление потоком.
Constant | Value | Description |
---|---|---|
QSerialPort::NoFlowControl |
0 |
Нет управления потоком. |
QSerialPort::HardwareControl |
1 |
Аппаратное управление потоком (RTS/CTS). |
QSerialPort::SoftwareControl |
2 |
Программное управление потоком (XON/XOFF). |
См. также QSerialPort::flowControl .
enum QSerialPort::Parity
Это перечисление описывает используемую схему четности.
Constant | Value | Description |
---|---|---|
QSerialPort::NoParity |
0 |
Нет бита четности,который он отправил.Это наиболее распространенная установка четности.Обнаружение ошибок обрабатывается протоколом связи. |
QSerialPort::EvenParity |
2 |
Количество битов в каждом символе,включая бит четности,всегда равномерно. |
QSerialPort::OddParity |
3 |
Количество битов в каждом символе,включая бит четности,всегда нечетное.Это гарантирует,что в каждом символе происходит хотя бы один переход из одного состояния в другое. |
QSerialPort::SpaceParity |
4 |
Пространственный паритет.Бит четности посылается в состоянии пробельного сигнала.Он не предоставляет информацию об обнаружении ошибок. |
QSerialPort::MarkParity |
5 |
Марк паритета.Бит четности всегда устанавливается в состояние сигнала метки (логическое 1).Он не предоставляет информацию об обнаружении ошибок. |
См. также QSerialPort::parity .
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qserialport.html
Qt
6.2
-
QSequentialAnimationGroup Class
Класс QSequentialAnimationGroup предоставляет анимации.
-
QSequentialIterable Class
Класс QSequentialIterable является интерфейсом для контейнера QVariant.
-
enum QSerialPort::PinoutSignalflags QSerialPort::PinoutSignals
Это перечисление описывает возможные сигналы пинаута RS-232.
-
bool QSerialPort::clear(направления = AllDirections)
Отбрасывает все символы из выходного или входного буфера, в зависимости от заданных направлений. Примечание. Последовательный порт должен быть открыт, прежде чем пытаться очистить буфер.
QSerialPort Class Reference
[QtBaseModule]
The QSerialPort class provides a simple serial device interface. More…
#include <QSerialPort>
Inherits QSerialIODevice.
- List of all members, including inherited members
Public Functions
-
QSerialPort ( const QString & device, int rate = 38400, bool trackStatus = false )
-
virtual void close ()
-
int fd () const
-
bool open ( OpenMode mode )
-
32 public functions inherited from QIODevice
-
29 public functions inherited from QObject
Static Public Members
-
QSerialPort * create ( const QString & name, int defaultRate = 115200, bool flowControl = false )
-
4 static public members inherited from QObject
Additional Inherited Members
-
1 property inherited from QObject
-
1 public slot inherited from QObject
-
1 signal inherited from QObject
-
1 public type inherited from QObject
-
5 protected functions inherited from QIODevice
-
7 protected functions inherited from QObject
-
2 protected variables inherited from QObject
Detailed Description
The QSerialPort class provides a simple serial device interface.
This class manages a very simple serial device, which is accessed at a specific baud rate with no parity, 8 data bits, and 1 stop bit. It is intended for communicating with GSM modems and the like.
The recommended way to create an instance of this class is to call the QSerialPort::create() method.
See also QSerialPort::create() and QSerialIODevice.
Member Function Documentation
QSerialPort::QSerialPort ( const QString & device, int rate = 38400, bool trackStatus = false )
Construct a new serial device handler object for the specified device at the given rate. After construction, it is necessary to call QSerialPort::open() to complete initialization.
If trackStatus is true, then the device should attempt to track changes in DSR, DCD, and CTS. This may require the use of a regular timeout, which will be detrimental to battery life.
Status tracking should only be enabled when absolutely required. It isn’t required for modems that support GSM 07.10 multiplexing, as the multiplexing mechanism has its own method of tracking status changes that does not require the use of a timeout.
The device name is usually something like /dev/ttyS0, but it can have the special form sim:hostname, where hostname is the name of a host running a phone simulator daemon (usually localhost). The phone simulator mode is intended for debugging purposes only.
QSerialPort::~QSerialPort ()
Destruct this serial device. If the device is currently open, it will be closed.
void QSerialPort::close () [virtual]
Closes the serial device.
Reimplemented from QIODevice.
QSerialPort * QSerialPort::create ( const QString & name, int defaultRate = 115200, bool flowControl = false ) [static]
Create and open a serial device from a name of the form device:rate. Returns NULL if the device could not be opened. The defaultRate parameter indicates the default rate to use if :rate was not included in the device name. If flowControl is true, then CTS/RTS flow control should be enabled on the device.
The name parameter can have the special form sim:hostname, where hostname is the name of a host running a phone simulator daemon (usually localhost). The phone simulator mode is intended for debugging purposes only.
int QSerialPort::fd () const
Returns the operating system file descriptor for this serial port, or -1 if the port is currently closed.
This function was introduced in Qtopia 4.3.
bool QSerialPort::flowControl () const
Returns the state of CTS/RTS flow control on the serial device. The default value is false.
See also setFlowControl().
bool QSerialPort::flush ()
Returns true if able to flush all buffered data to the physical serial device; otherwise returns false.
bool QSerialPort::keepOpen () const
Returns true if tty devices should be kept open on a zero-byte read; otherwise returns false. The default value is true.
Some serial devices return zero bytes when there is no data available, instead of returning the system error EWOULDBLOCK. When keepOpen() is true, a zero-byte read will be treated the same as EWOULDBLOCK. When keepOpen() is false, a zero-byte read will be interpreted as an unrecoverable error and the serial port will be closed.
For Bluetooth RFCOMM sockets, keepOpen() should be false.
The keepOpen() state is ignored if the underlying serial device is a socket connection to a phone simulator.
See also setKeepOpen().
bool QSerialPort::open ( OpenMode mode )
Opens the serial device with the specified mode. Returns true if the device could be opened; false otherwise.
void QSerialPort::setFlowControl ( bool value )
Sets the state of CTS/RTS flow control on the serial device to value. This must be called before QSerialPort::open(). Changes to the value after opening will be ignored.
See also flowControl().
void QSerialPort::setKeepOpen ( bool value )
Sets the keep open flag to value. The default value is true.
Some serial devices return zero bytes when there is no data available, instead of returning the system error EWOULDBLOCK. When value is true, a zero-byte read will be treated the same as EWOULDBLOCK. When value is false, a zero-byte read will be interpreted as an unrecoverable error and the serial port will be closed.
For Bluetooth RFCOMM sockets, value should be false.
The state of value is ignored if the underlying serial device is a socket connection to a phone simulator.
See also keepOpen().
Copyright © 2009 Trolltech | Trademarks |
Qt Extended 4.4.3 |