前言:
B站视频、CSDN“找宝贝”、度娘、博客园、Github找了好久关于QT联合Modbus(TCP)读写PLC数据的知识真就没有一个能从头到尾讲下来这个知识的,可能有也是我能力有限疏忽了,但是我能力范围内真就没有能把这个事儿说明白的,我自己通过学习CSDN前人的QT5里面读写PLC的知识和B站大佬讲解两个PLC之间TCP通讯,举一反三,硬把他们联系到一起,费话不多少,直接分享我的经验。
一、PLC配置连接环境和通讯模块引脚设置
不知道为啥首先添加新设备(我这个PLC只能用4.2版本的,其他版本不好用,有懂哥可以留言告诉弟弟,感谢)
其次设置IP地址
访问和连接打开
在主函数中找到Modbus(TCP)通讯模块并拖到主函数中
配置通讯块:这里很重要
第一个是是否通讯flase就是通讯、true就是不通讯
第二个是服务器数据存储区:我上图的参数意思就是从M10.0开始的4个区域,也就是M10.0、M12.0、M14.0、M16.0(对应地址就是0、1、2、3)
第三个参数是配置通讯的IP之类的我们接下来展开说:
首先创建一个DB块,他的数据类型是箭头所指(自己手打别无他法)
interfaceid就是64别动(除非你的是极少数的电脑,相信我你就是64)
id随便设置,和QT配对用的,我这里写1
其他的不用动
LocaIPort是端口号,和那个64一样固定502(别给自己找麻烦就用大家都用的就行)
设置完这些,把DB块的变量A放到刚才的通讯块第三个参数中,如上上个图所示
接下来设置监控的地址变量
添加新监控表->地址写上如上所示两个地址
这样一来,PLC这边配置完毕
二、QT配置Modbus编写程序
新建一个QT7(pro)项目
在Pro文件中添加如下代码
QT += serialbus serialport widgets//添加库
在头文件内容如下
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QModbusDataUnit> //存储接收和发送数据的类,数据类型为1bit和16bit
#include <QModbusReply> //客户端访问服务器后得到的回复(如客户端读服务器数据时包含数据信息)
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class QModbusClient;
class QModbusReply;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QModbusClient *modbusDevice = nullptr;
void readDevice();
void toReadReady();
void on_writeTor();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Cpp文件如下
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QModbusTcpClient>
#include <QDebug>
#include <QThread>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
modbusDevice = new QModbusTcpClient();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if (!modbusDevice)
return;
if (modbusDevice->state() != QModbusDevice::ConnectedState) {
//处于非连接状态,进行连接
//TCP连接,端口502,地址192.168.0.1
modbusDevice->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);
modbusDevice->setConnectionParameter(QModbusDevice::NetworkAddressParameter, "192.168.0.1");
//连接超时设置,2000ms
modbusDevice->setTimeout(2000);
//连接失败重试连接,3次
modbusDevice->setNumberOfRetries(3);
//调试窗口显示连接状态
if (modbusDevice->connectDevice()) {
qDebug()<< "Connected!";
}
}
else {
//处在连接状态进行断开连接的操作
modbusDevice->disconnectDevice();
}
}
void MainWindow::readDevice()
{
if (!modbusDevice)
{
return;
}
qDebug()<<"read device";
QModbusDataUnit readUnit = QModbusDataUnit(QModbusDataUnit::HoldingRegisters, 0, 1);
if (auto *reply = modbusDevice->sendReadRequest(readUnit, 1)) //1->modbus设备地址
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, &MainWindow::toReadReady);
}
else
{
delete reply; // broadcast replies return immediately
}
}
else
{
//emit statusBar(tr("Read error: ") + modbusDevice->errorString());
}
QThread::msleep(1);
}
void MainWindow::toReadReady()
{
//QModbusReply这个类存储了来自client的数据,sender()返回发送信号的对象的指针
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
{
return;
}
if (reply->error() == QModbusDevice::NoError)
{
//处理成功返回的数据
const QModbusDataUnit unit = reply->result();
//quint16 stat = unit.value(1); //状态(位与关系)
int a = unit.value(0);
qDebug()<<a;
}
}
void MainWindow::on_pushButton_2_clicked()
{
readDevice();
}
void MainWindow::on_pushButton_3_clicked()
{
on_writeTor();
}
void MainWindow::on_writeTor()
{
QModbusDataUnit writeUnit(QModbusDataUnit::HoldingRegisters, 0, 1); // write 1 value in address 40003
writeUnit.setValue(0, 0x00C);
//这里先建好QModbusDataUnit
if (auto *reply = modbusDevice->sendWriteRequest(writeUnit, 1))
//发送写请求
{
if (!reply->isFinished())
{
connect(reply, &QModbusReply::finished, this, [this, reply]()
{
if (reply->error() != QModbusDevice::NoError)
// error in reply
reply->deleteLater();
});
}
else
{
if (reply->error() != QModbusDevice::NoError)
// error in reply
// broadcast replies return immediately
reply->deleteLater();
}
}
else
{
// error in request
}
}
写入和读取我挑一个说里面值得注意的地方
第一行的参数0代表第一个地址,上文PLC有介绍
第一行的参数1代表读一个
第二行的0代表要往0中写入数据
第二行的0x00C表示往0地址中写入16进制(十进制就是12)
UI界面就三个按钮
三、测试
首先打开PLC转至在线,监视STATUS,7002就是没有通讯
运行QT程序点击连接PLC变为7006就是通讯连接
监视监控表,这里的12是我测试的时候写进去的,你们的刚开始肯定是0
点击QT界面写入,检测到PLCM10.0出现数据12,如上图所示
点击QT界面读取,qDebug出来数据可以看到确实是读到了
至此QT7联合Modbus(TCP)读写PLC数据全部完成。
但是还有个问题就是只能读写int类型的数据,十进制转16进制的时候写不进PLC,PLC读入Real类型进QT的时候也只能是整数,这个问题还没有解决,不知道有没有大佬或者懂哥指点一下,谢谢了,实在是不太想再在CSDN里面“遨游”了(狗头)
感谢大家支持,希望对你们有帮助!!!