From 10:00 CET Friday 22nd November we will adjust how the server works to deal with some recently reported problems. Therefore there may be a load problem, if you experience more problems than usual trying to access the forum then please PM AndyS or any of the moderators so they can inform me.


Modbus problem, beginner



  • Hello,

    I new to qt, and to programming at all.
    I learned a bit of Basic (PICBasic), and i quite understand the way it works.
    Now i want to learn c++ to make a modbus programm.

    I already understand a bit of it, but now i encountered a problem.

    When i connect my PC to the modbus device, and press connect, it says no device connected. If i use an other programm it workes.

    I made a modification on the modbus master example, and thought that was the problem, but when i open master, and try to connect that, i get the same.

    Can it be something with me using W8.1 and the MingW32 compiler?

    I can not post the code now, because it is on my other pc, but the connection part is the same as on master. And this one is also not working.
    I tested the connection with MBreader, and this worked.

    Can it also be that QT askes a connection confirmation? And MBreader just starts to poll?

    Serial, 9600, no par. 1 stop, 8 data.
    This is also set.

    Thanks


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    You should provide more information:

    • Version of Qt
    • What type of hardware are you connecting to ?
    • What kind of device are you trying to connect to ?


  • Thanks,
    On the laptop that i am using for the connection i have :

    Qt Creator 4.4.1
    Based on Qt 5.9.2 (MSVC 2015, 32 bit)
    

    The hardware is an alarm/monitoring system.
    It is made to monitor some data, like temperatures, and if they exceed a certain point, it will give alarm. The whole system is controlled/checked by a display.
    On the system is a modbus connection, so you can add a computer to it, to create your own visualisation of the data.

    This all works, if i connect with MBreader. Today i did a check with CASmodbus scanner, and i saw this one also askes for a connection, and got it. But with my QT programm, and with (examples) master it does not connect.

    I will add the code. It is made as connection test, so i do have some remarks and old stuff still in there.

    Project:

    #-------------------------------------------------
    #
    # Project created by QtCreator 2017-10-17T19:11:13
    #
    #-------------------------------------------------
    
    QT       += core gui serialport serialbus
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = Noris_test
    TEMPLATE = app
    
    # The following define makes your compiler emit warnings if you use
    # any feature of Qt which has been marked as deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if you use deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    
    SOURCES += \
            main.cpp \
            mainwindow.cpp \
        settings.cpp
    
    HEADERS += \
            mainwindow.h \
        settings.h
    
    FORMS += \
            mainwindow.ui \
        settings.ui
    
    

    Header mainwindow:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QtSerialPort/QSerialPort>
    #include <QtSerialBus/QModbusRtuSerialMaster>
    #include <QtSerialBus/QtSerialBus>
    #include <QModbusDataUnit>
    #include "settings.h"
    
    
    QT_BEGIN_NAMESPACE
    
    class QModbusClient;
    class QModbusReply;
    
    namespace Ui {
    class MainWindow;
    class Settings;
    }
    
    QT_END_NAMESPACE
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    
    private:
        QModbusDataUnit readRequestIR() const;
        QModbusDataUnit readRequestCO() const;
        QModbusDataUnit readRequestHR() const;
        QModbusDataUnit readRequestDI() const;
        Settings *settingswindow;
    
    private slots:
    
    //    void serialReceived();
        void readReadyCO();
        void readReadyDI();
        void readReadyIR();
        void readReadyHR();
        void onStateChanged(int state);
    
    
    
        void on_PB_dis_clicked();
    
        void on_PB_con_clicked();
    
        void on_actionExit_triggered();
    
    private slots:
    
        void updateRPM(const QString);
    
        void on_actionSettings_triggered();
    
    private:
        Ui::MainWindow *ui;
        QModbusReply *lastRequest;
        QModbusClient *modbusDevice;
        Settings *m_settings;
    
    
    };
    
    #endif // MAINWINDOW_H
    
    

    Header Settings

    #ifndef SETTINGS_H
    #define SETTINGS_H
    
    #include <QMainWindow>
    #include <QDialog>
    #include <QSerialPort>
    
    namespace Ui {
    class Settings;
    }
    
    class Settings : public QMainWindow
    {
        Q_OBJECT
    
    public:
        struct Startsettings {
            QString port ;
            int parity = QSerialPort::NoParity;
            int baud = QSerialPort::Baud9600;
            int dataBits = QSerialPort::Data8;
            int stopBits = QSerialPort::OneStop;
            int responseTime = 10000;
            int numberOfRetries = 3;
    
        };
    
        explicit Settings(QWidget *parent = 0);
        ~Settings();
    
        Startsettings startsettings() const;
    
    private slots:
        void on_closeButton_clicked();
    
    private:
        Startsettings m_settings;
        Ui::Settings *ui;
    };
    
    #endif // SETTINGS_H
    
    

    Source mainwindow:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QtSerialPort/QSerialPort>
    #include <QtSerialPort/QSerialPortInfo>
    #include <QtSerialBus>
    #include <QModbusRtuSerialMaster>
    #include <QStandardItemModel>
    #include <QStatusBar>
    #include <string>
    #include <QDebug>
    #include <QMessageBox>
    #include "qmessagebox.h"
    #include "settings.h"
    
    enum ModbusConnection {
       Serial
    };
    
    
    //QSerialPort *serial;
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
        , lastRequest(nullptr)
        , modbusDevice(nullptr)
    {
        ui->setupUi(this);
        m_settings = new Settings(this);
        statusBar()->showMessage("Check Settings before connecting");
    
    
    
    
    //    serial = new QSerialPort(this);
    //    serial->setPortName("com1");
    //    serial->setBaudRate(QSerialPort::Baud9600);
    //    serial->setDataBits(QSerialPort::Data8);
    //    serial->setParity(QSerialPort::NoParity);
    //    serial->setStopBits(QSerialPort::OneStop);
    //    serial->setFlowControl(QSerialPort::NoFlowControl);
    //    serial->open(QIODevice::ReadWrite);
    //    connect(serial, SIGNAL(readyRead()),this,SLOT(serialReceived()));
    
    
    
    
        ui->RPM->display("-----");
        ui->HTT->display("-----");
        ui->HTP->display("-----");
    
    //    const auto ports = QSerialPortInfo::availablePorts();
    //    for (const QSerialPortInfo &info : ports)
    //        ui->serialPortCombo->addItem(info.portName(), false);
    
    
    
    
    
    
    
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
        if (modbusDevice)
            modbusDevice->disconnectDevice();
        delete modbusDevice;
    }
    
    
    //void MainWindow::serialReceived()
    
    //{
    //    QByteArray ba;
    //    ba=serial->readAll();
    //    ui->label_4->setText(ba);
    //    qDebug()<<ba;
    
    //}
    
    void MainWindow::on_PB_dis_clicked()
    {
        if (modbusDevice)
            modbusDevice->disconnectDevice();
        delete modbusDevice;
        ui->statusBar->showMessage("Disconnecting",5000);
    }
    
    void MainWindow::on_PB_con_clicked()
    {
    
    
        QMessageBox msgBox;
        msgBox.setWindowTitle("CONNECTING");
        msgBox.setText("Please check your settings before connecting");
    
        QAbstractButton*
                pbuttonyes =
                msgBox.addButton("Settings", QMessageBox::YesRole);
                msgBox.addButton("No", QMessageBox::NoRole);
                msgBox.exec();
    if (msgBox.clickedButton()==pbuttonyes){
    
           settingswindow =new Settings(this);
           settingswindow->setFixedSize(250, 360);
           settingswindow->setWindowTitle("Settings");
           settingswindow->show();
       return;
       }
       else {
    
    
    
    
    
        if (!modbusDevice)
            ui->statusBar->showMessage("No device connected");
            return;
    
        statusBar()->clearMessage();
        if (modbusDevice->state() != QModbusDevice::ConnectedState) {
    
                    modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
                    m_settings->startsettings().port);
                    modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
                        m_settings->startsettings().parity);
                    modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
                        m_settings->startsettings().baud);
                    modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
                        m_settings->startsettings().dataBits);
                    modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
                        m_settings->startsettings().stopBits);
    
    }
        modbusDevice->setTimeout(m_settings->startsettings().responseTime);
        modbusDevice->setNumberOfRetries(m_settings->startsettings().numberOfRetries);;
                if (!modbusDevice->connectDevice()) {
                    statusBar()->showMessage(tr("Connect failed: ") + modbusDevice->errorString(), 5000);
                }else{ statusBar()->showMessage("Connected");
    }
    
    
                if (!modbusDevice)
                    return;
                statusBar()->clearMessage();
    
    
    //begin lezen CO1
    if (auto *replyCO = modbusDevice->sendReadRequest(readRequestCO(), 1)) {
    if (!replyCO->isFinished())
    connect(replyCO, &QModbusReply::finished, this, &MainWindow::readReadyCO);
    else
    delete replyCO; // broadcast replies return immediately
    } else {
    statusBar()->showMessage(tr("Read CO error: ") + modbusDevice->errorString(), 5000);
    }
    
    //einde lezen CO1
    
    //begin lezen DI1
    if (auto *replyDI = modbusDevice->sendReadRequest(readRequestDI(), 1)) {
    if (!replyDI->isFinished())
    connect(replyDI, &QModbusReply::finished, this, &MainWindow::readReadyDI);
    else
    delete replyDI; // broadcast replies return immediately
    } else {
    statusBar()->showMessage(tr("Read DI error: ") + modbusDevice->errorString(), 5000);
    }
    
    //einde lezen DI1
    
    //begin lezen IR1
    if (auto *replyIR = modbusDevice->sendReadRequest(readRequestIR(), 1)) {
    if (!replyIR->isFinished())
    connect(replyIR, &QModbusReply::finished, this, &MainWindow::readReadyIR);
    else
    delete replyIR; // broadcast replies return immediately
    } else {
    statusBar()->showMessage(tr("Read IR error: ") + modbusDevice->errorString(), 5000);
    }
    
    //einde lezen IR1
    
    //begin lezen HR1
    if (auto *replyHR = modbusDevice->sendReadRequest(readRequestHR(), 1)) {
    if (!replyHR->isFinished())
    connect(replyHR, &QModbusReply::finished, this, &MainWindow::readReadyHR);
    else
    delete replyHR; // broadcast replies return immediately
    } else {
    statusBar()->showMessage(tr("Read HR error: ") + modbusDevice->errorString(), 5000);
    }
    
    //einde lezen HR1
    
    
    
    
       }}
    
    
    
    
    //readrequest 1
    QModbusDataUnit MainWindow::readRequestCO() const
    {
       const auto table =
            static_cast<QModbusDataUnit::RegisterType> (QModbusDataUnit::Coils);
    
        int startAddress1 = (100);
        int numberOfEntries1 = (5);
       return QModbusDataUnit(table, startAddress1, numberOfEntries1);
    }
    
    QModbusDataUnit MainWindow::readRequestDI() const
    {
       const auto table =
            static_cast<QModbusDataUnit::RegisterType> (QModbusDataUnit::DiscreteInputs);
    
        int startAddress1 = (100);
        int numberOfEntries1 = (5);
       return QModbusDataUnit(table, startAddress1, numberOfEntries1);
    }
    
    QModbusDataUnit MainWindow::readRequestIR() const
    {
       const auto table =
            static_cast<QModbusDataUnit::RegisterType> (QModbusDataUnit::InputRegisters);
    
        int startAddress1 = (100);
        int numberOfEntries1 = (5);
       return QModbusDataUnit(table, startAddress1, numberOfEntries1);
    }
    
    QModbusDataUnit MainWindow::readRequestHR() const
    {
       const auto table =
            static_cast<QModbusDataUnit::RegisterType> (QModbusDataUnit::HoldingRegisters);
    
        int startAddress1 = (100);
        int numberOfEntries1 = (5);
       return QModbusDataUnit(table, startAddress1, numberOfEntries1);
    }
    
    
    
    
    //readrequest einde
    
    void MainWindow::readReadyCO()
    {
    {
    auto replyCO = qobject_cast<QModbusReply *>(sender());
    if (!replyCO)
    return;
    
    if (replyCO->error() == QModbusDevice::NoError) {
    const QModbusDataUnit unit = replyCO->result();
    for (uint i = 0; i < unit.valueCount(); i++) {
        const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i)
                                 .arg(QString::number(unit.value(i),
                                      unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16));
    //    ui->label_4->setText(entry);
    }
    } else if (replyCO->error() == QModbusDevice::ProtocolError) {
    statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
                                arg(replyCO->errorString()).
                                arg(replyCO->rawResult().exceptionCode(), -1, 16), 5000);
    } else {
    statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
                                arg(replyCO->errorString()).
                                arg(replyCO->error(), -1, 16), 5000);
    }
    
    replyCO->deleteLater();
    }
    
    }
    void MainWindow::readReadyDI()
    {
    {
    auto replyDI = qobject_cast<QModbusReply *>(sender());
    if (!replyDI)
    return;
    
    if (replyDI->error() == QModbusDevice::NoError) {
    const QModbusDataUnit unit = replyDI->result();
    for (uint i = 0; i < unit.valueCount(); i++) {
        const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i)
                                 .arg(QString::number(unit.value(i),
                                      unit.registerType() <= QModbusDataUnit::DiscreteInputs ? 10 : 16));
    //    ui->label_4->setText(entry);
    }
    } else if (replyDI->error() == QModbusDevice::ProtocolError) {
    statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
                                arg(replyDI->errorString()).
                                arg(replyDI->rawResult().exceptionCode(), -1, 16), 5000);
    } else {
    statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
                                arg(replyDI->errorString()).
                                arg(replyDI->error(), -1, 16), 5000);
    }
    
    replyDI->deleteLater();
    }
    
    }
    void MainWindow::readReadyIR()
                {
        {
            auto replyIR = qobject_cast<QModbusReply *>(sender());
            if (!replyIR)
                return;
    
            if (replyIR->error() == QModbusDevice::NoError) {
                const QModbusDataUnit unit = replyIR->result();
                for (uint i = 0; i < unit.valueCount(); i++) {
                    const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i)
                                             .arg(QString::number(unit.value(i),
                                                  unit.registerType() <= QModbusDataUnit::InputRegisters ? 10 : 16));
                    MainWindow::updateRPM(entry[8]);
                    ui->label_4->setText(entry);
    
                }
            } else if (replyIR->error() == QModbusDevice::ProtocolError) {
                statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
                                            arg(replyIR->errorString()).
                                            arg(replyIR->rawResult().exceptionCode(), -1, 16), 5000);
            } else {
                statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
                                            arg(replyIR->errorString()).
                                            arg(replyIR->error(), -1, 16), 5000);
            }
    
            replyIR->deleteLater();
        }
    
    }
    
    void MainWindow::updateRPM(const QString RPMreading)
    
    {
    ui->RPM->display(RPMreading);
    }
    
    void MainWindow::readReadyHR()
    {
    {
    auto replyHR = qobject_cast<QModbusReply *>(sender());
    if (!replyHR)
    return;
    
    if (replyHR->error() == QModbusDevice::NoError) {
    const QModbusDataUnit unit = replyHR->result();
    for (uint i = 0; i < unit.valueCount(); i++) {
        const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress() + i)
                                 .arg(QString::number(unit.value(i),
                                      unit.registerType() <= QModbusDataUnit::HoldingRegisters ? 10 : 16));
    //    ui->label_4->setText(entry);
    }
    } else if (replyHR->error() == QModbusDevice::ProtocolError) {
    statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
                                arg(replyHR->errorString()).
                                arg(replyHR->rawResult().exceptionCode(), -1, 16), 5000);
    } else {
    statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
                                arg(replyHR->errorString()).
                                arg(replyHR->error(), -1, 16), 5000);
    }
    
    replyHR->deleteLater();
    }
    
    }
    
    void MainWindow::onStateChanged(int state)
    {
    
        if (state == QModbusDevice::UnconnectedState)
            statusBar()->showMessage("Disconnected");
        else if (state == QModbusDevice::ConnectedState)
            statusBar()->showMessage("Connected");
    }
    
    void MainWindow::on_actionExit_triggered()
    {
        MainWindow::close();
    }
    
    
    
    void MainWindow::on_actionSettings_triggered()
    {
        settingswindow =new Settings(this);
        settingswindow->setFixedSize(250, 360);
        settingswindow->setWindowTitle("Settings");
        settingswindow->show();
    }
    
    

    Source main:

    #include "mainwindow.h"
    
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.setFixedSize(280, 500);
        w.setWindowTitle("Noris Test");
        w.show();
    
    
        return a.exec();
    }
    
    

    source settings:

    #include "settings.h"
    #include "ui_settings.h"
    #include <QSerialPortInfo>
    #include <QtSerialBus>
    #include "mainwindow.h"
    
    Settings::Settings(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::Settings)
    {
        ui->setupUi(this);
        const auto ports = QSerialPortInfo::availablePorts();
        for (const QSerialPortInfo &info : ports)
    
        ui->comCombo2->addItem(info.portName(), false);
        ui->comCombo2->setCurrentIndex(1);
        ui->parityCombo->setCurrentIndex(0);
        ui->baudCombo->setCurrentText(QString::number(m_settings.baud));
        ui->dataBitsCombo->setCurrentText(QString::number(m_settings.dataBits));
        ui->stopBitsCombo->setCurrentText(QString::number(m_settings.stopBits));
        ui->timeoutSpinner->setValue(m_settings.responseTime);
        ui->retriesSpinner->setValue(m_settings.numberOfRetries);
    
    
    
    
    
    
    
    
    
        connect(ui->applyButton, &QPushButton::clicked, [this]() {
            m_settings.port = ui->comCombo2->currentText();
            m_settings.parity = ui->parityCombo->currentIndex();
            if (m_settings.parity > 0)
                m_settings.parity++;
            m_settings.baud = ui->baudCombo->currentText().toInt();
            m_settings.dataBits = ui->dataBitsCombo->currentText().toInt();
            m_settings.stopBits = ui->stopBitsCombo->currentText().toInt();
            m_settings.responseTime = ui->timeoutSpinner->value();
            m_settings.numberOfRetries = ui->retriesSpinner->value();
    
            ui->statusbar->showMessage("Settings saved, press close.");
        });
    }
    
    Settings::~Settings()
    {
        delete ui;
    }
    
    
    Settings::Startsettings Settings::startsettings() const
    {
        return m_settings;
    }
    
    void Settings::on_closeButton_clicked()
    {
        hide();
    }
    
    

  • Lifetime Qt Champion

    Can you give the name of the device ?



  • I only have the maker of the device, Thats Noris Automation, this is all I have, the system was build and running before I got to know it. And this is written on the display.


  • Lifetime Qt Champion

    You didn't get any documentation for that device ?



  • No, not that i am aware of. But the strange thing in my opinion is that the other programms do work.


  • Lifetime Qt Champion

    It is indeed. What exact error message are you getting ?


  • Moderators

    @GhostWolf just a question on my side, did you check the Modbus-Settings of the ModbusMaster example? For whatever reason, its default Baud Rate is, IIRC 19200, and not the 9600 your device is supposed to have.



  • Thanks for the answers, I found the connection problem. I added the part:

    void MainWindow::on_connectType_currentIndexChanged(int index)
    {
    if (modbusDevice) {
    modbusDevice->disconnectDevice();
    delete modbusDevice;
    modbusDevice = nullptr;
    }

    auto type = static_cast<ModbusConnection> (index);
    if (type == Serial) {
        modbusDevice = new QModbusRtuSerialMaster(this);
    } else if (type == Tcp) {
        modbusDevice = new QModbusTcpClient(this);
        if (ui->portEdit->text().isEmpty())
            ui->portEdit->setText(QLatin1Literal("127.0.0.1:502"));
    }
    
    connect(modbusDevice, &QModbusClient::errorOccurred, [this](QModbusDevice::Error) {
        statusBar()->showMessage(modbusDevice->errorString(), 5000);
    });
    
    if (!modbusDevice) {
        ui->connectButton->setDisabled(true);
        if (type == Serial)
            statusBar()->showMessage(tr("Could not create Modbus master."), 5000);
        else
            statusBar()->showMessage(tr("Could not create Modbus client."), 5000);
    } else {
        connect(modbusDevice, &QModbusClient::stateChanged,
                this, &MainWindow::onStateChanged);
    }
    

    }

    And now I can make a connection.

    Now I have to test it on the device, but i can't access it for a while, to be continued