Skip to content

利用Qt/C++串口通讯协议与三菱PLC互通

因工作需要,研究了一下三菱的PLC通信协议,在这里记一下以防自己忘记

三菱PLC不做过多介绍,其通过一个CH340 USBtoSerial芯片连接到上位机,CH340在win10可能需要下载驱动,在Jetson Ubuntu 18.04上免驱测试通过。

首先,是串口通讯协议,我用了一个QSerialPort类来定义这个串口,根据三菱文档的PLC通讯协议可得

QSerialPort* mySerialPort;

通讯速率固定为Baud9600,1起始位-7数据位-偶极性-1停止位,返回值为15H时代表错误,返回06H代表操作成功

mySerialPort->setPortName(myPortName[PortNameIndex]);
mySerialPort->setBaudRate(9600);
mySerialPort->setDataBits(QSerialPort::Data7);
mySerialPort->setParity(QSerialPort::EvenParity);
mySerialPort->setFlowControl(QSerialPort::NoFlowControl);
mySerialPort->setStopBits(QSerialPort::OneStop);
myLinkStatus = mySerialPort->open(QIODevice::ReadWrite);
if (myLinkStatus)
{
	mySerialPort->setDataTerminalReady(true);
	qDebug() << mySerialPort->portName() + " is open";
}
else
{
	qDebug("Uart not exist or being occupied");
	return;
}

这段说明白了发送的16进制数据类型,由一个头码,一个指令 ,任意个资料位,一个结束码,两个总和校验码组成。

接下来就是具体的指令,CMD代表指令码,指令码为0时是读取地址的指令,返回15时代表指令错误,一般来说有可能是总和校验码出错,可以重新计算一下。

然后就是查表的地址

接下来就很清楚了,查表找到地址,然后就可以读写相对应的地址的数据了。

记得转换成16进制发送

char convertHexChart(char ch)
{
	if ((ch >= '0') && (ch <= '9'))
		return ch - 0x30; // 0x30 对应 ‘0’
	if ((ch >= 'A') && (ch <= 'F'))
		return ch - 'A' + 10;
	if ((ch >= 'a') && (ch <= 'f'))
		return ch - 'a' + 10;
	//        else return (-1);
	return ch - ch;
	//不在0-f范围内的会发送成0
}

void StringToHex(QString str, QByteArray& senddata)
{
	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 = convertHexChart(hstr);
		lowhexdata = convertHexChart(lstr);
		if ((hexdata == 16) || (lowhexdata == 16))
			break;
		hexdata = hexdata * 16 + lowhexdata;
		i++;
		senddata[hexdatalen] = static_cast<char>(hexdata);
		hexdatalen++;
	}
	senddata.resize(hexdatalen);
}

其实到这里问题都不是特别大了,就只是要把常用的读写命令计算一下,比如说

//读D10
02 30 31 30 31 34 30 32 03 35 42
//读D20
02 30 31 30 32 38 30 32 03 36 30
//读D30
02 30 31 30 33 43 30 32 03 36 43
//读D40
02 30 31 30 35 30 30 32 03 35 42
//写D30=0002
02 31 31 30 33 43 30 32 30 32 30 30 03 32 46
//写D30=0001
02 31 31 30 33 43 30 32 30 31 30 30 03 32 45
//写D30=01
02 31 31 30 33 43 30 31 30 31 03 43 46

TODO:之后我会写一下自动计算读写命令的函数,这样只要输入D、X的地址就能自动生成读写的16进制命令,这样易用性强很多。

Published in技术探究

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注