您尚未登录。

楼主 # 2023-09-13 16:58:28

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,378
积分: 1343.5

qt程序,想在循环里不停的进行modbusrtu读操作,结果串口只能发送出第一个字节来。

用的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)

离线

楼主 #1 2023-09-14 15:54:37

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,378
积分: 1343.5

Re: qt程序,想在循环里不停的进行modbusrtu读操作,结果串口只能发送出第一个字节来。

按以上的方法,在循环里,QModbusRtuSerialMaster的sendReadRequest()后,用事件循环等待QModbusReply的finished信号。
一开始,QModbusRtuSerialMaster的超时时间timeout设置为10ms,结果串口数据大约是1秒发送一次。修改timeout为100ms后,串口发数频率才正常。尝试了多个数据后发现,50ms以上正常,50ms以下,就变成了1秒发一帧。不知道这是为什么。

最近编辑记录 Gentlepig (2023-09-14 15:56:32)

离线

楼主 #2 2023-09-14 16:12:21

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,378
积分: 1343.5

Re: qt程序,想在循环里不停的进行modbusrtu读操作,结果串口只能发送出第一个字节来。

目前的程序是这样的:

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)

离线

#3 2023-09-15 11:22:28

达克罗德
会员
注册时间: 2018-04-10
已发帖子: 1,138
积分: 1090.5

Re: qt程序,想在循环里不停的进行modbusrtu读操作,结果串口只能发送出第一个字节来。

跨线程操作UI会出问题
QCoreApplication::processEvents();
跨线程signal应该也不工作了

离线

楼主 #4 2023-09-15 11:51:48

Gentlepig
会员
注册时间: 2018-10-24
已发帖子: 1,378
积分: 1343.5

Re: qt程序,想在循环里不停的进行modbusrtu读操作,结果串口只能发送出第一个字节来。

达克罗德 说:

跨线程操作UI会出问题
QCoreApplication::processEvents();
跨线程signal应该也不工作了

其实这次没用到ui,不确定processEvents()有没有用。
跨线程信号和槽是可以用的,connect有第五个参数可以设置。

connect(modbusMaster->modbusProc, &ModbusProc::dataPointToSend, mqttClient, &MqttClient::updateDataPoint, Qt::QueuedConnection);

最近编辑记录 Gentlepig (2023-09-15 11:53:14)

离线

#5 2023-09-15 23:55:26

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 660
积分: 793
个人网站

Re: qt程序,想在循环里不停的进行modbusrtu读操作,结果串口只能发送出第一个字节来。

@Gentlepig
connect函数不设置第5个参数默认就是线程安全的。

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn