3

I am writing a C++ program using Qt that reads data from the serial line. The "producer" of the data is an Arduino UNO board.

The Arduino code is very simple. Currently, it just generates a random number and sends it over the serial line. Here is the code:

long randNumber;

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(0));
}

void loop() {
  randNumber = random(300);
  Serial.write(randNumber);
  delay(10);
}

I have used the Arduino's "serial monitor" to verify that data is coming across the serial line.

On the Qt side of things, I have a worker thread that is supposed to read the serial data and update a plot on the UI accordingly. The worker thread is definitely running, and this code is getting executed (I've checked). I only have one device in my "port list" that shows up, and it is the Arduino, so currently I connect right to it. Here is the code:

void doWork ()
{
    QList<QSerialPortInfo> port_list = QSerialPortInfo::availablePorts();
    QSerialPort serialPort;
    serialPort.setPort(port_list[0]);
    serialPort.setBaudRate(QSerialPort::Baud9600);

    if (!serialPort.open(QIODevice::ReadWrite))
    {
        cout << QObject::tr("Failed to open port COM3, error: %1").arg(serialPort.errorString()).toStdString() << endl;
    }

    while(!abort_thread)
    {
        int bytes_available = serialPort.bytesAvailable();
        if (bytes_available >= 4)
        {
            QByteArray byte_array = serialPort.read(4);
            int data = byte_array.toInt();
            emit signalDataReady(data);
        }
    }

    serialPort.close();
}

Unfortunately, there are never any bytes available. It opens the serial port successfully, but no bytes come through. What am I doing wrong here? Any ideas? Thanks!

David
  • 1,847
  • 4
  • 26
  • 35
  • You seem to have checked pretty much every error I could think of, but are you *absolutely sure* you only have one port on your computer? Did you print out the length of `port_list` or did you use something else to check? I'm just asking because many computers tend to have extra serial ports even though they might not have a physical interface. – Matti Virkkunen Apr 28 '16 at 01:43
  • I presume that Qt is running on a PC connected to you arduino board? - or is Qt also running on another arduino board? Anyway, a couple of things to try: First is in your doWork() thread function you will probably be maxing out your processor as you have no switch points. Try adding `QThread::msleep(10);` to add a pause, slow down your polling and allows other processes some cpu time (not sure it will fix it, but....). You will need to `#include ` in your file. – code_fodder Apr 28 '16 at 06:38
  • Second thing... ok this is more a stab in the dark then the first, but I always open my QSerialPorts by setting setPortName()... always works for me. So you can try `serialPort.setPortName(port_list[0].portName());` instead of `serialPort.setPort(port_list[0]);` – code_fodder Apr 28 '16 at 06:41
  • Finally, have you tried to communicate to a known-good comport output? - i.e. connect to a windows/linux box with a serial terminal (like putty) and look for the ardiuno board output? - If that is ok, then try receiving in your Qt app from the putty terminal and update us with which way around this works / does not work (I know you say you have verified arduino board with its own tools... but I never trust these until I have seen it work with standard tools). – code_fodder Apr 28 '16 at 06:44

2 Answers2

1

You are forgot to add waitForReadyRead() before bytesAvailable().

Denis Shienkov
  • 517
  • 3
  • 12
  • Looking at it closely, this would probably fix it. There's probably no event loop in your thread, and I can't remember how `QSerialPort` behaves without one, but the docs state that this method is useful "when performing I/O operations in a non-GUI thread". At any rate it's good practice to block rather than busy wait. – Matti Virkkunen Apr 28 '16 at 10:12
  • After having looked at all of the various suggestions made here, it looks like this is the one that did it! Thanks! What's interesting is I have to do this each time before I call bytesAvailable(), and not just once after connecting to the Arduino. – David Apr 28 '16 at 16:14
0

From https://www.arduino.cc/en/Serial/Write:

Serial.write(val)

val: a value to send as a single byte

If you write a number Arduino only sends one byte, if you want to send a long then you must decompose it as an array and send the array (or get a pointer to the long's address and send each one of the bytes).

As your Qt code expects to read four bytes the if is never executed.

Gusman
  • 14,905
  • 2
  • 34
  • 50
  • That's probably an error but because the Arduino code is run in a loop it will eventually send 4 and more bytes and this doesn't explain why no data is received by the Qt program. – Matti Virkkunen Apr 28 '16 at 01:38
  • Well, the loop is not posted on the code, I can't imagine details of code not posted :D (yes, there's a loop() function, but I can't see it to be really a loop as the function just enters and exits). – Gusman Apr 28 '16 at 01:40
  • For some reason the Arduino/Wiring developers saw fit to protect programmers from having to write loops themselves so they provide a main() function that calls setup() and then keeps calling loop() in a loop for them. Go figure. – Matti Virkkunen Apr 28 '16 at 01:41
  • My bad then XD, I'm not very used to Arduino, I prefer to program directly on their native frameworks the microcontrollers. – Gusman Apr 28 '16 at 01:44
  • Same here. I'm not a big fan of the whole Wiring deal. – Matti Virkkunen Apr 28 '16 at 01:45
  • Thanks for this suggestion. Although it wasn't the root of the problem, it was definitely a bug. It's been fixed! – David Apr 28 '16 at 16:14