Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. About QModbus usage(How to read coils at a fixed frequecy?)
Forum Updated to NodeBB v4.3 + New Features

About QModbus usage(How to read coils at a fixed frequecy?)

Scheduled Pinned Locked Moved Unsolved General and Desktop
modbus
9 Posts 4 Posters 4.7k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MartinChan
    wrote on last edited by MartinChan
    #1

    Hi everyone.

    I used to ask a question about how to read coil in forum before,and I got a good answer.

    However,I came about another question:I don't just want to read the coils a 'Singel' time,I want to read these coils with a fixed interval(like 10ms or less).

    I tried the code like following to solve these quesition,but I didn't think it's a good way to solve this question:

    #include "modclient.h"
    #include <QVariant>
    #include <QModbusDataUnit>
    #include <QDebug>
    #include <QTime>
    #include <QCoreApplication>
    modclient::modclient()
    {
        client=new QModbusTcpClient();
        client->setConnectionParameter(QModbusDevice::NetworkAddressParameter,"192.168.0.201");
        client->setConnectionParameter(QModbusDevice::NetworkPortParameter,502);
        client->setTimeout(200);
        client->setNumberOfRetries(3);
        first[0]=false;
        first[1]=false;
        control=true;
    }
    
    void modclient::connecttoModbusServer(){
        control=true;
        if(client->state()==QModbusClient::UnconnectedState){
            if(!client->connectDevice()){
                qDebug()<<QString("There's something wrong with the device");
            }else {
                qDebug()<<QString("Right connection");
                connect(client,&QModbusTcpClient::stateChanged,this,&modclient::query);
    /****************Here is the first which puzzles me***************/ 
            }
        }
    }
    
    void modclient::readready(){
        if(control){
            QModbusReply *reply=qobject_cast<QModbusReply *>(sender());
            const QModbusDataUnit result=reply->result();
            bool temp0=false,temp1=false;
            qDebug()<<QString("The value of %1 is %2").arg(1).arg(result.value(1));
            qDebug()<<QString("The value of %1 is %2").arg(3).arg(result.value(3));
            if (result.value(1)==1) temp0=true;
            if (result.value(3)==1) temp1=true;
    
            if (temp1==true && first[1]==false){
                //delay(Time2);
                emit finishedreading2();
            }
            else if(temp0 ==true && first[0]==false){
                //delay(Time1);
                emit finishedreading();
            }
            first[0]=temp0;
            first[1]=temp1;
        }
    }
    
    
    void modclient::query(){
        QModbusDataUnit readUnit(QModbusDataUnit::Coils,00000,4);
    /****************Here is the second which puzzles me***************/ 
        while(1){
                if (auto *reply = client->sendReadRequest(readUnit,1))
                {
                    if (!reply->isFinished())
                    {
                        // connect the finished signal of the request to your read slot
                        connect(reply, &QModbusReply::finished,this,&modclient::readready);
                    }
                    else
                    {
                        delete reply; // broadcast replies return immediately
                    }
    
                }
                else
                {
                    // request error
                }
                delay(10);
            }
    
    }
    
    void modclient::Quit_Query(){
        control=false;
        //disconnect(client,&QModbusTcpClient::stateChanged,this,&modclient::query);
    }
    
    void modclient::delay(int a){
        QTime t;
        t.start();
        while(t.elapsed()<a)
        QCoreApplication::processEvents();
    }
    

    I marked two places which puzzles me:
    1)When the signal 'StateChanged' is emitted,it means the device state changed(like from unconnceted to connect,or reversed),or the coil state changed(I know its impossible but I still want to ask)?
    2)I just want to use a single QThread to do the reading(coils) job,however,it seems not recommended to use a 'infinite' while loop in the class which will be added to a QThread.So,what should I do is a better way to construct a right way to 'continously' read the coil?

    1 Reply Last reply
    0
    • M Offline
      M Offline
      MartinChan
      wrote on last edited by
      #2

      My previous topic was here:link

      And I used to refer to the Qt ModbusClient example,nevertheless,I didn't find too much about how to read coils synchronously,but when I test the program it did execute ‘synchronously’

      beeckscheB 1 Reply Last reply
      0
      • M MartinChan

        My previous topic was here:link

        And I used to refer to the Qt ModbusClient example,nevertheless,I didn't find too much about how to read coils synchronously,but when I test the program it did execute ‘synchronously’

        beeckscheB Offline
        beeckscheB Offline
        beecksche
        wrote on last edited by
        #3

        Hi @MartinChan,

        I think you want to poll to your slave like http://www.modbusdriver.com/modpoll.html

        If you want to have a synchronous API i would start a local QEventLoop after sending your request and stop this loop when the reply has finished. Sth like that:

        void modclient::readCoil()
        {
         QModbusDataUnit readUnit(QModbusDataUnit::Coils,00000,4);
         auto *reply = client->sendReadRequest(readUnit,1);
        
         QEventLoop loop;
        
         auto connection = QObject::connect(reply, &QModbusReply::finished, ()[&loop] { loop.quit(); }
        
         loop.start();
         QObject::disconnect(connection);
        
         // now you can get the result of the query and do your stuff
        
         const QModbusDataUnit result=reply->result();
         bool temp0=false,temp1=false;
         qDebug()<<QString("The value of %1 is %2").arg(1).arg(result.value(1));
         qDebug()<<QString("The value of %1 is %2").arg(3).arg(result.value(3));
         if (result.value(1)==1) temp0=true;
         ...
        
         if (polling)
           QTimer::singleShot(interval, &modclient::readCoil)
        
        }
        

        Haven't testet the code, may you have to add some security mechanism in the event loop.

        M YunusY 2 Replies Last reply
        1
        • beeckscheB beecksche

          Hi @MartinChan,

          I think you want to poll to your slave like http://www.modbusdriver.com/modpoll.html

          If you want to have a synchronous API i would start a local QEventLoop after sending your request and stop this loop when the reply has finished. Sth like that:

          void modclient::readCoil()
          {
           QModbusDataUnit readUnit(QModbusDataUnit::Coils,00000,4);
           auto *reply = client->sendReadRequest(readUnit,1);
          
           QEventLoop loop;
          
           auto connection = QObject::connect(reply, &QModbusReply::finished, ()[&loop] { loop.quit(); }
          
           loop.start();
           QObject::disconnect(connection);
          
           // now you can get the result of the query and do your stuff
          
           const QModbusDataUnit result=reply->result();
           bool temp0=false,temp1=false;
           qDebug()<<QString("The value of %1 is %2").arg(1).arg(result.value(1));
           qDebug()<<QString("The value of %1 is %2").arg(3).arg(result.value(3));
           if (result.value(1)==1) temp0=true;
           ...
          
           if (polling)
             QTimer::singleShot(interval, &modclient::readCoil)
          
          }
          

          Haven't testet the code, may you have to add some security mechanism in the event loop.

          M Offline
          M Offline
          MartinChan
          wrote on last edited by
          #4

          @beecksche Thx~!And I will try it soon~

          1 Reply Last reply
          0
          • M Offline
            M Offline
            MartinChan
            wrote on last edited by
            #5

            @beecksche Hi,Thx first and I have another little quesition .

            The code u provided,there is a line:

             auto connection = QObject::connect(reply, &QModbusReply::finished, ()[&loop] { loop.quit(); }
            

            It seems u use the lambda expression in '()[&loop] { loop.quit(); }' (I am sorry for I didn't know too much about Lambda expression...)However,it didn't work,can I just use

            auto connection=QObject::connect(reply,&QModbusReply::finished,loop.quit()); 
            

            to replace it?If not,why??

            beeckscheB jsulmJ 2 Replies Last reply
            0
            • M MartinChan

              @beecksche Hi,Thx first and I have another little quesition .

              The code u provided,there is a line:

               auto connection = QObject::connect(reply, &QModbusReply::finished, ()[&loop] { loop.quit(); }
              

              It seems u use the lambda expression in '()[&loop] { loop.quit(); }' (I am sorry for I didn't know too much about Lambda expression...)However,it didn't work,can I just use

              auto connection=QObject::connect(reply,&QModbusReply::finished,loop.quit()); 
              

              to replace it?If not,why??

              beeckscheB Offline
              beeckscheB Offline
              beecksche
              wrote on last edited by beecksche
              #6

              @MartinChan
              Oh, yes of course. Forgot that quit is a slot of the QEventLoop. Then you have to change the function:

              auto connection = QObject::connect(reply, &QModbusReply::finished, &loop, &QEventLoop::quit);
              

              Edit:
              Because of the lambda function, i mixed up the correct writing. It should be:

              auto connection = QObject::connect(reply, &QModbusReply::finished, [&loop]()
              { 
              loop.quit();
              }) ;
              
              1 Reply Last reply
              0
              • M MartinChan

                @beecksche Hi,Thx first and I have another little quesition .

                The code u provided,there is a line:

                 auto connection = QObject::connect(reply, &QModbusReply::finished, ()[&loop] { loop.quit(); }
                

                It seems u use the lambda expression in '()[&loop] { loop.quit(); }' (I am sorry for I didn't know too much about Lambda expression...)However,it didn't work,can I just use

                auto connection=QObject::connect(reply,&QModbusReply::finished,loop.quit()); 
                

                to replace it?If not,why??

                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @MartinChan You cannot do it like this:

                auto connection=QObject::connect(reply,&QModbusReply::finished,loop.quit());
                

                In this case you call the method loop.quit() instead of passing a pointer to it to connect. So, do it like @beecksche suggested.

                https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                0
                • beeckscheB beecksche

                  Hi @MartinChan,

                  I think you want to poll to your slave like http://www.modbusdriver.com/modpoll.html

                  If you want to have a synchronous API i would start a local QEventLoop after sending your request and stop this loop when the reply has finished. Sth like that:

                  void modclient::readCoil()
                  {
                   QModbusDataUnit readUnit(QModbusDataUnit::Coils,00000,4);
                   auto *reply = client->sendReadRequest(readUnit,1);
                  
                   QEventLoop loop;
                  
                   auto connection = QObject::connect(reply, &QModbusReply::finished, ()[&loop] { loop.quit(); }
                  
                   loop.start();
                   QObject::disconnect(connection);
                  
                   // now you can get the result of the query and do your stuff
                  
                   const QModbusDataUnit result=reply->result();
                   bool temp0=false,temp1=false;
                   qDebug()<<QString("The value of %1 is %2").arg(1).arg(result.value(1));
                   qDebug()<<QString("The value of %1 is %2").arg(3).arg(result.value(3));
                   if (result.value(1)==1) temp0=true;
                   ...
                  
                   if (polling)
                     QTimer::singleShot(interval, &modclient::readCoil)
                  
                  }
                  

                  Haven't testet the code, may you have to add some security mechanism in the event loop.

                  YunusY Offline
                  YunusY Offline
                  Yunus
                  wrote on last edited by
                  #8

                  @beecksche @MartinChan When I tried the code I get an error in the line:

                  loop.start();
                  

                  as

                  error: no member named 'start' in 'QEventLoop'
                  

                  What can cause that ?

                  jsulmJ 1 Reply Last reply
                  0
                  • YunusY Yunus

                    @beecksche @MartinChan When I tried the code I get an error in the line:

                    loop.start();
                    

                    as

                    error: no member named 'start' in 'QEventLoop'
                    

                    What can cause that ?

                    jsulmJ Offline
                    jsulmJ Offline
                    jsulm
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    @Yunus said in About QModbus usage(How to read coils at a fixed frequecy?):

                    What can cause that ?

                    It's not start but https://doc.qt.io/qt-6/qeventloop.html#exec ...

                    https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    0

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved