精华内容
下载资源
问答
  • libmodbus使用说明

    万次阅读 多人点赞 2018-01-20 13:30:38
    Modbus协议 百度解释 Modbus协议是应用于电子控制器上...此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一个控制器请求访问其它设备的过程,如何回应来自其它设

    Modbus协议

    百度解释

    Modbus协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一种通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一个控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

    当在同一Modbus网络上通信时,此协议决定了每个控制器需要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。

    此协议支持传统的RS-232、RS-422、RS-485和以太网设备。许多工业设备,包括PLC,DCS,智能仪表等都在使用Modbus协议作为他们之间的通信标准。

    应用场景

    项目中经常需要和各式各样的PLC进行通讯,开始的时候是三菱Q系列的5u,用的是SLMP协议,后面又对接了安川的PLC,指不定以后会用哪家的PLC,所以考虑到是不是应该换一个通用性比较强的接口协议,可以省去大量时间和精力。
    网上搜了一下,发现Modbus算是比较通用的协议了,也搜到了很多资料,因为对C++ 比较熟悉,所以搜的都是C++ 的Modbus资源。正好找到了libmodbus这个开源库,通读了一遍代码,觉得很不错,很强大,所以有了这篇文章。

    libmodbus配置

    官网下载了代码,用vs2013编译了一下,我自己编译生成的libCSDN下载地址(2分)Gitee下载地址(免积分)。还是很容易的。

    • 编译:
      libmodbus/src/win32目录下的 modbus-9.sln 文件,直接用vs打开编译就可以了。

    • 生成:
      libmodbus/src/win32目录下生成了
      modbus.dllmodbus.lib文件

    • 引用:
      工程包含头文件:modbus.h
      modbus-rtu.h

      modbus-tcp.h
      modbus-version.h
      库文件:
      modbus.lib
      程序目录下放入文件:
      modbus.dll

    libmodbus函数说明

    引入到工程之后,就需要了解几个主要的函数了。

    • 初始化与释放
    /* 
      以TCP的方式创建libmobus实例
      char *ip:连接的IP地址
      int port: 连接的IP端口
    */
    modbus_t *modbus_new_tcp(const char *ip, int port);
    
    /* 
      以串口的方式创建libmobus实例
      onst char *device:连接的串口号,类似是这样'\\\\.\\COM10'
      int baud: 波特率
      char parity:奇偶校验
      int data_bit:数据位
      int stop_bit:停止位
    */
    modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);
    
    /* 
      释放libmodbus实例,使用完libmodbus需要释放掉
      modbus_t *ctx:libmodbus实例
    */
    void modbus_free(modbus_t *ctx);
    
    • 读取
    /* 
      读取线圈状态,可读取多个连续线圈的状态
      modbus_t *ctx:Modbus实例
      int addr: 线圈地址
      int nb:读取线圈的个数
      uint8_t *dest: 传出的状态值
    */
    int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
    
    /* 
      读取输入状态,可读取多个连续输入的状态
      modbus_t *ctx:Modbus实例
      int addr:输入地址
      int nb:读取输入的个数
      uint8_t *dest:传出的状态值
    */
    int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
    
    /* 
      读取输入寄存器的值,可读取多个连续输入输入寄存器
      modbus_t *ctx:Modbus实例
      int addr:输入地址
      int nb:读取输入寄存器的个数
      uint8_t *dest:传出的寄存器值
    */
    int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
    
    /* 
      读取保持寄存器的值,可读取多个连续输入保持寄存器
      modbus_t *ctx:Modbus实例
      int addr:输入地址
      int nb:读取保持寄存器的个数
      uint8_t *dest:传出的寄存器值
    */
    int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
    
    
    • 写入
    /*
      写入单个线圈的状态
      modbus_t *ctx:Modbus实例
      int addr:线圈地址
      int status:线圈状态
    */
    int modbus_write_bit(modbus_t *ctx, int addr, int status);
    
    /*
      写入多个连续线圈的状态
      modbus_t *ctx:Modbus实例
      int addr:线圈地址
      int nb:线圈个数
      const uint8_t *src:多个线圈状态
    */
    int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
    
    /*
      写入单个寄存器
      modbus_t *ctx:Modbus实例
      int addr:寄存器地址
      int value:寄存器的值 
    */
    int modbus_write_register(modbus_t *ctx, int addr, int value);
    
    /*
      写入多个连续寄存器
      int addr:寄存器地址
      int nb:寄存器的个数
      const uint16_t *src:多个寄存器的值 
    */
    int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
    
    
    • float 浮点数

    libmodbus下处理浮点型真的是异常方便,我之前用的协议都是需要我自己转换的,在得到的寄存器的数据后,发现PLC的数解析的时候,可能分16位和32位的,拿16位举例,每4位一组就像ABCD,我们需要解析出来的是DCBA。
    后来我发现了libmodbus里面有这两个函数

    float modbus_get_float(const uint16_t *src);
    
    void modbus_set_float(float f, uint16_t *dest)
    

    这个两个函数主要是将整型数据转换成float,和将float转换成整型的。
    在用modbus_read_registers或者modbus_read_input_registers得到寄存器的值int16_t *dest,如果里面存的是浮点数,把dest当做参数传入到modbus_get_float里面,如果得到的值不对,你需要弄清楚PLC对应传出数据的模式是DCBA还是BADC,CDAB,ABCD。

    libmodbus还提供了其他函数

    modbus_get_float_abcd
    modbus_get_float_badc
    modbus_get_float_cdab
    modbus_get_float_dcba

    modbus_set_float_abcd
    modbus_set_float_badc
    modbus_set_float_cdab
    modbus_set_float_dcba

    下图是我在工作中常用的三菱5u PLC Modbus对应寄存器线圈输入等的地址。
    三菱5u Modbus对应的地址

    展开全文
  • libmodbus是功能强大的一个modbus库,可使用在C、C++、QT等平台下。本使用手册中文版,根据英文手册原版进行了翻译,方便大家使用
  • libmodbus使用类.rar

    2019-09-06 08:46:32
    c++调用libmodbus类,实现与plc通信,欢迎一块学习交流。
  • 使用手册在doc文件夹中,直接打开html文件查看,例子在tests文件中,库文件在src中。 libmodbus-3.0.3\libmodbus-3.0.3\doc\modbus_read_bits.html libmodbus-3.0.3\libmodbus-3.0.3\doc\modbus_read_bits.txt ...
  • libmodbus之嵌入式Linux使用及测试

    千次阅读 2019-08-02 15:05:30
    libmodbus使用ubuntu系统使用libmodbusarm-linux使用libmodbus解压安装移植编译modbus从机模拟 ubuntu系统使用libmodbus ubuntu系统可以直接使用apt命令进行库的安装。 sudo apt-get install libmodbus-dev 或者...

    1.ubuntu系统使用libmodbus

    ubuntu系统可以直接使用apt命令进行库的安装。

    sudo apt-get install libmodbus-dev
    或者
    sudo apt-get install libmodbus5
    

    2.arm-linux使用libmodbus

    库参考手册
    libmodbus-3.1.4源码

    2.1解压安装

    tar -xzvf libmodbus-3.1.4.tar.gz
    cd libmodbus-3.1.4
    # 新建安装文件夹
    mkdir -p install
    chmod 777 install
    ./configure --prefix=$(pwd)/install --host=arm-linux --enable-static ac_cv_func_malloc_0_nonnull=yes CC=arm-fsl-linux-gnueabi-gcc
    make
    make install
    

    2.2移植编译

    在我的应用程序工程里面新建一个 libmodbus 文件夹,将上面安装 install目录下的 include和lib文件夹拷贝过来
    移植文件
    我的工程总体结构如下所示
    工程目录结构
    在 mys_src 里面添加 modbus 主机测试程序 modbus_test.c
    makefile编写如下所示:

    #编译配置,使能为1
    CONFIG_MODBUS_BUILD = 1
    
    #当前路径
    CUR_DIR := $(shell pwd)
    
    #libmodbus目录
    LIBMODBUS_DIR := $(CUR_DIR)/../libmodbus
    
    # 头文件路径
    INCLUDE :=
    INCLUDE += -I$(CUR_DIR)/../include/
    ifeq ($(CONFIG_MODBUS_BUILD), 1)
    INCLUDE += -I$(LIBMODBUS_DIR)/include/modbus/
    endif
    
    #C编译器的选项
    CFLAGS :=
    CFLAGS += -g -Wall
    CFLAGS += -std=gnu99
    CFLAGS += $(INCLUDE)
    
    
    #库文件参数
    LDFLAGS :=
    #libmodbus共享库链接
    #LDFLAGS += -L$(LIBMODBUS_DIR)/lib
    #libmodbus静态库链接
    ifeq ($(CONFIG_MODBUS_BUILD), 1)
    LDFLAGS += $(LIBMODBUS_DIR)/lib/libmodbus.a
    endif
    
    
    SRCS += modbus_test.c
    OBJS += modbus_test.o
    BINS += modbus_test
    
    
    all:$(OBJS) $(BINS) 
    
    $(OBJS):%.o:%.c
        $(CC) -c $(CFLAGS) $^ -o $(OBJ_DIR)/$@
    
    $(BINS):$(OBJS)
        $(CC) -o $(BIN_DIR)/$@ $(OBJ_DIR)/$^ $(LDFLAGS)
    

    modbus_test.c

    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <modbus.h>
    
    #define MODBUS_DEV_NAME    "/dev/ttymxc3"    ///< 串口设备
    
    int main(void)
    {
        modbus_t *ctx =NULL;
    
        // 以串口的方式创建libmobus实例,并设置参数
        ctx = modbus_new_rtu(MODBUS_DEV_NAME, 115200, 'N', 8, 1);
        if (ctx == NULL)                //使用UART4,对应的设备描述符为ttymxc3
        {
            fprintf(stderr, "Unable to allocate libmodbus contex\n");
            return -1;
        }
        // 使用RS485时需考虑设置串口模式、RTS引脚等
    //    modbus_rtu_set_serial_mode(MODBUS_RTU_RS485);    //设置串口模式
    
        modbus_set_debug(ctx, 1);      //设置1可看到调试信息
        modbus_set_slave(ctx, 1);      //设置slave ID
    
        if (modbus_connect(ctx) == -1) //等待连接设备
        {
            fprintf(stderr, "Connection failed:%s\n", modbus_strerror(errno));
            return -1;
        }
    
        int i,rc;
        uint16_t tab_reg[64] = {0}; //定义存放数据的数组
        while (1)
        {
            printf("\n----------------\n");
            //读取保持寄存器的值,可读取多个连续输入保持寄存器
            rc = modbus_read_registers(ctx, 0, 10, tab_reg);
            if (rc == -1)
            {
                fprintf(stderr,"%s\n", modbus_strerror(errno));
                return -1;
            }
            for (i=0; i<10; i++)
            {
                printf("reg[%d] = %d(0x%x)\n", i, tab_reg[i], tab_reg[i]);
            }
    
            usleep(5000000);
        }
        modbus_close(ctx);  //关闭modbus连接
        modbus_free(ctx);   //释放modbus资源,使用完libmodbus需要释放掉
    
        return 0;
    }
    

    编译之后可通过nfs挂载进行测试

    2.3modbus从机模拟

    Modbus slave测试工具可以用来做modbus从机设备,从而实现arm控制板通过串口与PC端模拟的modbus从机进行通信测试。
    在这里插入图片描述
    然后设置 setup->slave definition 从机ID、设置为保存寄存器,10条
    在这里插入图片描述
    同时我们也给寄存器设置一些值
    在这里插入图片描述
    开发板运行测试程序后,成功读取modbus从机寄存器值
    在这里插入图片描述

    展开全文
  • 编译测试代码Linux平台下libmodbus使用ARM平台下libmodbus使用libmodbus 从机地址限制的问题 这篇文章是接上一篇Modbus协议简介,介绍Modbus实际项目应用,断断续续写了近两周时间。 为什么要使用驱动库? 上一篇...

    这篇文章是接上一篇Modbus协议简介,介绍Modbus实际项目应用,断断续续写了近两周时间。

    为什么要使用驱动库?

    上一篇文章,我们介绍了Modbus协议物理层和协议层,我们知道了Modbus是一种总线协议,它可以基于串口或网口,以基于串口的Modbus-RTU为例,我们需要在Windows或Linux下实现一个上位机,上位机的功能是读写Modbus接口传感器设备的数据,或者是和单片机等从设备进行交互。

    当需要向某个从机寄存器写入某个值时,如向01地址的设备,0x0105保持寄存器写入1个数据:0x0190为例,那么需要构建这样一个数据帧:

    主机发送: 01 06 01 05 01 90 99 CB

    01表示从机地址,06功能码表示写单个保持寄存器,0105表示寄存器地址,0190表示写入寄存器的数值,99 CB为CRC校验值。

    如果从机正确的收到了数据,会回复一个数据帧:

    从机回复: 01 06 01 05 01 90 99 CB

    所以作为主机,写数据的流程是:

    1. 构建一个Modbus-RTU数据帧

    2. 等待从机响应的数据

    3. 如果响应数据正确,说明写入成功,否则写入失败。

    读数据也是同样的流程,我们可以基于串口发送、串口接收函数、定时器等,自己写一个Modbus驱动库,来实现对从设备的读写。当然,也可以直接使用别人写好的Modbus驱动库,比如libmodbus,本文将介绍如何使用libmodbus驱动库,实现Modbus主机和从机。

    libmodbus简介

    libmodbus,是一个基于C语言实现的Modbus驱动库,作者是Stephane,支持Linux, Mac OS X, FreeBSD, QNX and Win32操作系统,主要应用在PC上,用来开发上位机,也可以对源代码进行交叉编译,以适配更多的平台,比如ARM Linux。源代码开源,遵循 LGPL-2.1 许可。目前最新版本是3.1.6,Github仓库最新提交时间是2021年5月21日。

    官方网站:https://libmodbus.org/

    开源地址:https://github.com/stephane/libmodbus/

    GitHub仓库

    libmodbus支持如下功能:

    • 支持Modbus-RTU和Modbus-TCP
    • 支持常用功能码,如01/02/03/04/05/06/07/0F/10/11/16/17
    • 支持线圈类型读写、寄存器读写、离散量读取等
    • 支持广播地址0,从机地址1-247
    • 支持浮点数和整形数据转换,大端小端等多种模式
    • 参数根据Modbus_Application_Protocol_V1_1b.pdf官方标准文档设计,比如最大读写线圈个数,最大读写寄存器个数等。
    • 源代码基于C编写,方便在各平台移植,只有11个文件。

    libmodbus常用函数

    libmodbus库函数非常简洁,读写操作函数对于RTU和TCP完全通用,RTU和TCP切换只需要修改一行代码就可以实现无缝切换。

    
    modbus_t *mb;
    int ret;
    //创建一个modbus-rtu对象,指定串口号,波特率,校验位,数据位,停止位
    //成功返回指针,否则返回NULL, 会调用malloc申请内存
    mb = modbus_new_rtu("/dev/ttySP1", 115200, 'N', 8, 1);	//linux
    mb = modbus_new_rtu("COM1", 115200, 'N', 8, 1);		//windows
    //创建modbus-tcp对象,指定IP地址和端口号
    mb = modbus_new_tcp("127.0.0.1", 502);	//TCP/IP
    
    //设置从机地址,成功返回0, 否则返回-1
    ret = modbus_set_slave(mb, slave);
    
    //连接Modbus主机,成功返回0, 否则返回-1
    ret = modbus_connect(mb);
    
    //设置响应超时时间1s,200ms
    ret = modbus_set_response_timeout(mb, 1, 200000);
    
    //读取寄存器数据,起始地址2, 数量5, 保存到table数组中
    //成功返回5, 否则返回-1
    uint16_t *table;
    ret = modbus_read_registers(mb, 2, 5, table);
    
    //modbus设备关闭和释放内存
    modbus_close(mb);
    modbus_free(mb);
    
    //写单个寄存器, 地址2写入56, 成功返回1,否则返回-1
    ret = modbus_write_register(mb, 2, 56);
    
    //写多个寄存器, 地址12起始,写入5个数据,成功返回5,否则返回-1
    uint16_t table[5] = {11, 22, 33, 44, 55};
    ret = modbus_write_registers(mb, 12, 5, table);
    
    //写单个线圈,线圈地址写入TRUE,成功返回1,否则返回-1
    ret = modbus_write_bit(mb, 11, TRUE);
    
    //查看错误信息
    char *err_str;
    err_str = modbus_strerror(errno);
    
    

    Windows平台libmodbus 使用

    以Windows下使用libmodbus实现从机和主机为例,Linux下类似。

    1.获取源代码

    使用Git工具下载GitHub代码仓库源代码到本地,这样可以获取到最新的libmodbus代码,但是也会有一些Bug。

    git clone https://github.com/stephane/libmodbus/

    如果下载速度缓慢,可以到我的Gitee仓库下载:

    git clone https://gitee.com/whik/libmodbus

    或者到官方仓库下载最新稳定发布版本v3.1.6:

    https://libmodbus.org/releases/libmodbus-3.1.6.tar.gz

    下载完成之后,解压到本地,Linux系统可以使用tar -zxvf libmodbus-3.0.6.tar.gz命令行解压:

    源代码

    我们重点关注以下3个文件夹:doc,src,tests。

    • doc,doc文件夹包含库的使用文档,文件名就是函数名,介绍每个函数的使用方法,参数定制,返回值说明,示例代码等。

    帮助文档

    • src,src文件夹是libmodbus库源文件和头文件,我们只需要把这些文件添加到工程中,然后包含头文件就可以直接使用了。

    源代码

    • tests,tests文件夹包含libmodbus使用示例,

    测试代码

    包括Modbus-RTU/TCP客户端和服务器单元测试,随机测试,效率测试,读写10万个线圈状态,10万个寄存器,记录消耗时间。

    //部分代码
    nb_points = MODBUS_MAX_READ_BITS;
    start = gettime_ms();
    for (i=0; i<n_loop; i++) {
        rc = modbus_read_bits(ctx, 0, nb_points, tab_bit);
        if (rc == -1) {
            fprintf(stderr, "%s\n", modbus_strerror(errno));
            return -1;
        }
    }
    end = gettime_ms();
    elapsed = end - start;
    

    官方提供的测试代码太繁琐,后面我们会写两个简单的示例程序,来演示主机和从机的使用。

    2.生成config.h配置文件

    无论是Windows还是Linux,在使用libmodbus库之前,我们需要先调用configure工具来生成config.h文件和Makefile。configure工具会根据当前系统环境,生成适用于当前平台的config.h文件。

    在libmodbus库文件夹下执行./configure命令。

    
    whik@windows_7 MINGW64 /d/libmodbus-3.1.6
    $ ./configure
    checking for a BSD-compatible install... /usr/bin/install -c
    checking whether build environment is sane... yes
    checking for strings.h... yes
        .......
    checking for inttypes.h... yes
    config.status: creating tests/unit-test.h
    config.status: executing libtool commands
    
        libmodbus 3.1.6
        ===============
    
        prefix:                 /usr/local
        sysconfdir:             ${prefix}/etc
        libdir:                 ${exec_prefix}/lib
        includedir:             ${prefix}/include
    
        compiler:               gcc
        cflags:                 -g -O2
        ldflags:
    
        documentation:          no
        tests:                  yes
    

    整个过程需要1分钟左右的时间,等待运行完成之后,会发现在当前目录下多了一些文件,主要是config.hMakefile

    如果想使用libmodbus官方提供的测试代码,可以直接在根目录执行make命令,就可以直接编译tests目录下的测试代码,Linux系统可以使用make install命令进行和安装。

    3.编写测试代码

    新建一个文件夹my_test,把libmodbus/src文件夹中的.c和.h文件,config.h复制到my_test。

    学习了libmodbus常用函数之后,我们就可以写一个简单的测试代码了。

    Modbus-RTU主机测试:test_rtu_master.c,实现对地址为1的从机设备,读取地址15/16/17的保持寄存器数据,进行+1操作后,再写入。

    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    
    #include "modbus.h"
    
    #define PORT_NAME "COM1"
    
    int main(int argc, char *argv[])
    {
        int ret;
        uint16_t table[3];
        modbus_t *mb;
        char port[20];
        printf("argc = %d, argv[1] = %s\n", argc, argv[1]);
        if(argc == 2)
            strcpy(port, argv[1]);
        else 
            strcpy(port, PORT_NAME);
        printf("libmodbus modbu-rtu master demo: %s, 115200, N, 8, 1\n", port);
    
        mb = modbus_new_rtu(port, 115200, 'N', 8, 1);
    
        if (mb == NULL)
        {
            modbus_free(mb);
            printf("new rtu failed: %s\n", modbus_strerror(errno));
            return 0;
        }
    
        modbus_set_slave(mb, 1);
        ret = modbus_connect(mb);
        
        if(ret == -1)
        {
            modbus_close(mb);
            modbus_free(mb);
            printf("connect failed: %s\n", modbus_strerror(errno));
            return 0;
        }
        while(1)
        {
            ret = modbus_read_registers(mb, 0x0F, 3, table);
            if(ret == 3)
                printf("read success : 0x%02x 0x%02x 0x%02x \n", table[0], table[1], table[2]);
            else
            {
                printf("read error: %s\n", modbus_strerror(errno));
                break;
            }
    
            for(int i = 0; i < 3; i++)
                table[i] += 1;
    
            ret = modbus_write_registers(mb, 0x0F, 3, table);
            if(ret == 3)
                printf("write success: 0x%02x 0x%02x 0x%02x \n", table[0], table[1], table[2]);
            else
            {
                printf("write error: %s\n", modbus_strerror(errno));
                break;
            }
            Sleep(1000);
        }
    
        modbus_close(mb);
        modbus_free(mb);
        system("pause");
        return 0;
    }
    
    

    Modbus-RTU从机测试:test_rtu_slave.c,创建从机设备,地址为1,初始化了3个保持寄存器,地址分别为15/16/17,数据分别为0x1001/0x1002/0x1003。

    #include "stdio.h"
    #include "stdlib.h"
    #include "string.h"
    
    #include "modbus.h"
    
    #define PORT_NAME "COM2"
    
    int main(int argc, char *argv[])
    {
        int ret = 0;
        uint8_t device = 1;
        uint8_t *query;
        modbus_t *mb;
        modbus_mapping_t *mb_mapping;
        char port[20];
        printf("argc = %d, argv[1] = %s\n", argc, argv[1]);
        if(argc == 2)
            strcpy(port, argv[1]);
        else 
            strcpy(port, PORT_NAME);
        
        printf("libmodbus modbu-rtu slave demo: %s, 115200, N, 8, 1\n", port);
        
        mb = modbus_new_rtu(port, 115200, 'N', 8, 1);
    
        if (mb == NULL)
        {
            modbus_free(mb);
            printf("new rtu failed: %s\n", modbus_strerror(errno));
            return 0;
        }
    
        //register: 15/16/17
        mb_mapping = modbus_mapping_new_start_address(0, 0, 0, 0, 15, 3, 0, 0);
        if(mb_mapping == NULL)
        {
            modbus_free(mb);
            printf("new mapping failed: %s\n", modbus_strerror(errno));
            return 0;
        }
        
        //保持寄存器数据
        mb_mapping->tab_registers[0] = 0x1001;
        mb_mapping->tab_registers[1] = 0x1002;
        mb_mapping->tab_registers[2] = 0x1003;
    
        modbus_set_slave(mb, device);
        ret = modbus_connect(mb);
        
        if(ret == -1)
        {
            modbus_free(mb);
            printf("connect failed: %s\n", modbus_strerror(errno));
            return 0;
        }
        printf("create modbus slave success\n");
        while(1)
        {
            do {
                ret = modbus_receive(mb, query);    //轮询串口数据,
            } while (ret == 0);
    
            if(ret > 0) //接收到的报文长度
            {
                printf("len=%02d: ", ret);
                for(int idx = 0; idx < ret; idx++)
                {
                    printf(" %02x", query[idx]);
                }
                printf("\n");
    
                modbus_reply(mb, query, ret, mb_mapping);
            }
            else
            {
                printf("quit the loop: %s", modbus_strerror(errno));
                modbus_mapping_free(mb_mapping);
                break;
            }
        }
    
        modbus_close(mb);
        modbus_free(mb);
        return 0;
    }
    

    4.编译测试代码

    现学了Makefile语法,凑合用。需要注意的是,windows下libmodbus依赖于ws2_32.dll库,需要添加编译参数-lws2_32:

    .PHONY: all
    
    all: test_rtu_master test_rtu_slave
    test_rtu_master : test_rtu_master.o modbus.o modbus-tcp.o modbus-rtu.o modbus-data.o 
    	gcc test_rtu_master.o modbus.o modbus-tcp.o modbus-rtu.o modbus-data.o -o test_rtu_master -lws2_32
    test_rtu_slave : test_rtu_slave.o modbus.o modbus-tcp.o modbus-rtu.o modbus-data.o 
    	gcc test_rtu_slave.o modbus.o modbus-tcp.o modbus-rtu.o modbus-data.o -o test_rtu_slave -lws2_32
    
    test_rtu_slave.o : test_rtu_slave.c
    	gcc test_rtu_slave.c -c -I.
    test_rtu_master.o : test_rtu_master.c
    	gcc test_rtu_master.c -c -I.
    modbus.o : modbus.c
    	gcc modbus.c -c -I.
    modbus-rtu.o : modbus-rtu.c
    	gcc modbus-rtu.c -c -I.
    modbus-tcp.o : modbus-tcp.c
    	gcc modbus-tcp.c -c -I.
    modbus-data.o : modbus-data.c
    	gcc modbus-data.c -c -I.
    
    clean:
    	rm -rf *.o *.exe
    

    最终的文件目录:

    测试文件

    Windows下Make工具我使用的是Qt自带的mingw32-make.exe工具,位于\Qt5.7.0\Tools\mingw530_32\bin目录下,执行mingw32-make命令进行,会对两个测试文件进行编译:

    whik@Windows_7 MINGW64 /d/my_test
    $ mingw32-make.exe
    gcc test_rtu_master.c -c -I.
    gcc modbus.c -c -I.
    gcc modbus-tcp.c -c -I.
    gcc modbus-rtu.c -c -I.
    gcc modbus-data.c -c -I.
    In file included from modbus-data.c:24:0:
    ./config.h:171:0: warning: "WINVER" redefined
     #define WINVER 0x0501
     ^
    In file included from D:/Program/Qt5.7.0/Tools/mingw530_32/i686-w64-mingw32/include/windows.h:10:0,
                     from D:/Program/Qt5.7.0/Tools/mingw530_32/i686-w64-mingw32/include/winsock2.h:23,
                     from modbus-data.c:19:
    D:/Program/Qt5.7.0/Tools/mingw530_32/i686-w64-mingw32/include/sdkddkver.h:162:0: note: this is the location of the previous definition
     #define WINVER  _WIN32_WINNT
     ^
    gcc test_rtu_master.o modbus.o modbus-tcp.o modbus-rtu.o modbus-data.o -o test_rtu_master -lws2_32
    gcc test_rtu_slave.c -c -I.
    gcc test_rtu_slave.o modbus.o modbus-tcp.o modbus-rtu.o modbus-data.o -o test_rtu_slave -lws2_32
    

    会在当前目录下生成目标文件:test_rtu_master.exetest_rtu_slave.exe

    这里,我的电脑本机虚拟了两个串口COM1和COM2,两个串口直接进行连接。

    先启动从机设备,配置为COM1:

    $ ./test_rtu_slave.exe "COM1"
    

    再启动主机设备,配置为COM2:

    $ ./test_rtu_master.exe "COM2"
    

    测试结果

    可以看到,从机可以正确的对接收的数据帧进行相应,主机可以正确的进行读取和写入。

    如果需要测试Modbus-TCP,只需要修改modbus设备创建函数:

    //modbus-rtu
    mb = modbus_new_rtu(port, 115200, 'N', 8, 1);
    
    //modbus-tcp
    mb = modbus_new_tcp("127.0.0.120", 502);	//指定IP地址
    

    其他无需任何改动!

    Linux平台下libmodbus使用

    Ubuntu下使用libmodbus和Windows几乎一样:

    //1.解压
    tar -zxvf libmodbus-3.0.6.tar.gz
        
    //2.配置
    ./configure
        
    //3.编译
    make
        
    //4.安装
    make install
    

    测试文件和Windows几乎一样,不过不需要ws2_32库的支持了。

    (来自:blog.csdn.net/qq_30650153/article/details/83385626

    ARM平台下libmodbus使用

    ARM开发板下使用libmodbus,需要使用交叉编译器进行交叉编译,生成so库文件。

    1.解压:

    tar -zxvf libmodbus-3.0.6.tar.gz

    2.创建安装目录:

    mkdir install
    

    3.配置编译选项:

    ./configure --host=arm-fsl-linux-gnueabi --enable-static --prefix=[安装路径]/install/
    

    4.编译:make

    5.安装:make install

    在install目录会生成3个文件夹:include lib share

    进入install/lib目录,执行file libmodbus*,出现如下打印信息,信息中有“ARM”说明libmodbus库移植成功。

    libmodbus.a:        current ar archive
    libmodbus.la:       libtool library file, 
    libmodbus.so:       symbolic link to `libmodbus.so.5.0.5'
    libmodbus.so.5:     symbolic link to `libmodbus.so.5.0.5'
    libmodbus.so.5.0.5: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, not stripped
    

    libmodbus.so、libmodbus.so.5、libmodbus.so.5.0.5复制到ARM开发板中的/usr/lib目录下

    执行cp libmodbus.so* /usr/lib

    如果出现无法创建的问题(cannot create ‘/usr/lib/libmodbus.so*’: Read-only file system)。

    可以执行 wr cp libmodbus* /usr/lib

    测试与使用,和Windows一样,对测试文件使用ARM交叉编译器进行编译。

    (来自:www.cnblogs.com/happybirthdaytoyou/p/11301612.html)

    libmodbus 从机地址限制的问题

    libmodbus支持1-247从机地址,0为广播地址,但是有些非标准的Modbus传感器,并不是采用0作为广播地址,而是0xfe作为广播地址:

    广播地址0xfe

    所以使用libmodbus会出现报错终止运行的问题,这是因为libmodbus源代码中限制了从机地址1-247,我们只需要修改源代码即可。

    modbus-rtu.c文件95行:

    modbus-rtu

    modbus-tcp.c文件80行:

    modbus-tcp

    只需要修改这两个数值就可以取消从机地址限制的问题。

    详细的从站最大地址限制问题排查记录,可以查看:

    https://blog.csdn.net/qingzhuyuxian/article/details/80391553

    其实这个问题,早在2011年,就有人在官方GitHub仓库提Issues了:

    https://github.com/stephane/libmodbus/issues/38

    issue

    对此问题,作者的答复是,为了遵循Modbus官方标准,所以一直以来都没有进行修改。

    展开全文
  • qt使用libmodbus

    2020-11-09 11:34:42
    一个客户端和一个服务器,但是没有解决断开重连的问题。数据的输入还有一些bug。但是整体的框架是没有问题的。
  • Qt使用libmodbus

    2020-11-09 11:28:30
    Qt使用libmodbus 链接: modbus下载地址. 下载后在src目录中提取所有.c.h文件,放到一个文件夹中。为了方便使用,我把这些文件放到了一个名叫modbus的文件夹中,文件夹中新建一个文本文档,里边保存以下内容 win32:...

    Qt使用libmodbus

    链接: modbus下载地址.

    下载后在src目录中提取所有.c.h文件,放到一个文件夹中。为了方便使用,我把这些文件放到了一个名叫modbus的文件夹中,文件夹中新建一个文本文档,里边保存以下内容

    win32:LIBS += -lws2_32
    
    HEADERS += \
        $$PWD/modbus-private.h \
        $$PWD/modbus-rtu-private.h \
        $$PWD/modbus-rtu.h \
        $$PWD/modbus-tcp-private.h \
        $$PWD/modbus-tcp.h \
        $$PWD/modbus-version.h \
        $$PWD/modbus.h
    
    SOURCES += \
        $$PWD/modbus-data.c \
        $$PWD/modbus-rtu.c \
        $$PWD/modbus-tcp.c \
        $$PWD/modbus.c
    
    
    

    保存后重命名为 : modbus.pri
    在这里插入图片描述
    新建qt项目后,把这个文件夹复制到项目的代码目录中。
    在这里插入图片描述
    在pro文件末尾加上:include(modbus/modbus.pri)
    这样qt项目中就可以使用libmodbus了。

    一个我写的modbus_tcp客户端服务器建立连接的程序
    只有基本功能,重连服务器时会有问题,暂时解决不掉。。。

    展开全文
  • libmodbus

    2021-03-16 07:49:32
    libmodbus1 简介2 库使用2.1 直接加入工程中3 函数接口流程参考 1 简介 A Modbus library for Linux, Mac OS X, FreeBSD, QNX and Win32. libmodbus is a free software library to send/receive data according to...
  • ubuntu下使用libmodbus

    2021-03-24 14:48:10
    ubuntu下使用libmodbus u013074298 2019-01-21 20:29:16 1820 收藏 9 文章标签: modbus 版权 参照:非常感谢原文作者 https://blog.csdn.net/qq_30650153/article/details/83385626 ...
  • libmodbus编译安装使用

    千次阅读 2018-09-13 19:45:56
    【编译】  ./configure --host=arm-fsl-linux-gnueabi --enable-static --..../configure --host=arm-linux --prefix=/opt/libmodbus/install # make # make install 其中--prefix为输出目录, 编译中如遇到...
  • libmodbus--使用记录

    2021-08-13 11:08:43
    2、基本使用顺序 (1)初始化指针; (2)建立连接; (3)设置从站ID; (4)读取保持寄存器/读取输入寄存器/读取位; (5)写单寄存器/写多寄存器/写多位数据; (6)关闭连接; 3、RTU模式 (1)初始化RTU指针—...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 571
精华内容 228
关键字:

libmodbus使用