三菱PLC与上位机串口通信
一.三菱Fx系列PLC编程口通讯协议地址算法1.DEVICE READ(读出软设备状态值)2.DEVICE WRITE(向PLC 软设备写入值)3.位设备强制置位/复位4.三菱Fx系列PLC地址对应表二.源代码1.ui文件2.PlcConnection.h3.PlcConnection.cpp4.main.cpp参考资料:一.三菱Fx系列PLC编程口通讯协议地址算法
三菱PLC编程口通讯协议三菱PLC编程口的通讯协议只有四个命令:
五个标示:
使用累加方式的和校验,帧格式如下:
STX CMD DATA … DATA ETX SUM(upper) SUM(lower)
和校验:
SUM= CMD+……+ETX。 如SUM=73H,SUM=“73”。
1.DEVICE READ(读出软设备状态值)
计算机向PLC发送:
始命令 首地址 位数 终和校验
STX CMD GROUP ADDRESS BYTES ETX SUM
PLC 返回
STX 1ST DATA 2ND DATA … LAST DATA ETX SUM
2.DEVICE WRITE(向PLC 软设备写入值)
计算机向PLC发送:
始命令 首地址 位数 数据 终和校验
PLC 返回
ACK (06H) 接受正确
NAK (15H) 接受错误
3.位设备强制置位/复位
FORCE ON 置位
始命令 地址 终和校验
STX CMD ADDRESS ETX SUM
02H 37H ADDRESS 03H SUM
FORCE OFF 复位
始 命令 地址 终 和校验
STX CMD ADDRESS ETX SUM
02H 38H ADDRESS 03H SUM
PLC 返回
ACK(06H) 接受正确
NAK(15H) 接受错误
4.三菱Fx系列PLC地址对应表
以上就是这些协议,但是由于没有寄存器类型信息,所以地址的计算十分关键,如D100和M100分别对应哪个地址呢?下面就是三菱Fx系列PLC地址对应表。
Public Const PLC_D_Base_AddRess = 4096 Public Const PLC_D_Special_Base_AddRess = 3584 Public Const PLC_Y_Group_Base_AddRess = 160 Public Const PLC_PY_Group_Base_AddRess = 672 Public Const PLC_T_Group_Base_AddRess = 192 Public Const PLC_OT_Group_Base_AddRess = 704 Public Const PLC_RT_Group_Base_AddRess = 1216 Public Const PLC_M_SINGLE_Base_AddRess = 2048(命令为7或8时) Public Const PLC_M_Group_Base_AddRess = 256 Public Const PLC_PM_Group_Base_AddRess = 768 Public Const PLC_S_Group_Base_AddRess = 0 Public Const PLC_X_Group_Base_AddRess = 128 Public Const PLC_C_Group_Base_AddRess = 448 Public Const PLC_OC_Group_Base_AddRess = 960 Public Const PLC_RC_Group_Base_AddRess = 1472 Public Const PLC_TV_Group_Base_AddRess = 2048 Public Const PLC_CV16_Group_Base_AddRess = 2560 Public Const PLC_CV32_Group_Base_AddRess = 3072
当我们用DEVICE READ命令时,D100地址=100*2+4096;M100地址=100+256;不同的是D类型寄存器存放的是字,M寄存器存放的是位,同样是读两个字节,D100返回的就是PLC中D100地址的值,M类型寄存器返回的是M100到M116的值。所以当我们用FORCE ON 命令时,M100寄存器地址=100+2048;
但三菱公司好像不甘于如此,FORCE ON/Off命令中地址排列与DEVICE READ/WRITE不同,是低位在前高位在后。如Y20,地址是0510H,代码中4个字节地址表示为:1005。(注意:Y寄存器为八进制,如Y20地址=16+1280=0510H)
二.源代码
1.ui文件
2.PlcConnection.h
#ifndef MAINWINDOW_H#define MAINWINDOW_H#include "ui_PlcConnection.h"#include <QtWidgets/QMainWindow>#include <QtSerialPort/QSerialPort>#include <QtSerialPort/QSerialPortInfo>#include <QtNetwork/QtNetwork>#include <QAbstractScrollArea>//#include <QTextCursor>#include <iostream>using namespace std;#define STX 0x02 //报文开始#define ETX 0x03 //文本结束#define EOT 0x04 //传送结束#define ENQ 0x05 //查询#define ACK 0x06 //PLC肯定响应#define NAK 0x15 //PLC否定响应#define DEVICE_READ_CMD '0' //读命令,适用软元件X、Y、M、S、T、C、D#define DEVICE_WRITE_CMD '1' //写命令,适用软元件X、Y、M、S、T、C、D#define FORCE_ON_CMD'7' //强制通命令,适用软元件X、Y、M、S、T、C#define FORCE_OFF_CMD '8' //强制断命令,适用软元件X、Y、M、S、T、Cnamespace Ui{class PlcConnection;}class PlcConnection : public QMainWindow{Q_OBJECTpublic:PlcConnection(QWidget *parent = Q_NULLPTR);//explicit PlcConnection(QWidget* parent = nullptr);//~PlcConnection();private:Ui::PlcConnectionClass ui;QSerialPort serial;//声明串口类//public:private://QSerialPort serial;//声明串口类QTcpServer* server;QTcpSocket* client;QUdpSocket* sender;QUdpSocket* receiver;QTcpSocket* clientConnection[10];quint8 index;QTimer testTimer;quint16 port_old;quint16 flag;QHostAddress serverAddress;QByteArray datagram;QTimer* timer;//public:private:void find_seralport();char ConvertHexChar(char ch);void StringToHex(QString str, QByteArray& senddata); //字符串转换为十六进制数据0-Fvoid on_time_scan_serial();uint8_t sum8(uint8_t data[], uint32_t len); //累加和int buf2value(char* b);private slots:void on_openPortBtn_clicked();void read_Com();//手动添加的槽函数声明,用于读出串口缓冲区的内容void on_sendButton_clicked();void on_pushButton_2_clicked();void testFunction();//void on_BaudBox_currentTextChanged(const QString &arg1);void onTimeOut();void on_sendButton_2_clicked();void on_sendButton_3_clicked();void on_sendButton_4_clicked();void on_sendButton_5_clicked();};#endif // MAINWINDOW_H
3.PlcConnection.cpp
#include "PlcConnection.h"#include <QTimer>#include <QMessageBox>#include "ui_PlcConnection.h"PlcConnection::PlcConnection(QWidget *parent):QMainWindow(parent){ui.setupUi(this);//关闭发送按钮禁能ui.sendButton->setEnabled(false);ui.sendButton_2->setEnabled(false);ui.sendButton_3->setEnabled(false);ui.sendButton_4->setEnabled(false);ui.sendButton_5->setEnabled(false);/*查找可用的串口*/find_seralport();ui.BaudBox->setCurrentText("9600");ui.BitNumBox->setCurrentText("7 bit");ui.ParityBox->setCurrentText("EVEN");//on_time_scan_serial();}/* 串口读取回调 */void PlcConnection::read_Com(){qDebug("aaa");/* 信号到来,读取所有的字符串 */QByteArray buf = serial.readAll();QDataStream out(&buf, QIODevice::ReadWrite); //将字节数组读入while (!out.atEnd()){qint8 outChar = 0;out >> outChar; //每字节填充一次,直到结束//十六进制的转换QString str = QString("%1").arg(outChar & 0xFF, 2, 16, QLatin1Char('0'));qDebug() << str;ui.recvTextBrowser->insertPlainText(str);ui.recvTextBrowser->insertPlainText(" ");}char* b = buf.data();int length = buf.length();if (length != 0)ui.recvTextBrowser->insertPlainText("\n");printf("receive:%d\n", length);for (int i = 0; i < length; i++){printf("0x%02x ", b[i]);}printf("\n");qDebug() << "length:" << length;if (length > 1){static char bb[500];static int index;uint8_t sum = sum8((uint8_t*)b + 1, length - 3);unsigned int temp = 0;sscanf(b + length - 2, "%02x", &temp);printf("temp = 0x%x\n", temp);printf("sum = 0x%x\n", sum);if (temp == sum && b[0] == 0x02){printf("check sum OK\n");index = 0;QString display;for (int i = 0; i < (length - 4) / 4; i++){int v = buf2value(b + 1 + i * 4);display += QString::number(v) + ",";}ui.lineEdit->setText(display);}else{printf("check sum failed\n");memcpy(bb + index, b, length);index += length;uint8_t sum = sum8((uint8_t*)bb + 1, index - 3);unsigned int temp = 0;printf("index = %d\n", index);sscanf(bb + index - 2, "%02x", &temp);printf("temp = 0x%x\n", temp);printf("sum = 0x%x\n", sum);for (int i = 0; i < index; i++){printf("%02x ", bb[i]);}printf("\n");if (temp == sum){printf("check sum OK\n");QString display;for (int i = 0; i < (index - 4) / 4; i++){int v = buf2value(bb + 1 + i * 4);display += QString::number(v) + ",";}ui.lineEdit->setText(display);index = 0;}else{printf("check sum failed\n");buf.clear();fflush(stdout);return;}fflush(stdout);}}else if (length == 1){if (b[0] == 0x06){qDebug() << "写入成功";}else if (b[0] == 0x15){qDebug() << "写入失败";}}buf.clear();fflush(stdout);}/**************** 读取 ***************/void PlcConnection::on_sendButton_2_clicked(){/* 首地址 */int addr = ui.spinBox->value();qDebug() << addr;if (addr >= 0 && addr < 1024){uint8_t buf1[100] = {0x02, DEVICE_READ_CMD, }; //起始、命令int d_addr = 0;if (boBox->currentText() == "S")d_addr = addr * 2 + 0x0000;else if (boBox->currentText() == "X")d_addr = addr * 2 + 0x0080;else if (boBox->currentText() == "Y")d_addr = addr * 2 + 0x00A0;else if (boBox->currentText() == "T")d_addr = addr * 2 + 0x00C0;else if (boBox->currentText() == "M") /**/d_addr = addr * 2 + 0x0100;else if (boBox->currentText() == "C")d_addr = addr * 2 + 0x01C0;else if (boBox->currentText() == "D") /**/d_addr = addr * 2 + 0x1000;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);/* 地址不需要倒序,值需要倒序 */for (int i = 0; i < 4; i++)buf1[2 + i] = d_addr_str[i];/* 字节数 */char count_str[3] = {0 };int count = ui.spinBox_2->value() * 2;snprintf(count_str, 3, "%02X", count);buf1[6] = count_str[0];buf1[7] = count_str[1];/* 结束 */buf1[8] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 8);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[9] = sum_str[0];buf1[10] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 11; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 11);QString str;for (int i = 0; i < 11; i++){char tmp[4] = {0 };sprintf(tmp, "%02x ", buf1[i]);str += tmp;}qDebug() << str;ui.lineEdit_sand1_2->setText(str);}else if (addr >= 8000 && addr < 8512){uint8_t buf1[100] = {0x02, 'E', '0', '0', }; //起始、命令int d_addr = (addr - 8000) * 2;d_addr += 0x8000;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);for (int i = 0; i < 4; i++)buf1[4 + i] = d_addr_str[i];/* 字节数 */char count_str[3] = {0 };int count = ui.spinBox_2->value() * 2;snprintf(count_str, 3, "%02X", count);buf1[8] = count_str[0];buf1[9] = count_str[1];/* 结束 */buf1[10] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 10);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[11] = sum_str[0];buf1[12] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 13; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 13);}fflush(stdout);}/********************** 写入 **********************/void PlcConnection::on_sendButton_3_clicked(){uint8_t buf1[100] = {0x02, DEVICE_WRITE_CMD, }; //起始、命令:写/* 首地址 */int addr = ui.spinBox->value();if (addr >= 0 && addr < 1024){int d_addr = 0;if (boBox->currentText() == "S")d_addr = addr * 2 + 0x0000;else if (boBox->currentText() == "Y")d_addr = addr * 2 + 0x00A0;else if (boBox->currentText() == "X")d_addr = addr * 2 + 0x0080;else if (boBox->currentText() == "T")d_addr = addr * 2 + 0x00C0;else if (boBox->currentText() == "M")d_addr = addr * 2 + 0x0100;else if (boBox->currentText() == "C")d_addr = addr * 2 + 0x01C0;else if (boBox->currentText() == "D")d_addr = addr * 2 + 0x1000;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);for (int i = 0; i < 4; i++)buf1[2 + i] = d_addr_str[i];/* 字节数 */char count_str[3] = {0 };int count = ui.spinBox_2->value() * 2;snprintf(count_str, 3, "%02X", count);buf1[6] = count_str[0];buf1[7] = count_str[1];count /= 2;QString str = ui.lineEdit->text();QStringList list = str.split(",", QString::SkipEmptyParts);qDebug() << list.length();if (list.length() < count){qDebug() << "请输入足够多的数据";QMessageBox::critical(nullptr, "提醒", "请输入足够多的数据", QMessageBox::Ok, 0);return;}char v[5][5];for (int i = 0; i < count; i++){qDebug() << list[i];QByteArray ba = list.at(i).toLatin1();char* c_str = ba.data();snprintf(v[i], 5, "%04X", atoi(c_str));qDebug() << v[i];buf1[8 + i * 4 + 2] = v[i][0];buf1[8 + i * 4 + 3] = v[i][1];buf1[8 + i * 4 + 0] = v[i][2];buf1[8 + i * 4 + 1] = v[i][3];}/* 结束 */buf1[8 + count * 4] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 8 + count * 4);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[9 + count * 4] = sum_str[0];buf1[10 + count * 4] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 11 + count * 4; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 11 + count * 4);fflush(stdout);}else if (addr >= 8000 && addr < 8512){uint8_t buf1[100] = {0x02, 'E', '1', '0', }; //起始、命令:写int d_addr = (addr - 8000) * 2;d_addr += 0x8000;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);for (int i = 0; i < 4; i++)buf1[4 + i] = d_addr_str[i];/* 字节数 */char count_str[3] = {0 };int count = ui.spinBox_2->value() * 2;snprintf(count_str, 3, "%02X", count);buf1[8] = count_str[0];buf1[9] = count_str[1];count /= 2;QString str = ui.lineEdit->text();QStringList list = str.split(",");qDebug() << list.length();if (list.length() < count){qDebug() << "请输入足够多的数据";QMessageBox::critical(0, "提醒", "请输入足够多的数据", QMessageBox::Ok, 0);return;}char v[5][5] = {{0} };for (int i = 0; i < count; i++){qDebug() << list[i];QByteArray ba = list.at(i).toLatin1();char* c_str = ba.data();snprintf(v[i], 5, "%04X", atoi(c_str));qDebug() << v[i];buf1[10 + i * 4 + 2] = v[i][0];buf1[10 + i * 4 + 3] = v[i][1];buf1[10 + i * 4 + 0] = v[i][2];buf1[10 + i * 4 + 1] = v[i][3];}/* 结束 */buf1[10 + count * 4] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 10 + count * 4);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[11 + count * 4] = sum_str[0];buf1[12 + count * 4] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 13 + count * 4; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 13 + count * 4);fflush(stdout);}}/* 累加和 */uint8_t PlcConnection::sum8(uint8_t data[], uint32_t len){uint8_t sum = 0;for (uint32_t i = 0; i < len; i++){sum += data[i];}return sum;}/* 打开串口 */void PlcConnection::on_openPortBtn_clicked(){if (ui.openPortBtn->text() == "打开"){ui.openPortBtn->setText("关闭");//按下“OpenPort”后,按键显示为“ClosePort”// if(ui->openPortBtn->text() == "打开")// ui->PortBox->setDisabled(true);//按下“OpenPort”后,禁止再修改COM口serial.setPortName(ui.PortBox->currentText());//设置COM口QSerialPort::BaudRate baud_rate = QSerialPort::Baud115200;if (ui.BaudBox->currentText() == "1200")baud_rate = QSerialPort::Baud1200;else if (ui.BaudBox->currentText() == "9600")baud_rate = QSerialPort::Baud9600;else if (ui.BaudBox->currentText() == "2400")baud_rate = QSerialPort::Baud2400;else if (ui.BaudBox->currentText() == "4800")baud_rate = QSerialPort::Baud4800;else if (ui.BaudBox->currentText() == "9600")baud_rate = QSerialPort::Baud9600;else if (ui.BaudBox->currentText() == "19200")baud_rate = QSerialPort::Baud19200;else if (ui.BaudBox->currentText() == "38400")baud_rate = QSerialPort::Baud38400;else if (ui.BaudBox->currentText() == "57600")baud_rate = QSerialPort::Baud57600;else if (ui.BaudBox->currentText() == "115200")baud_rate = QSerialPort::Baud115200;serial.setBaudRate(baud_rate); //设置波特率QSerialPort::DataBits data_bits = QSerialPort::Data8;if (ui.BitNumBox->currentText() == "8 bit")data_bits = QSerialPort::Data8;else if (ui.BitNumBox->currentText() == "7 bit")data_bits = QSerialPort::Data7;else if (ui.BitNumBox->currentText() == "6 bit")data_bits = QSerialPort::Data6;else if (ui.BitNumBox->currentText() == "5 bit")data_bits = QSerialPort::Data5;serial.setDataBits(data_bits);//设置数据位serial.setFlowControl(QSerialPort::NoFlowControl);//无流控制QSerialPort::Parity parity = QSerialPort::NoParity;if (ui.ParityBox->currentText() == "NONE")parity = QSerialPort::NoParity;else if (ui.ParityBox->currentText() == "EVEN")parity = QSerialPort::EvenParity;else if (ui.ParityBox->currentText() == "ODD")parity = QSerialPort::OddParity;else if (ui.ParityBox->currentText() == "SPACE")parity = QSerialPort::SpaceParity;else if (ui.ParityBox->currentText() == "MARK")parity = QSerialPort::MarkParity;serial.setParity(parity); //设置校验位QSerialPort::StopBits stop_bits = QSerialPort::OneStop;if (ui.StopBox->currentText() == "1 bit")stop_bits = QSerialPort::OneStop;else if (ui.StopBox->currentText() == "1.5 bit")stop_bits = QSerialPort::OneAndHalfStop;else if (ui.StopBox->currentText() == "5 bit")stop_bits = QSerialPort::TwoStop;serial.setStopBits(stop_bits);//设置停止位serial.close();//先关串口,再打开,可以保证串口不被其它函数占用。if (serial.open(QIODevice::ReadWrite))//以可读写的方式打开串口{connect(&serial, SIGNAL(readyRead()), this, SLOT(read_Com()));//把串口的readyRead()信号绑定到read_Com()这个槽函数上}ui.sendButton->setEnabled(true);ui.sendButton_2->setEnabled(true);ui.sendButton_3->setEnabled(true);ui.sendButton_4->setEnabled(true);ui.sendButton_5->setEnabled(true);}else{ui.openPortBtn->setText("打开");//按下“ClosePort”后,按键显示为“OpenPort”ui.PortBox->setEnabled(true);//按下“ClosePort”后,COM口可被修改serial.close();//关串口//关闭发送按钮的使能ui.sendButton->setEnabled(false);ui.sendButton_2->setEnabled(false);ui.sendButton_3->setEnabled(false);ui.sendButton_4->setEnabled(false);ui.sendButton_5->setEnabled(false);}}/* 清除按钮 */void PlcConnection::on_pushButton_2_clicked(){ui.recvTextBrowser->clear();}void PlcConnection::testFunction(){// qDebug() << clientConnection[0]->read(1);}int PlcConnection::buf2value(char* b){char a[4] = {0 };a[0] = b[2];a[1] = b[3];a[2] = b[0];a[3] = b[1];for (int i = 0; i < 4; i++)printf("%c ", a[i]);printf("\n");int v = 0;sscanf(a, "%04x", &v);// printf("v = %d\n", v);return v;}void PlcConnection::on_sendButton_clicked(){/* 串口发送 */// serial.write(ui->textEdit_2->toPlainText().toLatin1());char buf1[100] = {0x00 };/* 提取参数 */QString sand_str(ui.lineEdit_sand1_2->text());QString temp;int cnt = 0;for (int i = 0; ; i++){temp = sand_str.left(2);if (temp == "")break;buf1[i] = temp.toInt(nullptr, 16);// qDebug() << buf1[i];sand_str = sand_str.mid(3);qDebug() << temp;cnt++;}// clientConnection[ui->comboBox_2->currentIndex()]->write(buf1, cnt);// serial.write(ui->textEdit_2->toPlainText().toLatin1());serial.write(buf1, cnt);}/* 查找可用的串口 */void PlcConnection::find_seralport(){foreach(const QSerialPortInfo & info, QSerialPortInfo::availablePorts()){QSerialPort serial;serial.setPort(info);if (serial.open(QIODevice::ReadWrite)){ui.PortBox->addItem(serial.portName());serial.close();}}}void PlcConnection::on_time_scan_serial(){timer = new QTimer;connect(timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));timer->start(1000);}void PlcConnection::onTimeOut(){find_seralport();qDebug() << "aaa";}//void MainWindow::on_BaudBox_currentTextChanged(const QString &arg1)//{// qDebug() << arg1;// MainWindow::on_openPortBtn_clicked();//}/* 转换 */void PlcConnection::StringToHex(QString str, QByteArray& senddata) //字符串转换为十六进制数据0-F{int hexdata, lowhexdata;int hexdatalen = 0;int len = str.length();senddata.resize(len / 2);char lstr, hstr;for (int i = 0; i < len; ){//char lstr,hstr = str[i].toLatin1();if (hstr == ' '){i++;continue;}i++;if (i >= len)break;lstr = str[i].toLatin1();hexdata = ConvertHexChar(hstr);lowhexdata = ConvertHexChar(lstr);if ((hexdata == 16) || (lowhexdata == 16))break;elsehexdata = hexdata * 16 + lowhexdata;i++;senddata[hexdatalen] = (char)hexdata;hexdatalen++;}senddata.resize(hexdatalen);}char PlcConnection::ConvertHexChar(char ch){if ((ch >= '0') && (ch <= '9'))return ch - 0x30;else if ((ch >= 'A') && (ch <= 'F'))return ch - 'A' + 10;else if ((ch >= 'a') && (ch <= 'f'))return ch - 'a' + 10;else return ch - ch;//不在0-f范围内的会发送成0}/* 设置 */void PlcConnection::on_sendButton_4_clicked(){/* 首地址 */int addr = ui.spinBox_3->value();if (addr >= 0 && addr < 1024){uint8_t buf1[100] = {0x02, FORCE_ON_CMD, }; //起始、命令:写int d_addr = 0;if (boBox_2->currentText() == "S")d_addr = addr * 1 + 0x0000;else if (boBox_2->currentText() == "X")d_addr = addr * 2 + 0x0400;else if (boBox_2->currentText() == "Y")d_addr = addr * 1 + 0x0500;else if (boBox_2->currentText() == "T")d_addr = addr * 1 + 0x0600;else if (boBox_2->currentText() == "M")d_addr = addr * 1 + 0x0800;else if (boBox_2->currentText() == "C")d_addr = addr * 1 + 0x0E00;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);for (int i = 0; i < 2; i++)buf1[2 + i + 2] = d_addr_str[i];for (int i = 0; i < 2; i++)buf1[2 + i] = d_addr_str[i + 2];/* 结束 */buf1[6] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 6);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[7] = sum_str[0];buf1[8] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 9; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 9);fflush(stdout);//清空缓存区}else if (addr >= 8000 && addr < 8512){uint8_t buf1[100] = {0x02, 'E', '7', }; //起始、命令:写int d_addr = 0;addr -= 8000;d_addr = addr * 1 + 0x6000;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);for (int i = 0; i < 2; i++)buf1[3 + i + 2] = d_addr_str[i];for (int i = 0; i < 2; i++)buf1[3 + i] = d_addr_str[i + 2];/* 结束 */buf1[7] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 7);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[8] = sum_str[0];buf1[9] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 10; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 10);fflush(stdout);}}/* 清除 */void PlcConnection::on_sendButton_5_clicked(){/* 首地址 */int addr = ui.spinBox_3->value();if (addr >= 0 && addr < 1024){uint8_t buf1[100] = {0x02, FORCE_OFF_CMD, }; //起始、命令:写int d_addr = 0;if (boBox_2->currentText() == "S")d_addr = addr * 1 + 0x0000;else if (boBox_2->currentText() == "X")d_addr = addr * 2 + 0x0400;else if (boBox_2->currentText() == "Y")d_addr = addr * 1 + 0x0500;else if (boBox_2->currentText() == "T")d_addr = addr * 1 + 0x0600;else if (boBox_2->currentText() == "M")d_addr = addr * 1 + 0x0800;else if (boBox_2->currentText() == "C")d_addr = addr * 1 + 0x0E00;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);for (int i = 0; i < 2; i++)buf1[2 + i + 2] = d_addr_str[i];for (int i = 0; i < 2; i++)buf1[2 + i] = d_addr_str[i + 2];/* 结束 */buf1[6] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 6);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[7] = sum_str[0];buf1[8] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 9; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 9);fflush(stdout);}else if (addr >= 8000 && addr < 8512){uint8_t buf1[100] = {0x02, 'E', '8', }; //起始、命令:写int d_addr = 0;addr -= 8000;d_addr = addr * 1 + 0x6000;char d_addr_str[5] = {0 };snprintf(d_addr_str, 5, "%04X", d_addr);for (int i = 0; i < 2; i++)buf1[3 + i + 2] = d_addr_str[i];for (int i = 0; i < 2; i++)buf1[3 + i] = d_addr_str[i + 2];/* 结束 */buf1[7] = ETX;/* 累加和 *///从命令开始到结束为止的每一个字节累加和(不包括起始字节)uint8_t sum = sum8(buf1 + 1, 7);char sum_str[3] = {0 };snprintf(sum_str, 3, "%02X", sum);buf1[8] = sum_str[0];buf1[9] = sum_str[1];/* 打印 */printf("send:\n");for (int i = 0; i < 10; i++)printf("%02x ", buf1[i]);printf("\n");serial.write((char*)buf1, 10);fflush(stdout);}}
4.main.cpp
#pragma execution_character_set("utf-8")#include "PlcConnection.h"#include <QtWidgets/QApplication>int main(int argc, char *argv[]){QApplication a(argc, argv);PlcConnection w;w.setWindowTitle("三菱FX3U编程口通信助手");w.show();return a.exec();}
运行结果:
参考资料:
我还下了网上两个别人的实例,若有需要参考的评论区留下邮箱,我把那两个工程文件发给你。。。