前言
? ? ? ?QtserialBus下提供了访问工业串行总线和协议的类和函数,包括CAN和Modbus等。Modbus的一些类如下:
?Modbus协议物理层接口有RS232和RS485串行接口和以太网接口,使用网口通讯主要使用QModbusTcpClient(Modbus客户端设备的接口类)和QModbusTcpServer(TCP服务器与Modbus客户端进行通讯的Modbus服务器)。
上位机主站的实现
(1)创建modbusTCPclient对象指针:QModbusTcpClient *? myClient;并将其创建在堆上,添加到QT的对象数中,这是一个用于发送各种请求的对象,比如读和写。以下将其统称为客户端。
(2)通过TCP/IP进行连接:客户端的连接状态有四个状态,分别为:UnconnectedState (0)、ConnectingState(1)、ConnectedState(2)、ClosingState(3).可以判断状态未连接时进行连接。设置其连接相关参数:
myClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, “127.0.0.0”);
myClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, 502);
myClient->setTimeout(500);//超时时间内没有相应,则设置TimeoutError
myClient->setNumberOfRetries(3);//请求失败前客户端执行重试的次数
myClient->connectDevice()//连接设备
? ? ? ? 连接这里需要注意的问题是connectDevice()执行时会在另外一个线程中进行连接,因此需要另外写一个槽函数用于判断设备的连接状态。官方提供了一个stateChanged的信号,状态改变后在槽函数中判断设备是否连接。
(3)写操作:对modbus设备进行写操作时,需要使用QModbusDataUnit类来存储一些信息,包括写入寄存器的类型,写入数据的起始地址,写入数据的个数。创建该容器的方式如下,其中注意参数所需要的类型。创建完容器对象后,使用函数setValue()来将信息写入到modbus设备中。
QModbusDataUnit writeUnit = QModbusDataUnit(QModbusDataUnit::Coils, starAddress, numberOfwrite);
writeUnit .setValue(index,value);
此时还需要给设备发送写入的请求,当请求成功时会返回一个有效的QModbusReply的对象指针,否则返回nullptr。
QModbusReply* reply = myClient->sendWriteRequest(writeUnit, server_Address)
可以判断reply的状态进行后续的操作。
(4)读操作:与写操作对应,首先使用QModbusDataUnit类来存储所读寄存器的类型,读取数据的起始地址,读取数据的个数等信息。然后发送读取数据的请求,根据请求的返回QModbusReply对象指针来进行后续操作。
QModbusDataUnit readUnit(QModbusDataUnit::Coils, startAddress, numberOfRead);
QModbusReply *reply = myClient->sendReadRequest(readUnit, server_Address)
与写操作不同的是,读取请求发送后,需要根据响应的状态然后进行读取数据的存储。官方提供了响应完成的信号QModbusReply::finished,此时自己再实现读取数据的槽函数。
connect(reply, &QModbusReply::finished, [=](){
if (reply->error() == QModbusDevice::NoError)
{
//处理成功返回的数据
const QModbusDataUnit unit = reply->result();
quint16 res = unit.value(0); //读取第一位的数据
appendMsg("读取结果" + QString::number(res));
}
else
{
QString error = QString::fromLocal8Bit("Read response error: %1 (code: 0x%2)").arg(reply->errorString()).arg(reply->error(), -1, 16);
appendMsg(error);
}
reply->deleteLater();
});
代码有自己实现的接口,具体内容自己调整。
(5)自己调试过程需要的问题总结:
第一点,在连接PLC的时候不要自己另外开线程,会导致设置连接后自己线程没有退出,与连接自带的线程隔离,无法判断是否连接成功。
第二点,写入和读取寄存器对应地址的数据时,要判断该寄存器地址是否是可读可写的,我在调试过程中使用了一个只读的寄存器地址,让我以为写入数据的程序有问题,白调整了几个小时。。。另外,最近在做项目自学很多东西都会在此更新,有兴趣的欢迎关注,一同交流学习。
最后多使用QT帮助文档,太好的东西!
|