I'm writing a Qt GUI application that receives and sends data to an Arduino over serial. It writes correctly, but when trying to read it doesn't work.
My problem is:
I have an Arduino code that sends things over Serial, I programmed it to turn on and off a LED on pin 13 depending on the received data:
#define ARDUINO_TURNED_LED_ON "LEDON"
#define ARDUINO_TURNED_LED_OFF "LEDOFF"
#define PC_REQUESTED_LED_STATE_CHANGE u8"CHANGELED"
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
String serialCmd = "";
bool ledState=false;
void loop()
{
// put your main code here, to run repeatedly:
if (Serial.available())
{
serialCmd=Serial.readString();
if (serialCmd==PC_REQUESTED_LED_STATE_CHANGE)
{
if (ledState)
{
digitalWrite(13, LOW);
Serial.write(ARDUINO_TURNED_LED_OFF);
}
else
{
digitalWrite(13, HIGH);
Serial.write(ARDUINO_TURNED_LED_ON);
};
ledState=!ledState;
serialCmd = "";
}
}
}
I'm using the following signal and slot at MainWindow class:
#define ARDUINO_TURNED_LED_ON "LEDON"
#define ARDUINO_TURNED_LED_OFF "LEDOFF"
#define PC_REQUESTED_LED_STATE_CHANGE u8"CHANGELED"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/* Create Object the Class QSerialPort*/
serialPort = new QSerialPort(this);
/* Create Object the Class Arduino to manipulate read/write*/
arduino = new Arduino(serialPort);
//connect signal:
connect(serialPort, SIGNAL(readyRead()), this, SLOT(ReadData()));
}
//slot
void MainWindow::ReadData()
{
QString received = arduino->Read();
qDebug() << "received data:" << received;
if (received==ARDUINO_TURNED_LED_ON)
{
qDebug() << "led on";
}
else if (received==ARDUINO_TURNED_LED_OFF)
{
qDebug() << "led off";
}
}
And the Arduino::Read() method that is called by the previous slot:
QString Arduino::Read()
{
QString bufRxSerial;
qDebug() << "bytes available:" << serialPort->bytesAvailable();
/* Awaits read all the data before continuing */
while (serialPort->waitForReadyRead(20)) {
bufRxSerial += serialPort->readAll();
}
return bufRxSerial;
}
When writing to the Arduino it works well, the LED changes as it should, the problem happens when Qt tries to read the replied data.
In most of the times that the Arduino sends something, the signal is emitted and serialPort->bytesAvailable() returns a number that is not zero, but
serialPort->waitForReadyRead(20) times out without receiving anything and serialPort->readAll() returns an empty QString. If I use serialPort->waitForReadyRead(-1) the window freezes.
The weirdest thing is that, in a random moment that something is sent, everything works well and the function returns all the data that couldn't be read previously.
Here's an example of what happens:
1st attempt (fails)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns on)
Arduino writes ARDUINO_TURNED_LED_ON ("LEDON") to the serial port
Qt reads an empty QString from the Arduino
2nd attempt (fails)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns off)
Arduino writes ARDUINO_TURNED_LED_OFF ("LEDOFF") to the serial port
Qt reads an empty QString from the Arduino
3rd attempt (this is a random attempt that everything works)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns on)
Arduino writes ARDUINO_TURNED_LED_ON ("LEDON") to the serial port
Qt reads "LEDONLEDOFFLEDON" from the Arduino, that is everything that couldn't be read previosly.
4th attempt (fails)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns off)
Arduino writes ARDUINO_TURNED_LED_OFF ("LEDOFF") to the serial port
Qt reads an empty QString from the Arduino
5th attempt (this is another random attempt that everything works)
Qt writes PC_REQUESTED_LED_STATE_CHANGE (u8"CHANGELED") to the serial port
Arduino LED changes its state (turns on)
Arduino writes ARDUINO_TURNED_LED_ON ("LEDON") to the serial port
Qt reads "LEDOFFLEDON" from the Arduino, that is everything that couldn't be read previosly.
I tested using the Arduino IDE serial monitor and it worked as it was supposed to be: I wrote "CHANGELED", then the LED changed and the Arduino replied "LEDON" or "LEDOFF" all the times.
What can I do to solve this problem?
Thanks
Edit: the complete code can be found here
The Read method is incorrect and unnecessary. You should never use the waitFor methods. You also shouldn't be using QString when dealing with simple ASCII data that QByteArray handles fine:
class MainWindow : ... {
QByteArray m_inBuffer;
...
};
void MainWindow::ReadData() {
m_inBuffer.append(arduino->readAll());
QByteArray match;
while (true) {
if (m_inBuffer.startsWith((match = ARDUINO_TURNED_LED_ON))) {
qDebug() << "led on";
} else if (m_inBuffer.startsWith((match = ARDUINO_TURNED_LED_OFF))) {
qDebug() << "led off";
} else {
match = {};
break;
}
}
m_inBuffer.remove(0, match.size());
}
The deal is simple: ReadData can be called with any number of bytes available - even a single byte. Thus you must accumulate data until a full "packet" is received. In your case, packets can only be delineated by matching a full response string.
You'd make your life much easier if Arduino sent full lines - replace Serial.write with Serial.println. Then the lines are packets, and you don't need to buffer the data yourself:
void MainWindow::ReadData() {
while (arduino->canReadLine()) {
auto line = arduino->readLine();
line.chop(1); // remove the terminating '\n'
QDebug dbg; // keeps everything on a single line
dbg << "LINE=" << line;
if (line == ARDUINO_TURNED_LED_ON)
dbg << "led on";
else if (line == ARDUINO_TURNED_LED_OFF)
dbg << "led off";
}
}
See? It's much simpler that way.
You can also leverage Qt to "simulate" Arduino code without running real Arduino hardware, see this answer for an example.
This sounds like a buffering problem. Your Qt application receives the bytes, but there is nothing that tells it the reception is complete. I would add line feeds (\n) as terminator character after each string, just use Serial.println() instead of Serial.write(). Then you can use readLine() in Qt and always be sure that what you get is exactly one complete command string.
If you're on Linux you could also try to stty your device to raw with
stty -F /dev/ttyACM0 raw
to have the serial characters sent straight through instead of default line buffering (see What’s the difference between a “raw” and a “cooked” device driver?).
Note that then you might get a new issue: Your Qt application might be so fast that you receive only one letter at a time in your callback.
Related
I'm working on a windows application that receives data from a sensor at 600Hz. In two out of five cases, my IO thread reads the 4 bytes of data from the sensor successfully and passes it on to the GUI thread.
The problem is three out of five times, QSerialPort has inexplicable timeouts where QSerialPort's waitForReadyRead() returns false and serial.errorString() has a timeout error. In which case it will never read data. If I read from the serial port despite the timeout error I will read 2000+ bytes of data in the next waitForReadyRead which will be delivered in chunks which renders the realtime data reception aspect of my application obsolete.
I've tried using the readyRead() signal of the serial port but it exhibits the same behaviour ie. if the timeout error appears, no readyRead() signal is ever fired.
UPDATE: I am able to reproduce the issue with Qt's terminal example ([QT_INSTALL_EXAMPLES]/serialport/terminal) which uses a non-blocking read. The frequency of the bug is considerably less but it's definitely still there.
UPDATE: Using Serial Port Monitor, I can see that when it gets stuck, the Qt Terminal Example gets stuck on IOCTL_SERIAL_WAIT_ON_MASK, my example gets stuck on IRP_MJ_WRITE DOWN just after the IOCT_SERIAL_WAIT_ON_MASK. This never happens with other terminal softwares leading me to think the problem is definitely with Qt.
Pastebin of Serial Port Monitor Output
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...
}
Try if this makes any difference:
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";
}
}
If you want to prevent from timeouting from waitForReadyRead you can set:
if(serial.waitForReadyRead(-1))
bool QSerialPort::waitForReadyRead(int msecs = 30000) will timeout after msecs milliseconds; the default timeout is 30000 milliseconds. If msecs is -1, the function will not time out.
gets stuck on IOCTL_SERIAL_WAIT_ON_MASK
Most likelly a problem is in your HW or driver. QSP use asynchronous notification, based on WaitCommEvent. If WaitCommEvent get stuck - then a problem is in your device or driver (most likelly).
Thanks to the guys at QSerialPort, this bug in Qt 5.10.1 is solved by applying this patch: https://codereview.qt-project.org/#/c/225277/
"QSP may ignore all the read events when the data comes to the device
within opening. In this case, even re-opening of a device does not
help. Reason is that the QWinOverlappedIoNotifier is enabled after
than the startAsyncCommunication() called, that probably, leads to
ignoring for all EV_RXCHAR events. A workaround is to enable the
notifier before than any of I/O operation called." - Denis Shienkov, QSerialPort Maintainer
I've been trying to do a Lights GUI with an Arduino Mega 2560 with its Xbee Shield and two Xbee Pro S1, one connected to the Arduino and the other one to the PC. My problem is: however I can send data from Qt to my arduino and read it, i can't do the same in the other way. When trying to send a String as "Confirmado\r\n", it arrives to my Qt label wrong, sometimes I get the full String, other ones I receive half of it.
My arduino code is
char buffer[50];
String trama, dir, com, data;
int indexdir, indexcom, indexdata;
void setup(){
Serial.begin(9600);
}
void loop(){
trama= "Confirmado\r\n";
const char *bf = trama.c_str();
if(Serial.available() > 0)
{
Serial.readBytesUntil('/', buffer,500);
Serial.print(bf);
Serial.flush();
}
}
My Qt QSerialPort config is
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
serial = new QSerialPort(this);
serial->setPortName("COM3"); //COM-port your Arduino is connected to
serial->open(QIODevice::ReadWrite);
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
connect(serial,SIGNAL(readyRead()),this,SLOT(serialReceived()));
}
And I send and read data like this
void MainWindow::serialReceived()
{
QByteArray readData = serial->readAll();
//while (serial->waitForReadyRead(500))
// readData.append(serial->readAll());
ui->label->setText(readData);
}
void MainWindow::writeData(const QByteArray &data)
{
serial->write(data);
serial->flush();
serial->waitForBytesWritten(500);
}
The toogle lines means I've tried both options...
I've noticed, doing Debug, that if I place a breakpoint in ui->label->setText(readData);; if it doesnt arrive well (the full "Confirmado\r\n" string), this breakpoint gets twice in this line, the first one readData equals the second half of the string (i.e "mado\r\n") and the other one it values the rest of the string (i.e "Confir").
I've also tried to set a higher baudrate, 57600, but I cant send or receive any data, though I've set the baudrate in the XCTU app before.
Does anyone know a way to receive the full string from Arduino? Or at leats how to setup properly Arduino's and PC's Xbee to work with higher baudrates?
Thanks for the answers, and sorry for my writing skills...
Try use serial->readLine() instead of serial->readall() you can for example wait in loop after the serial->canReadLine() returns the true then you be sure that the data are you received is a full string.
So, I've built a basic QT GUI where I want to establish communication with an Arduino Nano through USB. I send a number through the GUI and the Arduino receives the number and processes it.
The communication works fine when I upload the code to Arduino and right afterwards open the GUI and start the process. However, when I disconnect the Arduino from the USB (or restart my PC - I've tried both) and reconnect it to use it with the GUI, the Arduino behaves like it received nothing.
More specifically, in the first case Serial.available() returns "1" as it receives the number properly, but in the latter case it returns "0", so it does nothing.
I made the code as simple as I could trying to track down the issue and the problem continues.
So here is the main QT GUI code:
depth_ = insertDepthEdit->text().toInt(); // user input from GUI
myThread *mThread;
mThread = new myThread(this, depth_);
connect(mThread, SIGNAL(valueRead(QString)), this, SLOT(onTextChange(QString)));
//valueRead is the signal emitted from Arduino
//onTextChange the function that processes the received string
mThread->start();
mThread->wait(100);
mThread->quit();
The Arduino thread code (also QT):
void myThread::run() {
QSerialPort serial;
serial.setPortName("COM3");
serial.setBaudRate(QSerialPort::Baud9600);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.setFlowControl(QSerialPort::NoFlowControl);
serial.open(QIODevice::ReadWrite);
if (serial.isOpen() && serial.isWritable()) {
qDebug() << "Ready to write..." << endl;
QByteArray ba(QString::number(depth_).toStdString().c_str());
qDebug() << ba << endl;
serial.write(ba);
if (serial.bytesToWrite() > 0) {
serial.flush();
if (serial.waitForBytesWritten(1000)) {
qDebug() << "data has been sent" << endl;
}
}
if (serial.flush()) {
qDebug() << "ok" << endl;
}
}
else {
qDebug() << "Error";
}
if (serial.isOpen() && serial.isReadable()) {
qDebug() << "Ready to read..." <<endl;
while (serial.waitForReadyRead(5000)) {
QByteArray inByteArray = serial.readLine();
input_ = QString(inByteArray);
qDebug() << input_;
qDebug() << "ok" << endl;
emit valueRead(input_);
}
}
serial.close();
}
And finally the Arduino code:
int c = 0;
const int ledPin = 13;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.print(Serial.available());
while (Serial.available() > 0) {
digitalWrite(ledPin, HIGH);
delay(5);
c = Serial.read() - '0';
Serial.flush();
}
delay(1000);
digitalWrite(ledPin, LOW);
delay(500);
}
When I upload the code to Arduino, it functions properly no matter if I close the GUI and restart it. The problem happens only if Arduino loses power, e.g: when I disconnect it from USB or restart the PC.
~~~~~~~~~~~~~~~~~~~~~~~~~~EDIT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
COM port remains the same after reconnecting and Arduino Rx LED flashes normally when I send data through the GUI.
~~~~~~~~~~~~~~~~~~~~~~~~~~EDIT 2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OK, so, I tried using the code from Arduino Serial documentation and the problem remains. When I upload the code the Arduino receives the character properly and turns the LED on, but once I disconnect it and then connect it back, it does nothing, the LED remains low as it never enters "if".
Here's the code I used:
int incomingByte = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
digitalWrite(13, HIGH);
incomingByte = Serial.read();
}
}
~~~~~~~~~~~~~~~~~~~~~~EDIT 3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So I have the following 3 scenarios:
Use Scenario A:
Upload code
Run GUI
Send data - It receives properly
Disconnect and reconnect
Run GUI again
Send data - RX blinks but Serial.available returns 0
Use Scenario B:
Upload code
Run Brays
Send data - It receives properly
Disconnect and reconnect
Run Brays again
Send data - It receives properly
Use Scenario C (the most interesting) :
Upload code
Run GUI
Send data - It receives properly
Disconnect and reconnect
Run Brays this time
Send data - It receives properly
Run GUI again after Brays
Send data - It receives properly
I also made the QT GUI code as simple as that but the problem persists:
void myThread::run()
{
QSerialPort *serial = new QSerialPort();
serial->setPortName("COM3");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->open(QIODevice::WriteOnly);
if (serial->isOpen() && serial->isWritable())
{
QByteArray ba(QString::number(depth_).toStdString().c_str());
serial->write(ba);
serial->flush();
serial->close();
}
delete serial;
}
~~~~~~~~~~~~~~~~~~~~~~EDIT 4~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So after much effort and curiosity, I realized that the source of the problem is not the Arduino code but something related to QT or Windows. I added the delays that Jeff recommended and noticed that each time it functioned properly Rx blinked and LED became high as indicated by the code. However, after reconnecting, the problem still remained but I noticed that, this time, immediately after clicking "Send" to send the characters, the LED blinked for some milliseconds (possibly indicating some error??) and then after the 1 second delay the Rx blinked indicating the receipt of data and LED remained LOW as Serial.available remained 0.
So, what I tried next, was to remove one line of code at a time to see what causes the problem. And I ended up with literally blank Arduino code, just empty setup and loop methods, and the following QT GUI code:
void myThread::run()
{
QSerialPort *serial1 = new QSerialPort();
serial1->setPortName("COM5");
serial1->open(QIODevice::WriteOnly);
serial1->close();
}
To summarize, what happens now is:
Upload code to Arduino
Run GUI
Send data
Nothing happens (normal behaviour)
Disconnect and reconnect Arduino to USB
Run GUI
Send data
Arduino LED momentarily blinks once (possibly indicating some kind of error)
OK, so, after hours of debugging I've found what caused the problem.
The root of it was that after reconnecting the Arduino, each time I called serial.open in QT, Arduino did a reset (indicated by the blink of the LED) and by the time it was after the bootloader stage and was running the code, the main program had already passed the serial.write QT command without receiving the data.
So, what I did to solve the problem was to just add a Sleep(uint(2000)); after serial.open in order to let Arduino finish booting and then start sending data.
Thank you all for your help and immediate answers!
In my experience, the issue is not the code in the Arduino. It is because the serial port gets a different name when it is plugged back in.
For example in Linux, originally the port is /dev/ARD0, but when it is disconnected and plugged back in with connections on ARD0, the new plugin is named /dev/ARD1. (In Windows, it might be COM17 then COM18.)
The only way I know to make it become the original port name is to close everything that is connected to it before plugging in again: Close the Arduino IDE, close all programs which have opened the port, etc.
If you use this example for the Arduino Serial documentation do you receive the chars you send?
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Grasping at straws here, replace my comments below a one second delay. Editing on iPhone messed with the format a little, but I believe you can see my intent.
Edit: Also, I think you should not do serial->close inside your loop. I would also try sending a single character repeatedly until we have that working.
void myThread::run()
{
QSerialPort *serial = new QSerialPort();
serial->setPortName("COM3");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->open(QIODevice::WriteOnly);
if (serial->isOpen() && serial->isWritable())
{
QByteArray ba(QString::number(depth_).toStdString().c_str());
serial->write("x");
delay 1 second here
serial->flush();
delay 1 second here
}
serial->close();
delay 1 second here
delete serial;
}
I'm trying to write \ read from a serial device using a usb / rs 232 cable.
I'm pretty sure that my code writes " #002s " (this is a control code) to the serial device, because
a) the serial port is open
b) the serial port is writable
c) the code successfully navigates "wait For Bytes Written (-1)"
d) when using a serial port sniffer the data is successfully written.
The issue I have is that I don't receive any data, and no data is being emitted from the other device. When using qt terminal writing the same " #002s " produces the correct response.
Any ideas?
many thanks.
#include "test_serial.h"
#include "ui_test_serial.h"
#include <QtSerialPort/QtSerialPort>
#include <QDebug>
QSerialPort *serial;
Test_Serial::Test_Serial(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Test_Serial)
{
ui->setupUi(this);
serial = new QSerialPort(this);
connect(serial,SIGNAL(readyRead()),this,SLOT(serialReceived()));
serial->setPortName("COM1");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
serial->open(QIODevice::ReadWrite);
if (serial->isOpen() && serial->isWritable())
{
QByteArray input;
input = "#";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "0";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "0";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "2";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "s";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "\r";
serial->write(input);
serial->waitForBytesWritten(-1);
serial->flush();
serial->waitForReadyRead(100);
QByteArray output = serial->readAll();
ui->label_2->setText(output);
}}
Test_Serial::~Test_Serial()
{
delete ui;
serial->close();
}
void Test_Serial::serialReceived()
{
QByteArray output;
output = serial->readAll();
ui->label->setText("output");
}
If you want to write " #002s ", Why not write at once? May be the serial device cant identify the control code when you write each character.
void Test_Serial::writeDataToSerialPort()
{
QByteArray input = QString("#002s").toLocal8Bit();
serial->write(input);
}
And no need for this reading part .
serial->waitForReadyRead(100);
QByteArray output = serial->readAll();
ui->label_2->setText(output);
The Test_Serial::serialReceived will be called any way when you have the response from the serial device.
And you can catch the error on opening the port by using the error signal from QSerialPort
connect(serial,SIGNAL(error(QSerialPort::SerialPortError)),this,SLOT(serialPortError(QSerialPort::SerialPortError)));
void Test_Serial::serialPortError(QSerialPort::SerialPortError error)
{
//Print error etc.
}
The issue ended up being that the readyread flag is only emitted if theirs data to read. However I was sending the data too quickly for the external device to receive it. This meant that some data was lost thus the device never recognised it as a valid command.
This meant that it was still waiting for the message to finish, hence the "IRP_MJ_DEVICE_CONTROL (IOCTL_SERIAL_WAIT_ON_MASK) UP STATUS_CANCELLED COM1" error message upon closing the program. This also explains why their were no error messages with regards to writing data.
This also explains why the same program occasionally managed to read data, and at other times failed, (even without rebuilding the program, just re-running it.) When the data was read, the processor was more loaded, i.e. programs running in the background. This meant that the data was transmitted more slowly and thus the external device could recognise the commands and thus reply.
We are using FTDI serial port CHIP in our hardware. Now we have working code in Linux and we moved to windows 7. We get some weird problems.
The Problem:
We can't write data to Serial Port without running other console application which do this:
serial.setPortName("COM3");
if (serial.open(QIODevice::ReadWrite)) {
bool success = serial.setBaudRate(QSerialPort::Baud9600) &
serial.setStopBits(QSerialPort::OneStop) &
serial.setDataBits(QSerialPort::Data8) &
serial.setParity(QSerialPort::NoParity) &
serial.setFlowControl(QSerialPort::NoFlowControl);
qDebug() << "Connected to usb device: " << (success ? "OK" : "FAIL");
while(true) {
if(serial.waitForReadyRead(-1)) {
QByteArray out = serial.readAll();
for(int i=0; i< out.length(); i++) {
qDebug() << (int) out[i];
}
}
}
serial.close();
So its just loop with read all. Hardware dosen't send anything, so read is just infinity loop. After closing and running our write program it runs correctly.
char* input;
input = new char[size+3];
QByteArray bytearr;
for(int i=0;i<size+2;i++) {
input[i] = (char) package[i];
bytearr.append((unsigned char) package[i]);
}
QString serialPortName = "COM3";
QSerialPort serialPort;
serialPort.setPortName(serialPortName);
serialPort.open(QIODevice::ReadWrite);
serialPort.write(bytearr);
serialPort.flush();
serialPort.close();
After running read everything works, but without read all, it wont work. What are we doing wrong?
Thanks.
We had similar problem in our application with a board with FTDI chip. We tried to write bytes with 19200 baud/sec, had though in real about 1200 baud/sec (seen using oscilloscope). The problem was closing the serial port right after writing a byte. Just waiting using QThread::msleep(5) before closing the port helped. It seems, that the device gets a reset or something during close operation and latest bytes are sent with false baudrate and other parameters.
I found out that the QT serial port SW requires you to process QT events in order to work.
Putting a qApp->processEvents() in the loop before the read made it work for me.
(QT 4.8.5 on Windows-7)