2
votes

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:

  1. Upload code
  2. Run GUI
  3. Send data - It receives properly
  4. Disconnect and reconnect
  5. Run GUI again
  6. Send data - RX blinks but Serial.available returns 0

Use Scenario B:

  1. Upload code
  2. Run Brays
  3. Send data - It receives properly
  4. Disconnect and reconnect
  5. Run Brays again
  6. Send data - It receives properly

Use Scenario C (the most interesting) :

  1. Upload code
  2. Run GUI
  3. Send data - It receives properly
  4. Disconnect and reconnect
  5. Run Brays this time
  6. Send data - It receives properly
  7. Run GUI again after Brays
  8. 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:

  1. Upload code to Arduino
  2. Run GUI
  3. Send data
  4. Nothing happens (normal behaviour)
  5. Disconnect and reconnect Arduino to USB
  6. Run GUI
  7. Send data
  8. Arduino LED momentarily blinks once (possibly indicating some kind of error)
4
Does the Arduino LED flash indicating that it is receiving data?Jeff
Yes, it flashes normally, even after reconnecting. It is only serial.available() that returns 0.r21
What output are you getting from the Arduino?Jeff
Sorry, when I said that the LED flashes, I meant that the Rx LED flashes, when I send the data. The proper LED, the one connected on digital pin 13, that I have defined as "ledpin" in the code above doesn't flash, as it never becomes HIGH because it never enters the while loop, and variable c remains zero. Regarding your suggested answer, I will try the code you posted and post the update on the situation soon.r21
Why did it change from "COM3:" to "COM5:"? Also, I noticed that only your first example sets Data8, OneStop and NoParity. You need to set all of the parameters when you open the port or they may stay at the last settings or be random. If the character is not the correct length or parity the Arduino may ignore it.Jeff

4 Answers

2
votes

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!

0
votes

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.

0
votes

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);
    }
}
0
votes

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;
}