简介
Modbus RTU(Remote Terminal Unit)是Modbus通信协议的一种变体,用于串行通信。它定义了在串行通信中传输Modbus消息的规则和格式。
Modbus RTU协议采用二进制形式传输数据,使用RS-232或RS-485等串行通信接口。
关键特征:
帧格式:Modbus RTU帧由起始位、设备地址、功能码、数据、CRC校验和结束位组成。
起始位:用于标识一个字节的开始,让接收端知道数据传输的时序和起始位置。在Modbus RTU协议中,起始位也是一个字节的第一个位,用于标识一个Modbus消息的开始。在Modbus RTU中,起始位的持续时间为3.5个字符时间,即在传输速率为9600 bps的情况下,起始位持续时间为约364us。
设备地址:每个Modbus RTU设备都有一个唯一的设备地址,用于标识通信的目标设备。
功能码:功能码指示了Modbus操作的类型,如读取寄存器、写入寄存器等。
数据:数据部分包含要读取或写入的寄存器地址和相关数据。
CRC校验和:用于检测数据的完整性和准确性,防止数据传输错误。
帧间隔:Modbus RTU中,每个字节之间没有固定的时间间隔,而是通过静默时间来区分帧。
常用类
QModbusRtuSerialMaster:这个类是Modbus RTU通信的主站(Master)的实现类。它继承自QModbusClient类,并通过串口与Modbus从站(Slave)进行通信。
QModbusRtuSerialSlave:这个类是Modbus RTU通信的从站(Slave)的实现类。它继承自QModbusServer类,并通过串口接收和处理来自主站的通信请求。
QModbusDataUnit:这个类用于定义Modbus数据单元,包括功能码、起始地址、数据长度等信息。可以用于读取或写入Modbus设备的寄存器和线圈。
QModbusReply:这个类表示一个Modbus请求的响应。通过该类可以获取响应的结果、错误信息等。
QModbusRtuSerialMaster常用函数
setConnectionParameter:用于设置Modbus设备的连接参数。它接受两个参数:参数类型和参数值。
- QModbusDevice::SerialPortNameParameter:串口名称,例如"/dev/ttyUSB0"。
- QModbusDevice::SerialParityParameter:串口奇偶校验位,例如QSerialPort::NoParity表示无校验。
- QModbusDevice::SerialBaudRateParameter:串口波特率,例如QSerialPort::Baud9600表示9600波特率。
- QModbusDevice::SerialDataBitsParameter:串口数据位数,例如QSerialPort::Data8表示8位数据位。
- QModbusDevice::SerialStopBitsParameter:串口停止位数,例如QSerialPort::OneStop表示1位停止位。
connectDevice:建立Modbus RTU串口连接。
disconnectDevice:断开Modbus RTU串口连接。
sendReadRequest:发送读取请求,读取指定地址的寄存器。该函数有多个重载版本,可以读取不同类型的寄存器,如输入寄存器、保持寄存器等。
sendWriteRequest:发送写入请求,向指定地址的寄存器写入数据。该函数有多个重载版本,可以写入不同类型的寄存器,如输入寄存器、保持寄存器等。
sendReadWriteRequest:发送读写请求,先读取指定地址的寄存器,再向其写入数据。
sendCustomRequest:发送自定义请求,可以用来发送一些特殊的Modbus请求,如读取设备标识符等。
state:获取当前连接状态,返回值为QModbusDevice::State枚举类型,表示设备的连接状态。
errorString:获取最后一次操作的错误信息。
dataCount:获取最后一次读取或写入的数据数量。
data:获取最后一次读取的数据,返回QModbusDataUnit类型,包含了读取到的数据。
setData:设置写入的数据。该函数只在发送写入请求前有效。
Modbus RTU服务端:
#include <QCoreApplication>
#include <QModbusRtuSerialServer>
#include <QSerialPort>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 创建串口对象
QSerialPort serialPort;
serialPort.setPortName("COM1"); // 设置串口号
serialPort.setBaudRate(QSerialPort::Baud9600); // 设置波特率
serialPort.setDataBits(QSerialPort::Data8); // 设置数据位
serialPort.setParity(QSerialPort::NoParity); // 设置校验位
serialPort.setStopBits(QSerialPort::OneStop); // 设置停止位
// 打开串口
if (!serialPort.open(QIODevice::ReadWrite)) {
qDebug() << "Failed to open serial port:" << serialPort.errorString();
return 1;
}
// 创建Modbus RTU服务端对象
QModbusRtuSerialServer modbusServer;
modbusServer.setConnectionParameter(QModbusDevice::SerialPortNameParameter, "COM1"); // 设置串口号
modbusServer.setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud9600); // 设置波特率
modbusServer.setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8); // 设置数据位
modbusServer.setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity); // 设置校验位
modbusServer.setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop); // 设置停止位
// 连接dataWritten()信号,表示主站写入数据
QObject::connect(&modbusServer, &QModbusRtuSerialServer::dataWritten, [&](int serverAddress, const QByteArray &data) {
qDebug() << "Data written by master:" << data.toHex();
// 在这里处理主站写入数据的逻辑
});
// 连接dataRead()信号,表示主站读取数据
QObject::connect(&modbusServer, &QModbusRtuSerialServer::dataRead, [&](int serverAddress, const QByteArray &data) {
qDebug() << "Data read by master:" << data.toHex();
// 在这里处理主站读取数据的逻辑
});
// 启动服务端
if (!modbusServer.connectDevice()) {
qDebug() << "Failed to start Modbus server:" << modbusServer.errorString();
return 1;
}
qDebug() << "Modbus server started";
return a.exec();
}