因工作需要,研究了一下三菱的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进制命令,这样易用性强很多。
Be First to Comment