Qt中使用TCP和MC协议与三菱Q系列PLC通信

前言

我是按照博主lucky-billyQt中使用TCP和MC协议与三菱Q系列PLC通信
实现了Qt中使用TCP和MC协议与三菱Q系列PLC通信 。该博主把Qt使用TCP和MC协议与三菱Q系列PLC通信的理论部分讲得很好,但贴出来的代码太少了,对初学者可能不太友好。我这篇博客的侧重的是把代码写出来,因此在我看这篇博客之前,强烈建议大家先把lucky-billy博主的Qt中使用TCP和MC协议与三菱Q系列PLC通信这篇博客看完。

实操

看了 Qt中使用TCP和MC协议与三菱Q系列PLC通信
之后,我们知道报文格式是这样的
在这里插入图片描述

通信示例:

从地址 D100 开始依次写入 3 个软元件的值:
50 00 00 FF FF 03 00 12 00 10 00 01 14 00 00 64 00 00 A8 03 00 95 19 02 12 30 11
D0 00 00 FF FF 03 00 02 00 00 00

读取地址 D100 开始连续 5 个软元件的值:
50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 64 00 00 A8 05 00
D0 00 00 FF FF 03 00 0C 00 00 00 95 19 02 12 30 11 00 00 00 00

我们只需按照协议要求,向plc发送指令就能实现plc通信

配置

这是 .pro 文件的内容
切记要加上 network,如果没有下载该组件需要使用 MaintenanceTool.exe 进行下载

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    Utils.cpp \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

代码

这个是程序的ui代码:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>938</width>
    <height>654</height>
   </rect>
  </property>
  <property name="font">
   <font>
    <pointsize>16</pointsize>
   </font>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout_6" rowstretch="1,1,3,3,4">
    <item row="0" column="0">
     <widget class="QGroupBox" name="groupBox">
      <property name="styleSheet">
       <string notr="true">ui-&gt;groupBox-&gt; setStyleSheet (&quot;QGroupBox {border: 0;}&quot;); </string>
      </property>
      <property name="title">
       <string/>
      </property>
      <layout class="QGridLayout" name="gridLayout_5">
       <item row="0" column="0">
        <layout class="QHBoxLayout" name="horizontalLayout_2">
         <item>
          <layout class="QHBoxLayout" name="horizontalLayout">
           <item>
            <widget class="QLabel" name="label">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>IP Address:</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QLineEdit" name="ip">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="horizontalSpacer">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>40</width>
               <height>20</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QLabel" name="label_2">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>Port:</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QLineEdit" name="port">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="horizontalSpacer_7">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>40</width>
               <height>20</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QPushButton" name="connect">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>connect</string>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="horizontalSpacer_2">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>30</width>
               <height>13</height>
              </size>
             </property>
            </spacer>
           </item>
          </layout>
         </item>
         <item>
          <widget class="QPushButton" name="disconnect">
           <property name="font">
            <font>
             <pointsize>16</pointsize>
            </font>
           </property>
           <property name="text">
            <string>disconnect</string>
           </property>
          </widget>
         </item>
         <item>
          <spacer name="horizontalSpacer_5">
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>40</width>
             <height>20</height>
            </size>
           </property>
          </spacer>
         </item>
        </layout>
       </item>
      </layout>
     </widget>
    </item>
    <item row="1" column="0">
     <widget class="QGroupBox" name="groupBox_2">
      <property name="styleSheet">
       <string notr="true">ui-&gt;groupBox-&gt; setStyleSheet (&quot;QGroupBox {border: 0;}&quot;); </string>
      </property>
      <property name="title">
       <string/>
      </property>
      <layout class="QGridLayout" name="gridLayout_4">
       <item row="0" column="0">
        <layout class="QHBoxLayout" name="horizontalLayout_3">
         <item>
          <widget class="QLabel" name="label_3">
           <property name="font">
            <font>
             <pointsize>16</pointsize>
            </font>
           </property>
           <property name="text">
            <string>soft component:</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QComboBox" name="soft">
           <property name="font">
            <font>
             <pointsize>16</pointsize>
            </font>
           </property>
           <item>
            <property name="text">
             <string>D</string>
            </property>
           </item>
           <item>
            <property name="text">
             <string>M</string>
            </property>
           </item>
          </widget>
         </item>
         <item>
          <spacer name="horizontalSpacer_3">
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>40</width>
             <height>20</height>
            </size>
           </property>
          </spacer>
         </item>
         <item>
          <widget class="QLabel" name="label_5">
           <property name="font">
            <font>
             <pointsize>16</pointsize>
            </font>
           </property>
           <property name="text">
            <string>First Address:</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QLineEdit" name="address">
           <property name="font">
            <font>
             <pointsize>16</pointsize>
            </font>
           </property>
          </widget>
         </item>
         <item>
          <spacer name="horizontalSpacer_4">
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>40</width>
             <height>20</height>
            </size>
           </property>
          </spacer>
         </item>
         <item>
          <widget class="QLabel" name="label_6">
           <property name="font">
            <font>
             <pointsize>16</pointsize>
            </font>
           </property>
           <property name="text">
            <string>Length:</string>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QSpinBox" name="length">
           <property name="sizeIncrement">
            <size>
             <width>996</width>
             <height>0</height>
            </size>
           </property>
           <property name="font">
            <font>
             <pointsize>16</pointsize>
            </font>
           </property>
           <property name="maximum">
            <number>65535</number>
           </property>
           <property name="value">
            <number>0</number>
           </property>
          </widget>
         </item>
         <item>
          <spacer name="horizontalSpacer_6">
           <property name="orientation">
            <enum>Qt::Horizontal</enum>
           </property>
           <property name="sizeType">
            <enum>QSizePolicy::Maximum</enum>
           </property>
           <property name="sizeHint" stdset="0">
            <size>
             <width>40</width>
             <height>20</height>
            </size>
           </property>
          </spacer>
         </item>
        </layout>
       </item>
      </layout>
     </widget>
    </item>
    <item row="2" column="0">
     <widget class="QGroupBox" name="groupBox_4">
      <property name="styleSheet">
       <string notr="true">ui-&gt;groupBox-&gt; setStyleSheet (&quot;QGroupBox {border: 0;}&quot;); </string>
      </property>
      <property name="title">
       <string/>
      </property>
      <layout class="QGridLayout" name="gridLayout_2">
       <item row="0" column="0">
        <layout class="QHBoxLayout" name="horizontalLayout_6">
         <item>
          <layout class="QVBoxLayout" name="verticalLayout_2">
           <item>
            <widget class="QLabel" name="label_7">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>Write Data:</string>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="verticalSpacer_2">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
             <property name="sizeType">
              <enum>QSizePolicy::Expanding</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>11</width>
               <height>41</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QPushButton" name="writebtn">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>write</string>
             </property>
            </widget>
           </item>
          </layout>
         </item>
         <item>
          <widget class="QPlainTextEdit" name="writeEdit">
           <property name="font">
            <font>
             <pointsize>12</pointsize>
            </font>
           </property>
          </widget>
         </item>
        </layout>
       </item>
      </layout>
     </widget>
    </item>
    <item row="3" column="0">
     <widget class="QGroupBox" name="groupBox_5">
      <property name="styleSheet">
       <string notr="true">ui-&gt;groupBox-&gt; setStyleSheet (&quot;QGroupBox {border: 0;}&quot;); </string>
      </property>
      <property name="title">
       <string/>
      </property>
      <layout class="QGridLayout" name="gridLayout_3">
       <item row="0" column="0">
        <layout class="QHBoxLayout" name="horizontalLayout_4">
         <item>
          <layout class="QVBoxLayout" name="verticalLayout_3">
           <item>
            <widget class="QLabel" name="label_8">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>Read Data:</string>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="verticalSpacer_3">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>20</width>
               <height>40</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QPushButton" name="readbtn">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>Read</string>
             </property>
            </widget>
           </item>
          </layout>
         </item>
         <item>
          <widget class="QPlainTextEdit" name="readEdit">
           <property name="font">
            <font>
             <pointsize>12</pointsize>
            </font>
           </property>
          </widget>
         </item>
        </layout>
       </item>
      </layout>
     </widget>
    </item>
    <item row="4" column="0">
     <widget class="QGroupBox" name="groupBox_3">
      <property name="styleSheet">
       <string notr="true">ui-&gt;groupBox-&gt; setStyleSheet (&quot;QGroupBox {border: 0;}&quot;); </string>
      </property>
      <property name="title">
       <string/>
      </property>
      <layout class="QGridLayout" name="gridLayout">
       <item row="0" column="0">
        <layout class="QHBoxLayout" name="horizontalLayout_5">
         <item>
          <layout class="QVBoxLayout" name="verticalLayout">
           <item>
            <widget class="QLabel" name="label_4">
             <property name="font">
              <font>
               <pointsize>16</pointsize>
              </font>
             </property>
             <property name="text">
              <string>log:</string>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="verticalSpacer">
             <property name="orientation">
              <enum>Qt::Vertical</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>20</width>
               <height>158</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QPushButton" name="clearPtn">
             <property name="sizePolicy">
              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
               <horstretch>0</horstretch>
               <verstretch>0</verstretch>
              </sizepolicy>
             </property>
             <property name="font">
              <font>
               <pointsize>14</pointsize>
              </font>
             </property>
             <property name="text">
              <string>clear</string>
             </property>
            </widget>
           </item>
          </layout>
         </item>
         <item>
          <widget class="QPlainTextEdit" name="log">
           <property name="font">
            <font>
             <pointsize>12</pointsize>
            </font>
           </property>
          </widget>
         </item>
        </layout>
       </item>
      </layout>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

运行起来的效果是这样的:
在这里插入图片描述
我创建了一个工具类,待会运行时会用得到

#include <QApplication>
#include <QRegularExpression>

class Utils{
public:
    static QString addSpacesToHex(const QByteArray info) {
        QString hexStr = info.toHex().toUpper();
        QString result;
        for (int i = 0; i < hexStr.length(); i += 2) {
            // 检查是否到达了字符串的末尾,并且不是偶数长度的字符串(即可能只剩下一个字符)
            if (i + 1 < hexStr.length()) {
                // 添加两个字符和一个空格
                result.append(hexStr.mid(i, 2)).append(" ");
            } else {
                // 如果是奇数长度的字符串,直接添加最后一个字符(不添加空格)
                result.append(hexStr.mid(i));
            }
        }
        return result.trimmed(); // 如果不想在字符串末尾有额外的空格,可以使用trimmed()去除
    }

    // 例子: (15,4)  --》 10 00     (1234,4)  --》 D2 04
    static QString convertToIntHexWithSpacesFlip(int num, int bit)
    {
        // 首先将整数转换为十六进制,并转换为大写
        QString hexStr = QString::number(num, 16).toUpper();
        // 如果转换后的字符串长度小于指定的位数,则前面补零
        QString formattedStr = hexStr.rightJustified(bit, '0');

        QString result;
        if(bit == 4){
            result.append(formattedStr.mid(2,2)).append(" ").append(formattedStr.mid(0,2));
        }else if(bit == 6){
            result.append(formattedStr.mid(4,2)).append(" ").append(formattedStr.mid(2,2)).append(" ").append(formattedStr.mid(0,2));
        }else{
            qDebug() << "bit 数值错误" << Qt::endl;
        }
        return result;
    }

    static int convertToIntDecimalFlip(QString hexStr){
        int result;
        QString str;
        bool k;
        if(hexStr.length() == 4){
            str.append(hexStr.mid(2,2)).append(hexStr.mid(0,2));
            result = str.toInt(&k,16);
            if(!k){
                qDebug() <<str<<"无法转化"<< Qt::endl;
            }
        }else if(hexStr.length() == 6){
            str.append(hexStr.mid(4,2)).append(hexStr.mid(2,2)).append(hexStr.mid(0,2));
            result = str.toInt(&k,16);
            if(!k){
                qDebug() <<str<<"无法转化"<< Qt::endl;
            }
        }else{
            qDebug() << "convertToIntDecimalFlip 出错!" << Qt::endl;
            result = -1;
        }
        return result;
    }

    static bool formattedCorrectly(QStringList writeData,QString address){
        QRegularExpression re("^[\\d\\s]+$");
        if(writeData.length() > 0){
            for(QString item:writeData){
                if(!re.match(item).hasMatch()){
                    qDebug() << "writeData内的元素:{"+item+"}包含除数字和空格之外的字符,无法发送" << Qt::endl;
                    return false;
                }
                if(item.toInt() > 65535){
                    qDebug() << "writeData内的元素:{"+item+"}大于发送数据的上限,无法发送" << Qt::endl;
                    return false;
                }
            }
        }
        if (address.length() > 0 && !re.match(address).hasMatch()) {
            qDebug() << "address:{"+address+"}包含除数字和空格之外的字符,无法发送" << Qt::endl;
            return false;
        }

        int startAddress = address.toInt();
        if(startAddress > 16777215){
            qDebug() << "起始位置{"+address+"}超出了范围上限,无法发送";
            return false;
        }
        return true;
    }
};

然后就是 mainwindows.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>


QT_BEGIN_NAMESPACE
class QTcpSocket;
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
    QTcpSocket *network;
    int connectionTimeout = 5000; // 连接超时时间,单位毫秒
    int sendTimeout = 5000;       // 发送超时时间,单位毫秒
    QString currentTime;
    QString head = "50 00 00 FF FF 03 00";
    QString timeoutStr = "10 00";
    QString writeCommand = "01 14";
    QString readCommand = "01 04";
    QString subCommand = "00 00";

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_clearPtn_clicked();

    void on_writebtn_clicked();

    void on_disconnect_clicked();

    void on_readbtn_clicked();

    void on_connect_clicked();

    void on_ip_textChanged(const QString &arg1);

    void on_port_textChanged(const QString &arg1);

    void readResponseData();

private:
    Ui::MainWindow *ui;
    void Recode_logs(QByteArray info, QString type);
    void setState(bool state);

    // test
    QByteArray CreateData_TEST();
    void ReadData_TEST();
    void Response_Test(QByteArray);
};
#endif // MAINWINDOW_H

mainwindows.cpp 文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "Utils.cpp"

#include <QDebug>
#include <QTcpSocket>
#include <QDateTime>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    network = new QTcpSocket(this);

    connect(network, &QTcpSocket::connected, [](){ qDebug() << "Connected to PLC successfully !" << Qt::endl; });
    connect(network, &QTcpSocket::disconnected, [](){ qDebug() << "Disconnected from plc !" << Qt::endl; });
    connect(network, &QTcpSocket::stateChanged, [](QAbstractSocket::SocketState socketState){
        qDebug() << "SocketState changed: " << socketState;
    });
    connect(network, &QTcpSocket::readyRead, this, &MainWindow::readResponseData);

    //界面初始化
    ui->groupBox-> setStyleSheet ("QGroupBox {border: 0;}");
    ui->groupBox_2-> setStyleSheet ("QGroupBox {border: 0;}");
    ui->groupBox_3-> setStyleSheet ("QGroupBox {border: 0;}");
    ui->groupBox_4-> setStyleSheet ("QGroupBox {border: 0;}");
    ui->groupBox_5-> setStyleSheet ("QGroupBox {border: 0;}");
    ui->address->setPlaceholderText("0");
    ui->writeEdit->setPlaceholderText("00 00");
    ui->log->setReadOnly(true);
    ui->readEdit->setReadOnly(true);
    ui->length->setReadOnly(false);
    setState(false);
}

void MainWindow::readResponseData()
{
    QByteArray response = network->readAll();
    Recode_logs(response,"Response");
    ui->log->appendPlainText("");

    // 从 response里读取数据,并上传到readEdit
    QString hexStr = response.toHex().toUpper().trimmed();

    if(hexStr.startsWith("D000")){
        /*
         * 例子:
         * "D0 00 00 FF FF 03 00 0B 00 51 C0 00 FF FF 03 00 01 04 00 00"
         *  51 C0 错误信息       访问地址:00 FF FF 03 00     01 04 指令     00 00 子指令
        */
        if(hexStr.mid(18,4) == "51C0"){
            qDebug() << "错误信息" << Qt::endl;
            QMessageBox info(this);
            info.setWindowTitle("info");
            info.setText("错误!\n发生错误的地址:" + hexStr.mid(22,10) + " ,发生错误的指令:" + hexStr.mid(32,4) + "\n发生错误的子指令:" + hexStr.mid(36,4));
            info.setIcon(QMessageBox::Information);
            info.addButton("确定", QMessageBox::AcceptRole);
            info.exec();
        }
        int point = 14;
        QString tmp = hexStr.mid(point,4);
        int count = (Utils::convertToIntDecimalFlip(tmp) - 2)/2;
        if(count > 0){
            point += 8;
            QString str;
            int data;
            for(int i = 0;i < count;i++){
                data = Utils::convertToIntDecimalFlip(hexStr.mid(point,4));
                point+=4;
                str.append(QString::number(data)).append(" ");
            }
            if(str.length() > 0){
                str = str.left(str.length() - 1);
            }
            ui->readEdit->appendPlainText(str);
            ui->readEdit->appendPlainText("");
        }
    }else{
        qDebug() << "响应错误" << Qt::endl;
    }

}

void MainWindow::setState(bool state){
    ui->readEdit->setEnabled(state);
    ui->writeEdit->setEnabled(state);
    ui->length->setEnabled(state);
    ui->address->setEnabled(state);
    ui->writebtn->setEnabled(state);
    ui->readbtn->setEnabled(state);
    ui->soft->setEnabled(state);
    ui->disconnect->setEnabled(state);
}

void MainWindow::Recode_logs(QByteArray info, QString type)
{
    currentTime = QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss]");
    QString str = Utils::addSpacesToHex(info);

    QString log = currentTime + "[" + type +"]" + str;
    ui->log->appendPlainText(log);
}

void MainWindow::on_ip_textChanged(const QString &arg1)
{
    Q_UNUSED(arg1);
    setState(false);
}

void MainWindow::on_port_textChanged(const QString &arg1)
{
    Q_UNUSED(arg1);
    setState(false);
}


void MainWindow::on_connect_clicked()
{
    // 连接到主机
    network->connectToHost(ui->ip->text(), ui->port->text().toInt());
    qDebug() << "....";
    if (network->waitForConnected(connectionTimeout)) {
        qDebug() << "连接成功";
        setState(true);
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("成功连接");
        info.setIcon(QMessageBox::Information);
        // 添加额外的按钮
        info.addButton("确定", QMessageBox::AcceptRole);
        // 显示对话框
        info.exec();
    }else{
        qDebug() << "连接失败";
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("连接失败");
        info.setIcon(QMessageBox::Information);
        info.addButton("确定", QMessageBox::AcceptRole);
        info.exec();
        disconnect();
        setState(false);
    }
}

void MainWindow::on_disconnect_clicked()
{
    if (network->state() == QAbstractSocket::ConnectedState) {
        network->disconnectFromHost(); // 正确地断开网络连接
        qDebug() << "成功断开连接" << Qt::endl;
        setState(false);
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("成功断开连接");
        info.setIcon(QMessageBox::Information);
        info.addButton("确定", QMessageBox::AcceptRole);
        info.exec();
    }
}

void MainWindow::on_writebtn_clicked()
{
    QString address = ui->address->text();
    QString soft = ui->soft->currentIndex() == 0 ? "A8" : "90";
    QStringList writeData = ui->writeEdit->toPlainText().split(" ", Qt::SkipEmptyParts);
    if(writeData.length() > ui->length->value()){
        qDebug() << "要写的内容大于length,无法发送";
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("要传输的内容大于 Length,无法发送,请调整write内容或length");
        info.setIcon(QMessageBox::Information);
        // 添加额外的按钮
        info.addButton("确定", QMessageBox::AcceptRole);
        // 显示对话框
        info.exec();
        return;
    }
    bool checkResult = Utils::formattedCorrectly(writeData,address);
    if(!checkResult){
        qDebug() << "format 错误" << Qt::endl;
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("格式错误,请检查你的数据内容和起始软元件");
        info.setIcon(QMessageBox::Information);
        info.addButton("确定", QMessageBox::AcceptRole);
        info.exec();
        return;
    }
    // 将10进制转为16进制 翻转
    QString count = Utils::convertToIntHexWithSpacesFlip(ui->length->text().toInt(), 4);
    address = Utils::convertToIntHexWithSpacesFlip(address.toInt(),6);
    QString content;
    for(QString item : writeData) {
        content.append(Utils::convertToIntHexWithSpacesFlip(item.toInt(), 4)).append(" ");
    }
    int diffrence = ui->length->value() - writeData.length();
    while(diffrence > 0){
        content.append("00 00 ");
        diffrence--;
    }
    if (content.length() > 0) {
        content.remove(content.length() - 1, 1);
    }
    QString data = timeoutStr + " " + writeCommand + " " + subCommand + " " + address + " " + soft + " " + count + " " + content;
    QString temp = data;
    temp.replace(" ", "");
    int len = temp.length()/2;
    QString lengthStr = Utils::convertToIntHexWithSpacesFlip(len, 4);
    // 组装最终要发送的数据
    QString result = head + " " + lengthStr + " " + data;
    // 转换为 QByteArray 并发送
    QByteArray array = QByteArray::fromHex(result.toLatin1());
    network->write(array);
    // 等待数据被发送
    if (!network->waitForBytesWritten(sendTimeout)) {
        on_disconnect_clicked();
        qDebug() << "发送数据超时,断开连接";
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("发送数据超时,已断开连接");
        info.setIcon(QMessageBox::Information);
        info.addButton("确定", QMessageBox::AcceptRole);
        info.exec();
    }
    Recode_logs(array,"Write");
}

void MainWindow::on_readbtn_clicked()
{
    QString address = ui->address->text();
    if(ui->length->value() == 0){
        qDebug() << "length长度为0,无法发送";

        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("length长度为0,无法发送\n请调整length的大小");
        info.setIcon(QMessageBox::Information);
        // 添加额外的按钮
        info.addButton("确定", QMessageBox::AcceptRole);
        // 显示对话框
        info.exec();
        return;
    }
    bool checkResult = Utils::formattedCorrectly(QStringList(),address);
    if(!checkResult){
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("格式错误,请检查你的起始软元件");
        info.setIcon(QMessageBox::Information);
        info.addButton("确定", QMessageBox::AcceptRole);
        info.exec();
        return;
    }
    QString soft = ui->soft->currentIndex() == 0 ? "A8" : "90";
    // 将10进制转为16进制 翻转
    QString count = Utils::convertToIntHexWithSpacesFlip(ui->length->value(), 4);
    address = Utils::convertToIntHexWithSpacesFlip(address.toInt(),6);
    QString data = timeoutStr + " " + readCommand + " " + subCommand + " " + address + " " + soft + " " + count;
    QString temp = data;
    temp.replace(" ", "");
    int len = temp.length()/2;
    QString lengthStr = Utils::convertToIntHexWithSpacesFlip(len, 4);

    // 组装最终要发送的数据
    QString result = head + " " + lengthStr +" " + data;

    // 转换为 QByteArray 并发送
    QByteArray array = QByteArray::fromHex(result.toLatin1());

    network->write(array);
    // 等待数据被发送
    if (!network->waitForBytesWritten(sendTimeout)) {
        qDebug() << "发送数据超时,断开连接";
        QMessageBox info(this);
        info.setWindowTitle("info");
        info.setText("发送数据超时,断开连接");
        info.setIcon(QMessageBox::Information);
        info.addButton("确定", QMessageBox::AcceptRole);
        info.exec();
        disconnect();
    }
    Recode_logs(array,"Read");
}

void MainWindow::on_clearPtn_clicked()
{
    ui->log->clear();
}

MainWindow::~MainWindow()
{
    delete ui;
}

运行

启动程序,只需要将plc对应的ipport输入,然后点击connect 按钮。如果没有连接出错就可以实现plc的通信了。
在这里插入图片描述

1. 写操作

我们想要向plc写入内容时,需要将想写入的内容写在WriteData中并且每个数之间用空格隔开,Length也需要自己手动输入,如果length大于WriteData里面的内容则会在输入内容的后面补零,如果length小于WriteData里面的内容则不会发送出指令,会弹出报错窗口,First Address代表输入的起始位置
在这里插入图片描述

2.读操作

读操作我们只需要确认我们想要读取数据的First Address(起始地址)和想要读取的Length(长度),点击read按钮,就能进行读取
在这里插入图片描述
读取的内容会打印在Read Data上,以十进制的方式展示

log 会打印 读写操作请求报文响应报文,我们可以通过返回的响应报文判断命令是否执行成功,如果执行失败,我们可以查看文档,找到错误的原因
出错代码
在这里插入图片描述

点击clear按钮可以清除log里的内容
在这里插入图片描述

总结

要想实现Qt中使用TCP和MC协议与三菱Q系列PLC通信,需要先知道它们之间的通信报文格式
在这里插入图片描述
按照格式,将报文拼接起来,实现对plc的通信。
如果不理解它的通信格式,可以看这一篇博客 Qt中使用TCP和MC协议与三菱Q系列PLC通信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值