连接到使用Modbus-RTU协议与设备的Qt/C++

问题描述:

我的问题是不知道为什么我的代码从停止到控制器的连接接收数据。连接到使用Modbus-RTU协议与设备的Qt/C++

情况:我正在写一个Qt程序来连接并从设备获取数据。该设备使用Modbus-RTU协议,波特率为9600,偶校验,8位数据位,1个停止位在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 

我错过在我的代码的东西吗?

谢谢。

+1

您是否尝试过使用调试器,看看发生什么事? –

我错过在我的代码的东西吗?

至少,你错过了错误检查。

它也很难说你的设备是否能够正常工作与否。

其他nitpicks:因为waitForReadyRead执行隐式刷新,所以不需要flush_sleep也是不必要的:最后,失败的waitForReadyRead将等待3秒钟。您是否希望重新打开日志文件是值得怀疑的 - 也许您只希望flush()它?最后,不要使用<QtModule/QClass> includes - 它们将项目配置错误推迟到链接时间。使用<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)); 
    } 
}