Windows端,libmodbus + Qt 上位机测试

Windows端,libmodbus + Qt 上位机测试

本文是在上一篇VS上实现modbus通讯的基础上,在Qt上做了一些简单的修改,以实现Qt上modbus的通讯。(也算是曲线救国了)

理清思路

一直以来,我对于Modbus-Master(主机端)和Modbus-Slave(从机端)通讯中,关于到底是在哪一端对寄存器赋值有点纠结。
主要原因:

  • 1.是自己对通讯概念的不清晰,主机端和从机端都可以传递数据,都可对寄存器进行赋值;
  • 2.参考网上的资料,大都是在Qt端建立Master与Slave的连接,而赋值是在工具Modbus Slave上完成的,所以造成误解

嵌入式STM32学习笔记(8)——libmodbus+Qt上位机测试
文中所展示的功能即是在Modbus Slave工具中对寄存器进行赋值,连接成功后,在命令窗口可看到值的传递情况。
但是对于我的实际情况中,Qt作为上位机,要通过对Slave端传递数值,以达到发送指令的效果。所以需要,对其中的代码做一些修改才能为我所用。

验证思路

在写代码前,需要对思路进行验证,看是否合理,首先借助Modbus辅助工具。

Modbus 辅助工具测试

借用辅助工具,建立Modbus Poll和Modbus Slave连接,然后分别以Modbus Poll端传递数据给Modbus Slave端,接着以Modbus Slave端传递数据给Modbus Poll端。
1.从Modbus Poll端传递0-9值给Modbus Slave端,如下图1所示。
图1

Tx表示发送,Rx表示接收。
Modbus Poll端先发送 03 00 00 00 0A C5 CD
Modbus Slave端接收到这串代码,
Modbus Slave端发送
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 Poll端收到

这个过程我有点疑惑,是为什么?
这个辅助软件有个bug,是在Modbus Poll赋值的过程中,直接就将值send给Modbus Slave中去了,这个测试没有说明问题。
2.从Modbus Slave端传递10-1值给Modbus Poll端,如下图2所示。
图2

同样,Tx表示发送,Rx表示接收。
Modbus Poll端先发送 03 00 00 00 0A C5 CD
Modbus Slave端接收到03 00 00 00 0A C5 CD
Modbus Slave端发送
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端收到

Qt上位机作Modbus-Master

以上位机Qt作Modbus-Master(主机端),并在主机端,对寄存器进行赋值,采用了随机采样赋值方法。
先贴上代码:
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需要释放掉
}




执行后的效果,如下图所示:
图3
可以看到,寄存器赋的值已经传递进Modbus Slave中,说明此代码在Modbus Master端赋值寄存器的值有效。
另外,在做这一测试时,希望借助我的上两篇文章的参考,包括libmodbus库的编辑以及modbus通讯模拟。
参考1:libmodbus在Windows端Qt 5上的使用注意事项
参考2:Visual Studio 上基于libmodbus库的modbus RTU模式的通讯模拟
参考3:嵌入式STM32学习笔记(8)——libmodbus+Qt上位机测试

猜你喜欢

转载自blog.csdn.net/qq_43552324/article/details/108714390