windows - Tilslut til en enhed ved hjælp af Modbus-RTU-protokollen med Qt/C ++

Indlæg af Hanne Mølgaard Plasc

Problem



mit problem er, jeg ved ikke, hvorfor min kode stopper med at modtage data fra en forbindelse til controlleren.


Situation: Jeg skriver et Qt-program til at forbinde og hente data fra en enhed. Enheden anvender Modbus-RTU-protokollen med baudrates 9600, Even Parity, 8 databits, 1 stopbit til overførsel af data på RS- 485. Mit Qt-program bruger QSerialPort klasse til at kommunikere med enheden. I første gang jeg starter programmet kan jeg modtage svar fra enheden efter at jeg har sendt en binær pakke. Men fra anden gang modtager mit program ikke noget , selv jeg sendte mange af de samme pakker ovenfor. Tjek venligst min kode nedenfor for lettere at forstå:


#include <QCoreApplication>
#include <QtSerialPort/qserialport.h>
#include <QtSerialPort/QSerialPort>
#include <iostream>
#include <bitset>
#include <fstream>
using namespace std;

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    fstream fs;

    QSerialPort qsp;
    qsp.setPortName("COM2");
    qsp.setBaudRate(QSerialPort::Baud9600);
    qsp.setDataBits(QSerialPort::Data8);
    qsp.setParity(QSerialPort::EvenParity);
    qsp.setStopBits(QSerialPort::OneStop);
    qsp.setFlowControl(QSerialPort::NoFlowControl);

    if (qsp.open(QIODevice::ReadWrite)){
        QByteArray qbaDataSend;
        qbaDataSend.resize(8);
        qbaDataSend[0] = 0x01;
        qbaDataSend[1] = 0x03;
        qbaDataSend[2] = 0x00;
        qbaDataSend[3] = 0x00;
        qbaDataSend[4] = 0x00;
        qbaDataSend[5] = 0x0A;
        qbaDataSend[6] = 0xC5;
        qbaDataSend[7] = 0xCD;
        cout << endl << "Byte wrote: " <<qbaDataSend.toHex().toStdString() << endl << "Length: " << qsp.write(qbaDataSend) << endl;

        fs.open("Data.txt", ios\_base::app | ios\_base::out);

        fs << qbaDataSend.toHex().toStdString() << endl;

        fs << "Length: " << qbaDataSend.toStdString().length() << endl << endl;
        fs.close();
        qsp.flush();
        while(true){
            \_sleep(3000);
            do {
                QByteArray qbaDataRead = qsp.readAll();

                fs.open("Data.txt", ios\_base::app | ios\_base::out);
                cout << qbaDataRead.toHex().toStdString() << endl;
                fs << qbaDataRead.toHex().toStdString() << endl;
                cout << "Length: " << qbaDataRead.toStdString().length() << endl << endl;
                fs << "Length: " << qbaDataRead.toStdString().length() << endl << endl;
                fs.close();
            }
            while(qsp.waitForReadyRead(3000));

            cout << endl << "Byte wrote: " <<qbaDataSend.toHex().toStdString() << endl << "Length: " << qsp.write(qbaDataSend) << endl;
            qsp.write(qbaDataSend, 8);
            fs.open("Data.txt", ios\_base::app | ios\_base::out);

            fs << qbaDataSend.toHex().toStdString() << endl;

            fs << "Length: " << qbaDataSend.toStdString().length() << endl << endl;
            fs.close();
            qsp.flush();
        }
    }

    cout << "Out" << endl;

    qsp.close();
    cout << "Error: " << qsp.errorString().toStdString() << endl;
    cout << "Close" << endl;

    return a.exec();
}


Her er resultatet jeg fik:


01030000000ac5cd
Length: 8


Length: 0

0103140000001b0000000000000000ffb2000400040000b49e
Length: 25

01030000000ac5cd
Length: 8


Length: 0

01030000000ac5cd
Length: 8


Length: 0

01030000000ac5cd
Length: 8


Har jeg savnet noget i min kode?


Tak.

Bedste reference



  Har jeg savnet noget i min kode?



I det mindste har du savnet fejlkontrol.


Det er også svært at vide, om din enhed kan være funktionsfejl eller ej.


Andre nitpicks: flush er unødvendig, da waitForReadyRead udfører en implicit flush. \_sleep er også unødvendigt: den sidste, hvis der ikke er waitForReadyRead, venter 3 sekunder. Det er tvivlsomt, om du vil genåbne logfilen - måske vil du kun flush() det? Endelig skal du ikke bruge <QtModule/QClass> - de udsætter projektkonfigurationsfejl for at forbinde tiden. <QClass> omfatter kun, eller at inkludere hele Qt-modulet brug <QtModule>.


Eksemplet du bogførte er lidt forfaldet, så måske denne lettere at læse version med fejlkontrol gør det muligt for dig at finde ud af, hvad der er forkert:


// https://github.com/KubaO/stackoverflown/tree/master/questions/serial-blocking-45369860
#include <QtSerialPort>

template <class T> bool hasError(const QIODevice & d) {
   return qobject\_cast<const T *>(&d) && static\_cast<const T &>(d).error() != T::NoError;
}

void chkError(const QIODevice & d) {
   if (hasError<QFile>(d) || hasError<QSerialPort>(d))
      qFatal("I/O Error on \%s: \%s", d.objectName().toLocal8Bit().constData(),
             d.errorString().toLocal8Bit().constData());
}

void logData(QTextStream & log, const QByteArray & data) {
   log << data.toHex() << "
Length: " << data.size() << "

";
   log.flush();
   chkError(*log.device());
}

void transmit(QSerialPort & port, const QByteArray & data, QTextStream & log) {
   port.write(data);
   qDebug() << "
Wrote" << data.size() << ":" << data.toHex().constData();
   chkError(port);
   logData(log, data);
}

void receive(QSerialPort & port, QTextStream & log) {
   auto data = port.readAll();
   qDebug() << "
Read" << data.size() << ":" << data.toHex().constData();
   chkError(port);
   logData(log, data);
}

int main(int argc, char *argv[])
{
   QCoreApplication app(argc, argv);

   QFile logFile("Data.txt");
   if (!logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
      qFatal("Can't open the log file: \%s", logFile.errorString().toLocal8Bit().constData());
   QTextStream log(&logFile);

   QSerialPort port;
   port.setPortName("COM2");
   port.setBaudRate(QSerialPort::Baud9600);
   port.setDataBits(QSerialPort::Data8);
   port.setParity(QSerialPort::EvenParity);
   port.setStopBits(QSerialPort::OneStop);
   port.setFlowControl(QSerialPort::NoFlowControl);

   if (!port.open(QIODevice::ReadWrite))
      qFatal("Can't open the serial port: \%s", port.errorString().toLocal8Bit().constData());

   logFile.setObjectName("Log File");
   port.setObjectName("Serial Port");

   const QByteArray sendPacket = QByteArrayLiteral("x01x03x00x00x00x0AxC5x0CD");

   while (true) {
      transmit(port, sendPacket, log);
      do {
        receive(port, log);
      } while (port.waitForReadyRead(3000));
   }
}