作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
之前博主写过一篇通过 MX 插件与三菱PLC通信的文章,具体请参考:Qt使用 MX Component 插件与三菱PLC通信
使用 MX 插件有一个弊端,那就是 MX 插件提供的 COM 组件是 32 位的,如果是 64 位的编译器则无法使用。因为一些特殊因素的影响,我们的项目需要从 32 位转到 64 位,所以 PLC 通信这一块就不能再使用 MX 插件了。考虑到我们的 PLC 是三菱Q系列,所以博主选择了 MC 协议。
从三菱官网下载了协议文档,也从网上查找了一些资料,发现都是对 MC 协议的解析,也有一些已经实现了的第三方库,但是没有实际的代码可以参考,而且第三方库都是 VB、C# 的。于是,博主自己做了一个例子,在这里分享一下,希望对大家有所帮助。
为了方便初学者快速上手,博主标记了一些重要的页数,方便快速切换查看:
MC 协议的功能
外部设备(个人计算机、显示器等)可以通过 MC 协议来管理可编程控制器设备的数据通信,简单来说就是允许外部设备通过 MC 协议来读写 PLC 里的寄存器。
通信方式
MC 协议的通讯方式有很多种:4C、3C、2C、1C、4E、3E、1E帧格式
数据格式分为二进制格式和ASCII码格式:
以二进制代码进行数据通信时,将2字节的数值从低位字节(L:位0~7)进行发送
以ASCII代码进行数据通信时,将数值转换为ASCII代码4位(16进制数)后从高位进行发送
博主选择的是最大众的:3E + 二进制格式
从地址 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
下载 GX Works2
下载地址:网盘下载
提取码:2q5d
我的工程分享
下载地址:网盘下载
提取码:zxi9
在 pro 中添加网络模块
使用 TCP 需要在 pro 文件中添加 network 模块:
QT += network
核心代码
初始化,绑定信号槽
// init
network = new QTcpSocket(this);
timeout = 1000;
connect(network, &QTcpSocket::connected, [](){ qDebug() << "Connected to PLC successfully !" << endl; });
connect(network, &QTcpSocket::disconnected, [](){ qDebug() << "Disconnected from plc !" << endl; });
connect(network, &QTcpSocket::stateChanged, [](QAbstractSocket::SocketState socketState){
qDebug() << "SocketState changed: " << socketState;
});
connect(network, &QTcpSocket::readyRead, [&](){ readData(); });
通过 ip 地址和端口号连接 PLC
network->connectToHost(ui->ip->text(), ui->port->text().toInt());
network->waitForConnected(timeout)
按照 MC 协议发送数据给 PLC
QString head = "50 00 00 FF FF 03 00";
QString length;
QString timeout = "10 00";
QString command = "01 14";
QString subCommand = "00 00";
QString address = convert10216(ui->address->text().toInt(), 6);
QString soft = ui->comboBox->currentIndex() == 0 ? "A8" : "90";
QString count = convert10216(ui->length->text().toInt(), 4);
QString data = timeout + " " + command + " " + subCommand + " " + address + " " + soft + " " + count + " " + str;
QString temp = data;
QRegExp regExp("[^a-fA-F0-9]");
temp.replace(regExp, "");
int len = temp.length()/2;
length = convert10216(len, 4);
QString ret = head + " " + length + " " + data;
QByteArray array = QByteArray::fromHex(ret.toLatin1()); // 使用 16 进制格式
network->write(array);
network->waitForBytesWritten();
network->flush();
接收 PLC 的响应
QByteArray array = network->readAll();
QString ret = array.toHex().toUpper();