三菱PLC与上位机进行通讯

三菱PLC与上位机串口通信

  • 一.三菱Fx系列PLC编程口通讯协议地址算法
    • 1.DEVICE READ(读出软设备状态值)
    • 2.DEVICE WRITE(向PLC 软设备写入值)
    • 3.位设备强制置位/复位
    • 4.三菱Fx系列PLC地址对应表
  • 二.源代码
    • 1.ui文件
    • 2.PlcConnection.h
    • 3.PlcConnection.cpp
    • 4.main.cpp
  • 参考资料:

一.三菱Fx系列PLC编程口通讯协议地址算法

三菱PLC编程口通讯协议三菱PLC编程口的通讯协议只有四个命令

命令 命令码 目标设备
DEVICE READ CMD “0” X,Y,M,S,T,C,D
DEVICE WRITE CMD “1” X,Y,M,S,T,C,D
FORCE ON CMD “7” X,Y,M,S,T,C
FORCE OFF CMD “8” X,Y,M,S,T,C

五个标示

ENQ 05H 请求
ACK 06H PLC正确响应
NAK 15H PLC错误响应
STX 02H 报文开始
ETX 03H 报文结束

使用累加方式的和校验,帧格式如下:
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(命令为78) 
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文件

三菱PLC与上位机进行通讯_第1张图片

2.PlcConnection.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "ui_PlcConnection.h"

#include 
#include 
#include 
#include 
#include 


//#include 

#include 

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、C

namespace Ui
{
    class PlcConnection;
}

class PlcConnection : public QMainWindow
{
    Q_OBJECT

public:
    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-F
    void 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 
#include 
#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 (ui.comboBox->currentText() == "S")
            d_addr = addr * 2 + 0x0000;
        else if (ui.comboBox->currentText() == "X")
            d_addr = addr * 2 + 0x0080;
        else if (ui.comboBox->currentText() == "Y")
            d_addr = addr * 2 + 0x00A0;
        else if (ui.comboBox->currentText() == "T")
            d_addr = addr * 2 + 0x00C0;
        else if (ui.comboBox->currentText() == "M")  /**/
            d_addr = addr * 2 + 0x0100;
        else if (ui.comboBox->currentText() == "C")
            d_addr = addr * 2 + 0x01C0;
        else if (ui.comboBox->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 (ui.comboBox->currentText() == "S")
            d_addr = addr * 2 + 0x0000;
        else if (ui.comboBox->currentText() == "Y")
            d_addr = addr * 2 + 0x00A0;
        else if (ui.comboBox->currentText() == "X")
            d_addr = addr * 2 + 0x0080;
        else if (ui.comboBox->currentText() == "T")
            d_addr = addr * 2 + 0x00C0;
        else if (ui.comboBox->currentText() == "M")
            d_addr = addr * 2 + 0x0100;
        else if (ui.comboBox->currentText() == "C")
            d_addr = addr * 2 + 0x01C0;
        else if (ui.comboBox->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;
        else
            hexdata = 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 (ui.comboBox_2->currentText() == "S")
            d_addr = addr * 1 + 0x0000;
        else if (ui.comboBox_2->currentText() == "X")
            d_addr = addr * 2 + 0x0400;
        else if (ui.comboBox_2->currentText() == "Y")
            d_addr = addr * 1 + 0x0500;
        else if (ui.comboBox_2->currentText() == "T")
            d_addr = addr * 1 + 0x0600;
        else if (ui.comboBox_2->currentText() == "M")
            d_addr = addr * 1 + 0x0800;
        else if (ui.comboBox_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 (ui.comboBox_2->currentText() == "S")
            d_addr = addr * 1 + 0x0000;
        else if (ui.comboBox_2->currentText() == "X")
            d_addr = addr * 2 + 0x0400;
        else if (ui.comboBox_2->currentText() == "Y")
            d_addr = addr * 1 + 0x0500;
        else if (ui.comboBox_2->currentText() == "T")
            d_addr = addr * 1 + 0x0600;
        else if (ui.comboBox_2->currentText() == "M")
            d_addr = addr * 1 + 0x0800;
        else if (ui.comboBox_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 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    PlcConnection w;
    w.setWindowTitle("三菱FX3U编程口通信助手");
    w.show();

    return a.exec();
}

运行结果:
三菱PLC与上位机进行通讯_第2张图片

参考资料:

我还下了网上两个别人的实例,若有需要参考的评论区留下邮箱,我把那两个工程文件发给你。。。
三菱PLC与上位机进行通讯_第3张图片
三菱PLC与上位机进行通讯_第4张图片

你可能感兴趣的:(海康威视工业相机,串口通信,plc,c++)