Windows side, libmodbus + Qt PC test
This article is based on the realization of modbus communication on VS, and some simple modifications have been made on Qt to realize modbus communication on Qt. (It can be regarded as a curve to save the country)
Clear thinking
For a long time, I am a bit entangled in the communication between Modbus-Master (master side) and Modbus-Slave (slave side) as to which end is assigned to the register.
main reason:
- 1. It is because I am not clear about the concept of communication. Both the host side and the slave side can transmit data, and both can assign values to registers;
- 2. Referring to the information on the Internet, most of the connections between Master and Slave are established on the Qt side, and the assignment is done on the tool Modbus Slave, which causes misunderstandings
Embedded STM32 study notes (8)-libmodbus+Qt host computer test
The function shown in the text is to assign values to the registers in the Modbus Slave tool. After the connection is successful, you can see the value transfer in the command window.
But in my actual situation, Qt, as a host computer, must pass values to the Slave end to achieve the effect of sending instructions. So I need to make some changes to the code in it to work for me.
Verification idea
Before writing the code, you need to verify the idea to see if it is reasonable. First, use Modbus auxiliary tools.
Modbus auxiliary tool test
Borrow auxiliary tools to establish Modbus Poll and Modbus Slave connections, and then use Modbus Poll to transmit data to Modbus Slave, and then use Modbus Slave to transmit data to Modbus Poll.
1. Pass 0-9 values from Modbus Poll to Modbus Slave, as shown in Figure 1 below.
Tx means sending, Rx means receiving.
Modbus Poll first sends 03 00 00 00 0A C5 CD
Modbus Slave receives this string of codes,
Modbus Slave sends
03 14 00 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 CD 51
Modbus Received on the Poll
I am a little confused about this process, why?
There is a bug in this auxiliary software. It directly sends the value to Modbus Slave during the Modbus Poll assignment process. This test did not explain the problem.
2. Pass 10-1 value from Modbus Slave end to Modbus Poll end, as shown in Figure 2 below.
Similarly, Tx means sending and Rx means receiving.
Modbus Poll first sends 03 00 00 00 0A C5 CD
Modbus Slave receives 03 00 00 00 0A C5 CD
Modbus Slave sends
03 14 00 0A 00 09 00 08 00 07 00 06 00 05 00 04 00 03 00 02 00 01 AD B5
Modbus Poll end received
Qt host computer as Modbus-Master
The upper computer Qt is used as Modbus-Master (host side), and on the host side, the register is assigned, using random sampling assignment method.
Paste the code first:
1.mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <libmodbus/modbus.h>
#define ADDRESS_START 0
#define ADDRESS_END 9
#define LOOP 1
QT_BEGIN_NAMESPACE
namespace Ui {
class myWidget; }
QT_END_NAMESPACE
class myWidget : public QWidget
{
Q_OBJECT
public:
myWidget(QWidget *parent = nullptr);
~myWidget();
private slots:
void on_pushButton_clicked();
private:
Ui::myWidget *ui;
modbus_t *ctx;
uint16_t *tab_reg;
uint16_t *send_tab_reg;
int nb;
int addr;
modbus_mapping_t *mb_mapping;
int nb_fail;
int nb_loop;
};
#endif // MYWIDGET_H
2.mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include "libmodbus/modbus.h"
#include "QThread"
#include <QtDebug>
#include <errno.h>
#include <stdlib.h>
#include <malloc.h>
myWidget::myWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::myWidget)
{
ui->setupUi(this);
}
myWidget::~myWidget()
{
delete ui;
}
void myWidget::on_pushButton_clicked()
{
int rc;
int i;
ctx = modbus_new_rtu("COM3", 115200, 'N', 8, 1);
modbus_set_slave(ctx,1);
modbus_set_debug(ctx,TRUE);
if (modbus_connect(ctx)==-1)
{
fprintf(stderr, "Connection failed: %s\n",modbus_strerror(errno));
modbus_free(ctx);
}
/*
uint32_t old_response_to_sec;//秒
uint32_t old_response_to_usec;//微秒,1秒=1,000,000微秒
modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);//获取当前设置的超时
modbus_set_response_timeout(ctx,0,50000);//设定超时,默认50ms(50,000us)
qDebug()<<"get timeout sec:"<<old_response_to_sec;
qDebug()<<"get timeout usec:"<<old_response_to_usec;
printf("\n----------------\n");*/
nb=ADDRESS_END-ADDRESS_START;
tab_reg=(uint16_t *)malloc(nb * sizeof(uint16_t));
memset(tab_reg,0,nb * sizeof(uint16_t));
/*写入保持寄存器数值*/
nb_loop=nb_fail=0;
while(nb_loop++<LOOP)
{
for(addr=ADDRESS_START;addr<ADDRESS_END;addr++)
{
int i;
for(i=0;i<nb;i++)
{
tab_reg[i]=(uint16_t)(65535*rand()/(RAND_MAX+1.0));
}
nb=ADDRESS_END-addr;
rc=modbus_write_register(ctx,addr,tab_reg[0]);
if(rc !=1)
{
printf("ERROR modbus_write_register(%d)\n",rc);
nb_fail++;
}
else
{
rc = modbus_read_registers(ctx,addr,1, tab_reg); //03#读取保持寄存器的值,(对象,起始地址,读取数量,存储读取到的值)
if (rc != 1)
{
fprintf(stderr,"%s\n", modbus_strerror(errno));
qDebug()<<"rc错误"<<modbus_strerror(errno);
nb_fail++;
}
else
{
qDebug()<<"链接成功";
for (i=0; i<10; i++)
{
printf("reg[%d] = %d(0x%x)\n", i, tab_reg[i], tab_reg[i]);
qDebug()<<"rc收到:"<<tab_reg[i];
}
}
}
}
}
modbus_close(ctx); //关闭modbus连接
modbus_free(ctx); //释放modbus资源,使用完libmodbus需要释放掉
}
The effect after execution is as shown in the figure below:
you can see that the value assigned to the register has been transferred to Modbus Slave, indicating that this code is valid at the Modbus Master end.
In addition, when doing this test, I hope to use the reference of my last two articles, including the editing of the libmodbus library and the modbus communication simulation.
Reference 1: Precautions for using libmodbus on Qt 5 on Windows
Reference 2: Communication simulation in modbus RTU mode based on libmodbus library on Visual Studio
Reference 3: Embedded STM32 learning notes (8)-libmodbus+Qt PC test