1,要解析协议,首先要弄清楚报文格式,其中modbustcp协议中的标准格式为:
MBAP报文头(7byte) + 功能码(1byte)+ 数据(n byte)
MBAP报文头包括:
1.事务处理标识符 2字节 (表示当前的操作事务类型,例如:读取温度0x00 0x01, 读取压力0x00 0x02 )
2.协议标识符 2字节 0=Modbus协议
3.长度 2字节 后续字节的数量 (单元标识符,功能码,和数据)
4.单元标识符 1字节(表示从机编号,一个modbus主机可对应多个从机)
2.了解报文之后,接下来需要对功能码进行认识,对于协议来说,功能码有以下几项:
0x01 读线圈(coils)状态,读取单个或多个
0x02 读离散输入(discreteinputs)状态,读取单个或多个
0x03 读保持寄存器(holdingregisters),读取单个或多个
0x04 读输入寄存器(inputregisters),读取单个或多个
0x05 写单个线圈(coils)状态,单个写入
0x06 写单个保持寄存器(holdingregisters),单个写入
0x0F 写多个线圈(coils),多个写入
0x10 写多个保持寄存器(holdingregisters),多个写入
3.了解报文之后,可以进行发送数据的组织了,下面是数据组织:
例子:写入和读取保持寄存器代码如下:
void ModbusTcpHandler::writeHoldingRegister(quint16 address, quint16 value)
{
QByteArray request;
request.resize(12);
uchar addh = address/256;
uchar addl = address%256;
request[0]=addh;//事务处理标识符 2byte
request[1]=addl;
request[2]=0x00;//协议标识符 2byte
request[3]=0x00;
request[4]=0x00;//数据长度 2byte
request[5]=0x06;
request[6]=0x01;//单元标识符 1byte
request[7]=0x06;//功能码 1byte
request[8]=addh;//起始地址h
request[9]=addl;//起始地址l
uchar valueh = value/256;
uchar valuel = value%256;
request[10]=valueh;//值1h
request[11]=valuel;//值1l
m_tcpSocket->write(request);
qDebug () << Q_FUNC_INFO << request;
}
void ModbusTcpHandler::readHoldingRegister(quint16 address, quint16 value)
{
QByteArray request;
request.resize(12);
uchar addh = address/256;
uchar addl = address%256;
request[0]=addh;//事务处理标识符 2byte
request[1]=addl;
request[2]=0x00;//协议标识符 2byte
request[3]=0x00;
request[4]=0x00;//数据长度 2byte
request[5]=0x06;
request[6]=0x01;//单元标识符 1byte
request[7]=0x03;//功能码 1byte
request[8]=addh;//起始地址h
request[9]=addl;//起始地址l
uchar valueh = value/256;
uchar valuel = value%256;
request[10]=valueh;//读取数量值1h
request[11]=valuel;//读取数量值1l
qint64 nWriteData = m_tcpSocket->write(request);
if (!m_tcpSocket->waitForBytesWritten(2000)) {
qDebug () << Q_FUNC_INFO << m_tcpSocket->errorString();
}
qDebug () << Q_FUNC_INFO << nWriteData << request.toHex();
}
3.发送完数据之后,接下来就是数据处理部分:
由于接收到的数据是char*[] 数组,对于char的处理函数有:
4个char转浮点类型函数:
float ModbusTcpHandler::parse4Int2Float(quint8 value1, quint8 value2, quint8 value3, quint8 value4)
{
// 合并为 32 位整数
uint32_t combined = (static_cast<uint32_t>(value1) << 24) |
(static_cast<uint32_t>(value2) << 16) |
(static_cast<uint32_t>(value3) << 8) |
static_cast<uint32_t>(value4);
float fData = *reinterpret_cast<float*>(&combined);
qDebug () << Q_FUNC_INFO << combined << fData;
return fData;
}
还有两个char转uint16:
quint16 ModbusTcpHandler::parse2Int2Int(quint8 value1, quint8 value2)
{
quint16 combined = (static_cast<quint16>(value1) << 8) | value2;
quint16 nValue = static_cast<quint16>(combined);
qDebug () << Q_FUNC_INFO << nValue;
return nValue;
}
有了这两个函数,数据基本上就可以完成处理了。
690

被折叠的 条评论
为什么被折叠?



