Serial Port Communication with Arduino
-
Hi all,
I'm building a multi-sensory device using an Arduino uno and i want to output the sensor values to the qt ui, the only thing i'm struggling with is interpreting the data read from the Arduino, you'll see in the code for readsearial() the first section before QStringList bufferSplit works, i am reading data and it is correct in terms of value however it is splitting the data up in the wrong place. I also need for this process to work to write the buffer split data to the variables in the inputData array however this code is never being executed and i don't know why, help would be greatly appreciated. Thank you in advance.Read Serial function in main.cpp
void MainWindow::readSerial() { qDebug() << "Reading serial port data..."; QByteArray data = arduino->readAll(); qDebug() << data; //displaying all input data to the debug consol //serialBuffer = serialBuffer + QString::fromStdString(serialData.toStdString()); qDebug() << "Serial Buffer Value: " << data << "\n"; QStringList bufferSplit = serialBuffer.split(","); if(bufferSplit.length() < 3){ // no parsed value yet so continue accumulating bytes from serial in the buffer. serialData = arduino->readAll(); serialBuffer = serialBuffer + QString::fromStdString(serialData.toStdString()); serialData.clear(); }else{ // the second element of buffer_split is parsed correctly, update the temperature value on temp_lcdNumber serialBuffer = ""; qDebug() << &bufferSplit << "\n"; inputData.temperatureArray[1] = bufferSplit[0].toFloat(); inputData.phArray[1] = bufferSplit[1].toFloat(); inputData.moistureArray[1] = bufferSplit[2].toFloat(); qDebug() << "Temperature: " << &inputData.temperatureArray[1] << "\n"; MainWindow::sensorUpdate(inputData.temperatureArray[1], inputData.phArray[1], inputData.moistureArray[1]); } data.clear(); }
Header function cause thats where most of the variables are declared:
private slots: void on_Device_1_clicked(); //Takes user to Device_1 page void on_Device_2_clicked(); //Takes user to Device_2 page void on_actionHOMEPAGE_triggered(); //Takes user to Homepage (from toolbar menu) void on_actionDEVICE_1_triggered(); //Takes user to Device_1 page (from toolbar menu) void openSerial(); //Opens serial port connection void readSerial(); //Reads serial port connection void DatUpdate(); //Updates the displayed homepage data void sensorUpdate(QString tempSensorReading, QString moistureSensorReading, QString PHSensorReading); //Updates the displayed sensor values void errorAlert(QString errorMsg); //Opens a dialog box which displays an error message private: Ui::MainWindow *ui; QSerialPort *arduino; static const quint16 arduinoUnoVendorId = 9025; static const quint16 arduinoUnoProductId = 67; QString arduinoPortName; QByteArray serialData; QString serialBuffer; QString parsedData; int updateType; double temperatureValue; };
The values will be diffrent because i can't open serial port coms to view on arduino and qt at the same time but here are some examples of the ouputs from both
arduino output:
23.11.21,0,15.92,10.35,0,23.24,11.19,0,23.24,10.12,0,
qt output:Reading serial port data... "1.20" Serial Buffer Value: "1.20" Reading serial port data... ",0," Serial Buffer Value: ",0," Reading serial port data... "2" Serial Buffer Value: "2" Reading serial port data... "3.24" Serial Buffer Value: "3.24" Reading serial port data... ",10." Serial Buffer Value: ",10." Reading serial port data... "14,0" Serial Buffer Value: "14,0" Reading serial port data... "," Serial Buffer Value: ","
-
Hi,
What is usually done is to have frames with a start and end char (or sequence of char) so that you can easily identify when you got one frame of data and then process it accordingly.
You then cumulate the data received on dataRead and check if there's at least a frame available. If not, do nothing and start again next time you receive data.
-
@SGaist that makes a lot of sense, i was going down a similar path or at least i thought i was by having the Arduino output commas after every data chunk however as you can see that didn't work well, could you give me an example of implementing it? Would you be using QByteArray functions or something else? Thank you
-
Hi @Will_Craig,
I assume your data looks like that:
123,456,789\n
then your slot would look like that (untested, not even compiled):
MyClass::serialDataReady() { while (m_serial->canReadLine()) { const QByteArray data = m_serial->readLine(); const QStringList list = QString(data).split(','); if (list.size() != 3) { // corrupted data, discard it continue; } // data seems valid, handle it qDebug() << list; } } Regards
-
Yeah it comes in 3's but with no newline, the serial port kept reading the newline character so i am only displaying the " , " not a new line on Arduino output.
The way the Arduino is outputting the data is
float temperature, int ph, int moisture,
and then it repeats in line.I've changed the code a bit and I'm starting to get clearer readings but now it is reading floats weird which is throwing everything else out of place. i may try running the code and see what it picks up if the output of the singular float variable is an int, because if its a problem with the decimal i will just work with an int the precision is not too much of an issue here.
That if statement that broke it into a 3variable package was not needed that i can see from the output of new code it was wasted lines i think i was overthinking it.
UPDATED CODE:
void MainWindow::readSerial() { QByteArray data = arduino->readAll(); serialBuffer = data; data.truncate(3); QStringList bufferSplit = serialBuffer.split(", "); if(counter == 0) { inputData.temperatureArray[1] = bufferSplit[0]; qDebug() << "TEMPERATURE: " << bufferSplit[0] << "\n"; } else if(counter == 1) { inputData.phArray[1] = bufferSplit[0]; qDebug() << "PH: " << bufferSplit[0] << "\n"; } else if(counter == 2) { inputData.moistureArray[1] = bufferSplit[0]; qDebug() << "MOISTURE: " << bufferSplit[0] << "\n"; } MainWindow::sensorUpdate(inputData.temperatureArray[1], inputData.phArray[1], inputData.moistureArray[1]); counter++; if(counter == 3) { counter = 0; } data.clear(); }
Thanks everyone for the help so far.
-
@Will_Craig your protocol should really have a start/end of line marker, as it makes parsing so much easier.
It may be impossible to understand the data if you only have
int
orfloat
strings with comma between.Regards