簡體   English   中英

使用帶有Qt / C ++的Modbus-RTU協議連接到設備

[英]Connect to a device using Modbus-RTU protocol with Qt/C++

我的問題是我不知道為什么我的代碼停止從與控制器的連接中接收數據。

情況:我正在編寫Qt程序以連接設備並從設備獲取數據。 該設備使用具有9600波特率,偶數奇偶校驗,8個數據位,1個停止位的Modbus-RTU協議在RS-485上傳輸數據。 我的Qt程序使用QSerialPort類與設備進行通信。 第一次啟動程序時,發送二進制數據包后,我可以收到設備的回復。 但是從第二次開始,我的程序什么都沒收到,即使我在上面發送了很多相同的數據包。 請檢查下面的代碼,以便於理解:

#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();
}

這是我得到的結果:

01030000000ac5cd
Length: 8


Length: 0

0103140000001b0000000000000000ffb2000400040000b49e
Length: 25

01030000000ac5cd
Length: 8


Length: 0

01030000000ac5cd
Length: 8


Length: 0

01030000000ac5cd
Length: 8

我是否錯過了代碼中的某些內容?

謝謝。

我是否錯過了代碼中的某些內容?

至少您錯過了錯誤檢查。

很難判斷您的設備是否可能出現故障。

其他挑剔:該flush是不必要的,因為該waitForReadyRead執行隱式平齊。 _sleep也是不必要的:最后一個失敗的waitForReadyRead將等待3秒。 是否要重新打開日志文件值得懷疑-也許您只希望flush()它? 最后,不要使用<QtModule/QClass>包含-它們會延遲項目配置錯誤來鏈接時間。 使用<QClass>只包括或者包括整個Qt的模塊使用<QtModule>

您發布的示例有些復雜,因此也許此易於閱讀且帶有錯誤檢查的版本將使您能夠找出問題所在:

// 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() << "\nLength: " << data.size() << "\n\n";
   log.flush();
   chkError(*log.device());
}

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

void receive(QSerialPort & port, QTextStream & log) {
   auto data = port.readAll();
   qDebug() << "\nRead" << 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("\x01\x03\x00\x00\x00\x0A\0xC5\x0CD");

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM