libmodbus在Windows端Qt 5上的使用注意事项

libmodbus在Windows端Qt 5上的使用注意事项

本人在制作软件时,要用到modbus通讯,就找了有关modbus通讯的资料,但是看过后觉得有些问题跟别人遇到的不太一样,所以就自己整理一下。

libmodbus库文件的下载和编译

libmodbus作为modbus的库,在官网上可直接下载,网上资料建议都是下载libmodbus-3.0.6.tar.gz版本,不过在官网上只找到了3.1.6的版本,介绍讲是长期稳定的,遂下载。解压libmodbus压缩包,是两个文件夹,libmodbus-3.1.6和PaxHeaders.27399。打开libmodbus-3.1.6文件夹,找到configure配置脚本,需要利用工具生成config.h文件。

下载和安装msys工具

在网上搜了一些资料,其中有一篇博客讲解的比较详细,我是照他的步骤一步步来的。网址我贴在下边了:

我是直接在github上下载msys的,资源挺多,我选择的是msys2-installer,主要是电脑是64位的,就选择了64位的安装包,下载很快,90M也就十几秒。双击exe文件,安装即可,比想象中的要简单,安装完成后,在开始菜单栏,发现有三种启动方式,先不用管它,随便一种方式打开;
下载网址:https://github.com/msys2/msys2-installer
我是根据自己的需求,选择性的安装了功能,分别如下:
**1.**实现 cd +文件名进入目录:打开/etc/profile文件,添加一个关键变量:“export MSYS="winsymlinks:lnk”
**2.**配置国内镜像,方便快捷下载资源:在/etc/pacman.d文件中对3个镜像文件mirrorlist文件进行修改,我采用的是博主挂出的配置。
**3.**安装git和vim编辑器:有点像linux了, 安装命令:pacman -S git;
**4.**安装配置zsh:在linux下,默认采用的是bash,但是现在大多数人都用zsh,方便快捷。安装zsh的命令:pacman -S zsh ;zsh主题采用oh-my-zsh,需要链接到相应的github网址,进行下载,我采用的是博主发的第二种途径,有效。
**5 .**修改默认shell为zsh:在msys2_shell.cmd文件中,将LOGINSHELL的变量,改为zsh,则启动msys2后自动进入zsh,并自己选择oh-my-zsh中的主题,我采用了ys。采用vim编辑器在根目录下,打开zshrc文件,修改其中的ZSH_THEME的名字,完成修改。
**6 .**最重要的部分:gcc的安装和环境配置:我安装的是mingw64 mingw-x86_64-gcc版本。安装命令:pacman -S mingw -w64-x86_64-gcc.安装完成。

config.h的生成

打开msys2,找到之前解压文件下的configure文件,并运行,然后将libmodbus3.1.6文件夹下src文件夹中所有的.c和.h文件复制到一个空文件夹中,将生成的config.h文件也复制进去,将文件夹命名为libmodbus。至此,libmodbus库文件生成。
在这里插入图片描述

Qt 新建项目

在Windows端打开Qt,我的Qt的版本是5.13.2,QtCreater的版本是4.10.1,打开后,新建工程文件后,在添加文件选项中,将上述libmodbus文件中所有的文件选中,添加进去,特别需要注意的是config.h路径的问题,config.h的路径为你的libmodbus文件中config.h的路径,因此需要对比如modbus-private.h、modbus.c等头文件中含有config.h路径的文件。

在这里插入图片描述

添加dll文件

此外,modbus库依赖于window系统的ws2_32.dll库文件,在c盘中搜索,复制到所建立的项目文件夹下,命名为dll文件夹,并在项目文件.pro中添加“LIBS += -Ldll -lws2_32”,完成,开始运行程序。

测试代码

测试代码是参考一篇博主的,但是博主贴的代码是5年前的,另外只贴了工程文件.pro和.cpp文件,所以我在现有编译的libmodbus库的基础上,根据博主之间的代码做了些调整,因为在运行的过程中,发现了modbus.h文件中的一些API函数的定义发生了变,导致Qt文件在编译的过程中出现了一些错误。

以下是5年前博主生成的libmodbus库中modbus.h文件中的关于响应超时的API是这样的:

void modbus_get_response_timeout(modbus_t *ctx, struct timeval *timeout);
void modbus_set_response_timeout(modbus_t *ctx, const struct timeval *timeout);

然而我现在编译出的libmodbus库中modbus.h文件中关于响应超时API的定义是这样的:

扫描二维码关注公众号,回复: 11780216 查看本文章
MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);

首先是返回值的数据类型不一致,然后就是函数的参数不一致,所以在引用博主的代码测试时,需要做一些额外的修改。

1.工程文件代码 libmodbus.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11
LIBS += -Ldll -lws2_32

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked 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 it uses 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 += \
    H:/libmodbus/modbus-data.c \
    H:/libmodbus/modbus-rtu.c \
    H:/libmodbus/modbus-tcp.c \
    H:/libmodbus/modbus.c \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    H:/libmodbus/config.h \
    H:/libmodbus/modbus-private.h \
    H:/libmodbus/modbus-rtu-private.h \
    H:/libmodbus/modbus-rtu.h \
    H:/libmodbus/modbus-tcp-private.h \
    H:/libmodbus/modbus-tcp.h \
    H:/libmodbus/modbus-version.h \
    H:/libmodbus/modbus.h \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${
    
    TARGET}/bin
else: unix:!android: target.path = /opt/$${
    
    TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2.主窗口头文件 mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include<QPushButton>
#include "H:/libmodbus/modbus.h"

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    
    
    Q_OBJECT

    struct timeval
    {
    
    
        uint32_t  tv_sec;
        uint32_t  tv_usec;
    };

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    QPushButton *pbRtu;
    QPushButton *pbTcp;

private slots:
    void doRtuQuery();

    void doTcpQuery();




private:
    Ui::MainWindow *ui;


};
#endif // MAINWINDOW_H

3.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QMessageBox>
#include "H:/libmodbus/modbus.h"
#include <QPushButton>



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),ui(new Ui::MainWindow)

{
    
    

    ui->setupUi(this);
    this->resize(200, 60);
        this->setWindowTitle("libmodbus slave test");

        pbRtu=new QPushButton("以modbus rtu方式读取地址1中前20个寄存器值", this);
        pbRtu->resize(200, 30);

        pbTcp=new QPushButton("以modbus tcp方式读取地址1中前20个寄存器值", this);
        pbRtu->resize(200, 30);

        QWidget *w=new QWidget();

        QVBoxLayout *layout=new QVBoxLayout();
        layout->addWidget(pbRtu);
        layout->addWidget(pbTcp);

        w->setLayout(layout);

        this->setCentralWidget(w);

        connect(pbRtu, SIGNAL(clicked()), this, SLOT(doRtuQuery()));
        connect(pbTcp, SIGNAL(clicked()), this, SLOT(doTcpQuery()));

}


MainWindow::~MainWindow()
{
    
    
    delete ui;
}



void MainWindow::doRtuQuery()
{
    
    
    //RTU
    modbus_t *mb;
    uint16_t tab_reg[32]={
    
    0};

    mb = modbus_new_rtu("COM3", 9600, 'N', 8, 1);   //相同的端口只能同时打开一个
    modbus_set_slave(mb, 1);  //设置modbus从机地址

    modbus_connect(mb);

    struct timeval t;
    t.tv_sec=0;
    t.tv_usec=1000000;   //设置modbus超时时间为1000毫秒
    modbus_set_response_timeout(mb, t.tv_sec,t.tv_usec);

    int regs=modbus_read_registers(mb, 0, 10, tab_reg);

    QMessageBox::about(NULL, "报告", QString("RTU 读取寄存器的个数: %1").arg(regs));
    modbus_close(mb);
    modbus_free(mb);

}

void MainWindow::doTcpQuery()
{
    
    
    //TCP
    modbus_t *mb;
    uint16_t tab_reg[32]={
    
    0};

    mb = modbus_new_tcp("127.0.0.1", 502);  //由于是tcp client连接,在同一个程序中相同的端口可以连接多次。
    modbus_set_slave(mb, 1);  //从机地址

    modbus_connect(mb);

    struct timeval t;
    t.tv_sec=0;
    t.tv_usec=1000000;   //设置modbus超时时间为1000毫秒,注意:经测试,如果没有成功建立tcp连接,则该设置无效。
    modbus_set_response_timeout(mb, t.tv_sec,t.tv_usec);

    int regs=modbus_read_registers(mb, 0, 10, tab_reg);

    QMessageBox::about(NULL, "报告", QString("TCP 读取寄存器的个数: %1").arg(regs));
    modbus_close(mb);
    modbus_free(mb);

}



至此,分享的内容就算结束了,希望有用,谢谢~
参考博客
参考博客2
下载Msys

猜你喜欢

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