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
-
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(); }
-
Can you give the name of the device ?
-
You didn't get any documentation for that device ?
-
It is indeed. What exact error message are you getting ?
-
@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