2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Qt下实现欧姆龙PLC 串口发送HOSTLINK(FINS)模式

Qt下实现欧姆龙PLC 串口发送HOSTLINK(FINS)模式

时间:2020-12-03 01:21:50

相关推荐

Qt下实现欧姆龙PLC 串口发送HOSTLINK(FINS)模式

文章目录

前言一、HOSTLINK协议说明二、校验码(FCS)计算三、示例完整代码四、下载链接总结

前言

本文讲述了Qt下模拟串口调试工具发送HOSTLINK(FINS)模式,主要进行了HR保持区的字和位的读写,对HOSTLINK协议中校验码(FCS)的计算方式进行了展示,详情可见下文代码,希望可以帮助到大家,如有错误之处,欢迎大家批评指正。

项目效果

提示:以下是本篇文章正文内容,下面案例可供参考

一、HOSTLINK协议说明

HOSTLINK(FINS)命令细化的格式内容如下图所示

这里对FINS的命令格式进行解释(详细内容可见说明书)

(a)、command code(命令代码)

0101 :读命令

0102 :写命令

(b)、IO Memory Area Code(内存区域地址)

WR(Word):B1

WR(Bit):31

HR(Word):B2

HR(Bit):32

… …

此处以示例来进行上述格式说明:

//单写HR字地址(HR1写入数据1) 写:0102 字:B2

@ 00 FA 0 00 00 00 00 0102 B2 00 01(address) 00 00 01 0001(data) **(FCS) *\CR

//单读HR字地址(读取HR1地址上的数值) 读:0101 字:B2

@ 00 FA 0 00 00 00 00 0101 B2 00 01(address) 00 00 01 **(FCS) *\CR

//单写HR位地址(对HR1.01位写入数据1) 写:0102 位:32

@ 00 FA 0 00 00 00 00 0102 32 00 0101(address) 00 01 01(data) **(FCS) *\CR

//单读HR位地址(读取HR1.01位上的数值) 读:0101 位:32

@ 00 FA 0 00 00 00 00 0101 32 00 0101(address) 00 01 **(FCS) *\CR

二、校验码(FCS)计算

协议中FCS栏位:占用两个字符,取值为从@开始到正文结束的所有字符的ASCⅡ码按位异或运算的结果。计算校验码的步骤:

1.先进行输入地址位的转换

2.界面上显示的是ASCII字符,将界面上字符转化为十进制后进行按位异或运算

3.按位运算后的结果转换为16进制即为校验码

三、示例完整代码

1.示例中用到了串口相关函数,所以需要在pro中添加下列代码:

QT += serialport

2.serialport.h

#ifndef SERIALPORT_H#define SERIALPORT_H#include <QWidget>#include <QSerialPort>#include <QSerialPortInfo>#include <QMessageBox>#include <QDebug>QT_BEGIN_NAMESPACEnamespace Ui {class SerialPort; }QT_END_NAMESPACEclass SerialPort : public QWidget{Q_OBJECTpublic:SerialPort(QWidget *parent = nullptr);~SerialPort();void initWidget();private slots:void slot_serialRead();void slot_writeHRWordData(int address, int numWrite);void slot_readHRWordData(int address);void slot_writeHRBitData(int address, int bit, int numWrite);void slot_readHRBitData(int address, int bit);void on_pb_refresh_clicked();void on_pb_operate_clicked();void on_pb_send_clicked();void on_rb_read_clicked();void on_rb_write_clicked();private:Ui::SerialPort *ui;QSerialPort *serial;};#endif // SERIALPORT_H

3.serialport.cpp

#include "serialport.h"#include "ui_serialport.h"SerialPort::SerialPort(QWidget *parent): QWidget(parent), ui(new Ui::SerialPort){ui->setupUi(this);this->initWidget();}SerialPort::~SerialPort(){delete ui;}void SerialPort::initWidget(){this->setWindowTitle("HOSTLINK(FINS)读写测试");setFixedSize(this->width(),this->height());ui->rb_read->setChecked(true);ui->le_num->setEnabled(false);ui->pb_send->setEnabled(false);//初始化串口serial = new QSerialPort(this);connect(serial,SIGNAL(readyRead()),this,SLOT(slot_serialRead()));}void SerialPort::slot_serialRead(){QByteArray receiveBuf = serial->readAll();QString receiveStr = QString(receiveBuf);//qDebug()<<"receiveStr:"<<receiveStr;int sizeNum = receiveStr.size();QString showStr = receiveStr.left(sizeNum - 1);ui->plainTextEdit->appendPlainText("接收命令:\n" + showStr + "\\CR");QString leftStr = receiveStr.left(sizeNum - 4);//qDebug()<<"leftStr:"<<leftStr;QString rightStr = leftStr.right(sizeNum - 4 - 23);//qDebug()<<"receiveStr:"<<receiveStr<<" leftStr:"<<leftStr<<" rightStr:"<<rightStr;//rightStr需要视情况而定ui->le_num->setText(rightStr);}//单写HR字地址void SerialPort::slot_writeHRWordData(int address,int numWrite){//H保持区 字:B2 位:32//@ 00 FA 0 00 00 00 00 0102 B2 00 01(address) 00 00 01 0001(data) **(FCS) *\CR//QString testStr = "@00FA0000000000102B200010000010001";//addressQString startStr = "@00FA0000000000102B200";int adsNum[2];QByteArray hrBa;hrBa.setNum(address,16);if(address < 16){adsNum[0] = 0;adsNum[1] = address;startStr.append("0" + QString(hrBa) + "000001");}else{adsNum[0] = (int)hrBa.at(0);adsNum[1] = (int)hrBa.at(1);startStr.append(QString(hrBa) + "000001");}//qDebug()<<"num[0]:"<<num[0]<<" num[1]:"<<num[1];//numWrite 根据写入值长度变化#if 0QString numStr = QString::number(numWrite);QByteArray numBa = numStr.toLatin1();qDebug()<<"numBa:"<<numBa;int numSize = numStr.size();int numEnd = numSize;//qDebug()<<"numSize:"<<numSize;if(numSize%2){numEnd = numSize + 1;}//qDebug()<<"numEnd:"<<numEnd;int numNum[numEnd];if(numSize%2){numNum[0] = 0;for(int i=1;i<numEnd;i++){numNum[i] = (int)numBa.at(i-1);}startStr.append("0" + QString(numBa));}else{for(int i=0;i<numEnd;i++){numNum[i] = (int)numBa.at(i);}startStr.append(QString(numBa));}#elseQString finStr = "";QString numStr = QString::number(numWrite);int numSize = numStr.size();if(numSize < 4){for(int i=numSize;i<4;i++){finStr.append("0");}finStr += numStr;}else if(numSize == 4){finStr = numStr;}else if(numSize == 5){finStr = "0" + numStr;}else if(numSize == 6){finStr = numStr;}else{finStr = "0000";}QByteArray numBa = finStr.toLatin1();//qDebug()<<"numBa:"<<numBa;int numEnd = finStr.size();//qDebug()<<"numEnd:"<<numEnd;int numNum[numEnd];for(int i=0;i<numEnd;i++){numNum[i] = (int)numBa.at(i);}startStr.append(QString(numBa));#endifquint8 sendBuf[30+numEnd];memset(sendBuf+numEnd,0,30+numEnd);sendBuf[0] = (quint8)0x40; //@ 64sendBuf[1] = (quint8)0x30; //0 48sendBuf[2] = (quint8)0x30; //0 48sendBuf[3] = (quint8)0x46; //F 70sendBuf[4] = (quint8)0x41; //A 65sendBuf[5] = (quint8)0x30; //0 48sendBuf[6] = (quint8)0x30; //0 48sendBuf[7] = (quint8)0x30; //0 48sendBuf[8] = (quint8)0x30; //0 48sendBuf[9] = (quint8)0x30; //0 48sendBuf[10] = (quint8)0x30; //0 48sendBuf[11] = (quint8)0x30; //0 48sendBuf[12] = (quint8)0x30; //0 48sendBuf[13] = (quint8)0x30; //0 48sendBuf[14] = (quint8)0x30; //0 48sendBuf[15] = (quint8)0x31; //1 49sendBuf[16] = (quint8)0x30; //0 48sendBuf[17] = (quint8)0x32; //2 50sendBuf[18] = (quint8)0x42; //B 66sendBuf[19] = (quint8)0x32; //2 50sendBuf[20] = (quint8)0x30; //0 48sendBuf[21] = (quint8)0x30; //0 48sendBuf[22] = (quint8)adsNum[0]; //0 48sendBuf[23] = (quint8)adsNum[1]; //1 49sendBuf[24] = (quint8)0x30; //0 48sendBuf[25] = (quint8)0x30; //0 48sendBuf[26] = (quint8)0x30; //0 48sendBuf[27] = (quint8)0x30; //0 48sendBuf[28] = (quint8)0x30; //0 48sendBuf[29] = (quint8)0x31; //1 49for(int i=0;i<numEnd;i++) //data 1234{sendBuf[30+i] = numNum[i];}quint8 fcsNum = 0;for(int i=0;i<30+numEnd;i++){fcsNum ^= sendBuf[i];}QByteArray fcsBa;fcsBa.setNum(fcsNum,16);//qDebug()<<"fcsBa:"<<fcsBa;QString scsStr = "";if(fcsBa.size() == 1){scsStr = "0" + QString(fcsBa);}else{scsStr = QString(fcsBa);}//qDebug()<<"ab:"<<ab;startStr.append(scsStr + "*\r");QString lastStr = startStr.toUpper();//qDebug()<<"lastStr:"<<lastStr;int sizeNum = lastStr.size();QString showStr = lastStr.left(sizeNum - 1);ui->plainTextEdit->appendPlainText("发送写命令:\n" + showStr + "\\CR");char *writeStr;QByteArray writeBa = lastStr.toLatin1();writeStr = writeBa.data();qDebug()<<"writeStr:"<<writeStr;serial->write(writeStr);}//单读HR字地址void SerialPort::slot_readHRWordData(int address){//H保持区 字:B2 位:32//@ 00 FA 0 00 00 00 00 0101 B2 00 01(address) 00 00 01 **(FCS) *\CR//QString testStr = "@00FA0000000000101B20001000001";QString startStr = "@00FA0000000000101B200";//addressint adsNum[2];QByteArray hrBa;hrBa.setNum(address,16);if(address < 16){adsNum[0] = 0;adsNum[1] = address;startStr.append("0" + QString(hrBa) + "000001");}else{adsNum[0] = (int)hrBa.at(0);adsNum[1] = (int)hrBa.at(1);startStr.append(QString(hrBa) + "000001");}//qDebug()<<"num[0]:"<<num[0]<<" num[1]:"<<num[1];quint8 sendBuf[30];memset(sendBuf,0,30);sendBuf[0] = (quint8)0x40; //@ 64sendBuf[1] = (quint8)0x30; //0 48sendBuf[2] = (quint8)0x30; //0 48sendBuf[3] = (quint8)0x46; //F 70sendBuf[4] = (quint8)0x41; //A 65sendBuf[5] = (quint8)0x30; //0 48sendBuf[6] = (quint8)0x30; //0 48sendBuf[7] = (quint8)0x30; //0 48sendBuf[8] = (quint8)0x30; //0 48sendBuf[9] = (quint8)0x30; //0 48sendBuf[10] = (quint8)0x30; //0 48sendBuf[11] = (quint8)0x30; //0 48sendBuf[12] = (quint8)0x30; //0 48sendBuf[13] = (quint8)0x30; //0 48sendBuf[14] = (quint8)0x30; //0 48sendBuf[15] = (quint8)0x31; //1 49sendBuf[16] = (quint8)0x30; //0 48sendBuf[17] = (quint8)0x31; //1 49sendBuf[18] = (quint8)0x42; //B 66sendBuf[19] = (quint8)0x32; //2 50sendBuf[20] = (quint8)0x30; //0 48sendBuf[21] = (quint8)0x30; //0 48sendBuf[22] = (quint8)adsNum[0]; //0 48sendBuf[23] = (quint8)adsNum[1]; //1 49sendBuf[24] = (quint8)0x30; //0 48sendBuf[25] = (quint8)0x30; //0 48sendBuf[26] = (quint8)0x30; //0 48sendBuf[27] = (quint8)0x30; //0 48sendBuf[28] = (quint8)0x30; //0 48sendBuf[29] = (quint8)0x31; //1 49quint8 fcsNum = 0;for(int i=0;i<30;i++){fcsNum ^= sendBuf[i];}QByteArray fcsBa;fcsBa.setNum(fcsNum,16);//qDebug()<<"fcs:"<<fcs;QString scsStr = "";if(fcsBa.size() == 1){scsStr = "0" + QString(fcsBa);}else{scsStr = QString(fcsBa);}//qDebug()<<"ab:"<<ab;startStr.append(scsStr + "*\r");QString lastStr = startStr.toUpper();//qDebug()<<"lastStr:"<<lastStr;int sizeNum = lastStr.size();QString showStr = lastStr.left(sizeNum - 1);ui->plainTextEdit->appendPlainText("发送读命令:\n" + showStr + "\\CR");char *readStr;QByteArray readBa = lastStr.toLatin1();readStr = readBa.data();qDebug()<<"readStr:"<<readStr;serial->write(readStr);}//单写HR位地址void SerialPort::slot_writeHRBitData(int address,int bit,int numWrite){//H保持区 字:B2 位:32//@ 00 FA 0 00 00 00 00 0102 32 00 1900(address) 00 01 01(data) **(FCS) *\CR//QString testStr = "@00FA000000000010232001900000101";//addressQString startStr = "@00FA00000000001023200";int adsNum[2];QByteArray hrBa;hrBa.setNum(address,16);if(address < 16){adsNum[0] = 0;adsNum[1] = address;startStr.append("0" + QString(hrBa));}else{adsNum[0] = (int)hrBa.at(0);adsNum[1] = (int)hrBa.at(1);startStr.append(QString(hrBa));}//qDebug()<<"num[0]:"<<num[0]<<" num[1]:"<<num[1];//bitint bitNum[2];QByteArray bitBa;bitBa.setNum(bit,16);bitNum[0] = 0;bitNum[1] = bit;startStr.append("0" + QString(bitBa) + "0001");//numWriteQString numStr = QString::number(numWrite);int numNum[2];numNum[0] = 0;numNum[1] = numWrite;startStr.append("0" + numStr);quint8 sendBuf[32];memset(sendBuf,0,32);sendBuf[0] = (quint8)0x40; //@ 64sendBuf[1] = (quint8)0x30; //0 48sendBuf[2] = (quint8)0x30; //0 48sendBuf[3] = (quint8)0x46; //F 70sendBuf[4] = (quint8)0x41; //A 65sendBuf[5] = (quint8)0x30; //0 48sendBuf[6] = (quint8)0x30; //0 48sendBuf[7] = (quint8)0x30; //0 48sendBuf[8] = (quint8)0x30; //0 48sendBuf[9] = (quint8)0x30; //0 48sendBuf[10] = (quint8)0x30; //0 48sendBuf[11] = (quint8)0x30; //0 48sendBuf[12] = (quint8)0x30; //0 48sendBuf[13] = (quint8)0x30; //0 48sendBuf[14] = (quint8)0x30; //0 48sendBuf[15] = (quint8)0x31; //1 49sendBuf[16] = (quint8)0x30; //0 48sendBuf[17] = (quint8)0x32; //2 50sendBuf[18] = (quint8)0x33; //3 51sendBuf[19] = (quint8)0x32; //2 50sendBuf[20] = (quint8)0x30; //0 48sendBuf[21] = (quint8)0x30; //0 48sendBuf[22] = (quint8)adsNum[0]; //1 49sendBuf[23] = (quint8)adsNum[1]; //9 57sendBuf[24] = (quint8)bitNum[0]; //0 48sendBuf[25] = (quint8)bitNum[1]; //0 48sendBuf[26] = (quint8)0x30; //0 48sendBuf[27] = (quint8)0x30; //0 48sendBuf[28] = (quint8)0x30; //0 48sendBuf[29] = (quint8)0x31; //1 49sendBuf[30] = (quint8)numNum[0]; //0 48sendBuf[31] = (quint8)numNum[1]; //1 49quint8 fcsNum = 0;for(int i=0;i<32;i++){fcsNum ^= sendBuf[i];}QByteArray fcsBa;fcsBa.setNum(fcsNum,16);//qDebug()<<"fcsBa:"<<fcsBa;QString scsStr = "";if(fcsBa.size() == 1){scsStr = "0" + QString(fcsBa);}else{scsStr = QString(fcsBa);}//qDebug()<<"ab:"<<ab;startStr.append(scsStr + "*\r");QString lastStr = startStr.toUpper();//qDebug()<<"lastStr:"<<lastStr;int sizeNum = lastStr.size();QString showStr = lastStr.left(sizeNum - 1);ui->plainTextEdit->appendPlainText("发送写命令:\n" + showStr + "\\CR");char *writeStr;QByteArray writeBa = lastStr.toLatin1();writeStr = writeBa.data();qDebug()<<"writeStr:"<<writeStr;serial->write(writeStr);}//单读HR位地址void SerialPort::slot_readHRBitData(int address,int bit){//H保持区 字:B2 位:32//@ 00 FA 0 00 00 00 00 0101 32 00 1900(address) 00 01 **(FCS) *\CR//QString testStr = "@00FA0000000000102320019000001";//addressQString startStr = "@00FA00000000001013200";int adsNum[2];QByteArray hrBa;hrBa.setNum(address,16);if(address < 16){adsNum[0] = 0;adsNum[1] = address;startStr.append("0" + QString(hrBa));}else{adsNum[0] = (int)hrBa.at(0);adsNum[1] = (int)hrBa.at(1);startStr.append(QString(hrBa));}//qDebug()<<"num[0]:"<<num[0]<<" num[1]:"<<num[1];//bitint bitNum[2];QByteArray bitBa;bitBa.setNum(bit,16);bitNum[0] = 0;bitNum[1] = bit;startStr.append("0" + QString(bitBa) + "0001");quint8 sendBuf[30];memset(sendBuf,0,32);sendBuf[0] = (quint8)0x40; //@ 64sendBuf[1] = (quint8)0x30; //0 48sendBuf[2] = (quint8)0x30; //0 48sendBuf[3] = (quint8)0x46; //F 70sendBuf[4] = (quint8)0x41; //A 65sendBuf[5] = (quint8)0x30; //0 48sendBuf[6] = (quint8)0x30; //0 48sendBuf[7] = (quint8)0x30; //0 48sendBuf[8] = (quint8)0x30; //0 48sendBuf[9] = (quint8)0x30; //0 48sendBuf[10] = (quint8)0x30; //0 48sendBuf[11] = (quint8)0x30; //0 48sendBuf[12] = (quint8)0x30; //0 48sendBuf[13] = (quint8)0x30; //0 48sendBuf[14] = (quint8)0x30; //0 48sendBuf[15] = (quint8)0x31; //1 49sendBuf[16] = (quint8)0x30; //0 48sendBuf[17] = (quint8)0x31; //1 49sendBuf[18] = (quint8)0x33; //3 51sendBuf[19] = (quint8)0x32; //2 50sendBuf[20] = (quint8)0x30; //0 48sendBuf[21] = (quint8)0x30; //0 48sendBuf[22] = (quint8)adsNum[0]; //1 49sendBuf[23] = (quint8)adsNum[1]; //9 57sendBuf[24] = (quint8)bitNum[0]; //0 48sendBuf[25] = (quint8)bitNum[1]; //0 48sendBuf[26] = (quint8)0x30; //0 48sendBuf[27] = (quint8)0x30; //0 48sendBuf[28] = (quint8)0x30; //0 48sendBuf[29] = (quint8)0x31; //1 49quint8 fcsNum = 0;for(int i=0;i<30;i++){fcsNum ^= sendBuf[i];}QByteArray fcsBa;fcsBa.setNum(fcsNum,16);//qDebug()<<"fcsBa:"<<fcsBa;QString scsStr = "";if(fcsBa.size() == 1){scsStr = "0" + QString(fcsBa);}else{scsStr = QString(fcsBa);}//qDebug()<<"ab:"<<ab;startStr.append(scsStr + "*\r");QString lastStr = startStr.toUpper();//qDebug()<<"lastStr:"<<lastStr;int sizeNum = lastStr.size();QString showStr = lastStr.left(sizeNum - 1);ui->plainTextEdit->appendPlainText("发送读命令:\n" + showStr + "\\CR");char *readStr;QByteArray readBa = lastStr.toLatin1();readStr = readBa.data();qDebug()<<"readStr:"<<readStr;serial->write(readStr);}void SerialPort::on_pb_refresh_clicked(){ui->cb_port->clear();foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts()){QSerialPort serial;serial.setPort(info);if(serial.open(QIODevice::ReadWrite)){ui->cb_port->addItem(info.portName());serial.close();}}}void SerialPort::on_pb_operate_clicked(){if(ui->cb_port->currentText().isEmpty()){QMessageBox::information(this, tr("提示"),"请先刷新并进行串口选择!");return;}if(ui->pb_operate->text() == QString("OPEN")){QString portName = ui->cb_port->currentText();QString baudRate = ui->cb_baud->currentText();qDebug()<<"portName:"<<portName<<" baudRate:"<<baudRate;QSerialPortInfo info(portName);if(info.isBusy()){qDebug()<<"The serial port is occupied"<<portName;return;}serial->setPortName(portName);serial->setBaudRate(baudRate.toInt());serial->setStopBits(QSerialPort::TwoStop);serial->setDataBits(QSerialPort::Data7);serial->setParity(QSerialPort::EvenParity);serial->setFlowControl(QSerialPort::NoFlowControl);bool flag = serial->open(QIODevice::ReadWrite);if(!flag){qDebug()<<QString("Failed to open serial port:")<<portName<<serial->errorString();serial->clearError();ui->pb_send->setEnabled(false);}else{qDebug()<<QString("The serial port is open:")<<portName;ui->pb_operate->setText("CLOSE");ui->pb_send->setEnabled(true);}}else{ui->pb_operate->setText("OPEN");serial->close();ui->pb_send->setEnabled(false);}}void SerialPort::on_pb_send_clicked(){//1.界面上显示的是ASCII字符//2.计算校验码的步骤//3.先进行输入地址位的转换//4.将界面上字符转化为十进制后进行按位异或运算//5.按位运算后的结果转换为16进制即为校验码int address = ui->le_address->text().toInt();int bit = ui->le_bit->text().toInt();int numWrite = ui->le_num->text().toInt();//单读if(ui->rb_read->isChecked()){if(ui->le_bit->text().isEmpty()){slot_readHRWordData(address);}else{slot_readHRBitData(address,bit);}}//单写if(ui->rb_write->isChecked()){if(ui->le_bit->text().isEmpty()){slot_writeHRWordData(address,numWrite);}else{slot_writeHRBitData(address,bit,numWrite);}}}void SerialPort::on_rb_read_clicked(){ui->le_num->setEnabled(false);}void SerialPort::on_rb_write_clicked(){ui->le_num->setEnabled(true);}

4.serialport.ui

四、下载链接

我的示例百度网盘链接:/s/1eGnt6I7UVeN5p3n4bvLVTA

提取码:xxcj

总结

本文实现的与欧姆龙PLC进行的通信也是比较简单的,使用串口进行命令的发送,前提是对HOSTLINK协议有相应的了解,然后去实现该协议命令的组装,其中需要注意的一个点是FCS(校验码)的获取。本文还存在的局限是只进行了HR区域的读写,并且只能进行单独某地址或某位的读写,所以想要实现更多区域的读写就需要进行改进了,这里提供这样一个示例,希望可以帮助到大家。

hello:

共同学习,共同进步,如果还有相关问题,可在评论区留言进行讨论。

参考博客:

欧姆龙plc交互协议hostlink

基于HostLink协议的Fins命令读写

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。