用的qt的Modbus库,想在子线程里不停地进行modbus读操作,写了这么个函数。
如果只执行一次的话,串口能输出正确的数据,或者用定时器定时调用这个函数,串口也能不停地输出数据。
但是如果在while循环里不停的调用这个函数的话,则串口只会输出第一个字节。
void ModbusProc::modbusPoll()
{
while (true)
{
readDataPoint();
QCoreApplication::processEvents();
QThread::msleep(1000);
}
}
void ModbusProc::readDataPoint()
{
if (!modbusDevice)
return;
QModbusDataUnit readData(QModbusDataUnit::InputRegisters, 10, 2);
QModbusReply *reply = modbusDevice->sendReadRequest(readData, 01);
if (reply){
if (!reply->isFinished())
{
qDebug() << "modbus reply is finished." << endl;
// delete reply;
}
else
{
qDebug() << "modbus reply is not finished." << endl;
delete reply;
}
}
else
{
qDebug() << "read request failed" << endl;
}
QThread::msleep(100);
}
按gpt的回答,加了QEventLoop事件循环,算是死等发送完成,可以正常工作了。
void ModbusProc::readDataPoint()
{
if (!modbusDevice)
return;
QModbusDataUnit readData(QModbusDataUnit::InputRegisters, 10, 2);
QModbusReply *reply = modbusDevice->sendReadRequest(readData, 01);
if (reply){
if (!reply->isFinished())
{
qDebug() << "modbus reply is finished." << endl;
// delete reply;
QEventLoop loop;
QObject::connect(reply, &QModbusReply::finished, &loop, &QEventLoop::quit);
loop.exec();
}
else
{
qDebug() << "modbus reply is not finished." << endl;
delete reply;
}
}
else
{
qDebug() << "read request failed" << endl;
}
QThread::msleep(100);
}
请教,单次执行时不需要死等,为什么连续循环就需要死等?除此之外还有其他办法吗?
最近编辑记录 Gentlepig (2023-09-14 08:46:20)
离线
按以上的方法,在循环里,QModbusRtuSerialMaster的sendReadRequest()后,用事件循环等待QModbusReply的finished信号。
一开始,QModbusRtuSerialMaster的超时时间timeout设置为10ms,结果串口数据大约是1秒发送一次。修改timeout为100ms后,串口发数频率才正常。尝试了多个数据后发现,50ms以上正常,50ms以下,就变成了1秒发一帧。不知道这是为什么。
最近编辑记录 Gentlepig (2023-09-14 15:56:32)
离线
目前的程序是这样的:
void ModbusProc::modbusPoll()
{
while (true)
{
foreach (int index, readList)
{
uint8_t funcR = dataPoint[index].funcR;
uint16_t addr = dataPoint[index].addr;
uint8_t dataLen = dataPoint[index].dataLen;
uint8_t slave = dataPoint[index].slave;
if (dataLen == 0)
dataLen = 1;
if (slave == 0)
slave = 1;
if (funcR == 1 || funcR == 2 || funcR == 3 || funcR == 4)
{
uint8_t readType;
if (funcR == 1)
readType = QModbusDataUnit::Coils;
else if (funcR == 2)
readType = QModbusDataUnit::DiscreteInputs;
else if (funcR == 3)
readType = QModbusDataUnit::HoldingRegisters;
else if (funcR == 4)
readType = QModbusDataUnit::InputRegisters;
else
{
continue;
}
QModbusDataUnit readData((QModbusDataUnit::RegisterType)readType, addr, dataLen);
QModbusReply *reply = modbusDevice->sendReadRequest(readData, slave);
if (reply)
{
if (!reply->isFinished())
{
qDebug() << "modbus reply is not finished." << endl;
QEventLoop loop;
QObject::connect(reply, &QModbusReply::finished, &loop, &QEventLoop::quit);
loop.exec();
}
if (reply->error() == QModbusDevice::NoError)
{
qDebug() << "modbus reply is finished." << endl;
currentIndex = index;
delete reply;
}
}
else
{
qDebug() << "Read request failed";
delete reply;
}
}
QCoreApplication::processEvents();
QThread::msleep(10);
}
QCoreApplication::processEvents();
QThread::msleep(10);
}
}
现在设置的modbus的超时时间是50ms,每发送一次后有个线程的延时10ms,算下来应该是60ms一帧数据。实际pc端收到的数据,大概是110ms左右。
一帧8个字节。
设置超时时间为100ms,结果pc端收到数据的间隔,大概是160ms左右。
最近编辑记录 Gentlepig (2023-09-14 16:33:14)
离线
跨线程操作UI会出问题
QCoreApplication::processEvents();
跨线程signal应该也不工作了
其实这次没用到ui,不确定processEvents()有没有用。
跨线程信号和槽是可以用的,connect有第五个参数可以设置。
connect(modbusMaster->modbusProc, &ModbusProc::dataPointToSend, mqttClient, &MqttClient::updateDataPoint, Qt::QueuedConnection);
最近编辑记录 Gentlepig (2023-09-15 11:53:14)
离线