zoukankan      html  css  js  c++  java
  • freemodbus移植、实例及其测试方法

    Modbus简介

    参考:Modbus​协议​深入​讲解 https://www.ni.com/zh-cn/innovations/white-papers/14/the-modbus-protocol-in-depth.html

    http://www.sohu.com/a/230628953_315598

    官方文档:http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf

    Modbus协议包括ASCII、RTU、TCP等,并没有规定物理层。此协议定义了控制器能够认识和使用的消息结构,而不管它们是经过何种网络进行通信的。标准的Modicon控制器使用RS232C实现串行的Modbus。Modbus的ASCII、RTU协议规定了消息、数据的结构、命令和就答的方式,数据通讯采用Maser/Slave方式,Master端发出数据请求消息,Slave端接收到正确消息后就可以发送数据到Master端以响应请求;Master端也可以直接发消息修改Slave端的数据,实现双向读写。

    其通信协议理解也比较简单,其帧结构如下

    地址码 + 功能码 + 数据区 + 错误校验

    常用功能码

    最常使用的读写功能码如下;

    01   读取单个/多个线圈状态(类似DO:数字输出)

    02   读取单个/多个离散输入(类似DI:数字输入)

    03   读取单个/多个保存寄存器

    04   读取单个/多个输入寄存器(类似AI:模拟输入)

    05   写单个线圈状态

    06   写单个保存寄存器

    15   写多个线圈

    16   写多个保存寄存器

    FreeModbus简析

    FreeMODBUS 提供了RTU/ASCII 传输模式及TCP协议支持。

    FreeModbus协议对硬件的需求非常少——基本上任何具有串行接口,并且有一些能够容纳modbus数据帧的RAM的微控制器都足够了。 

    现支持如下功能码:

    • Read Input Register (0x04)
    • Read Holding Registers (0x03)
    • Write Single Register (0x06)
    • Write Multiple Registers (0x10)
    • Read/Write Multiple Registers (0x17)
    • Read Coils (0x01)
    • Write Single Coil (0x05)
    • Write Multiple Coils (0x0F)
    • Read Discrete Inputs (0x02)
    • Report Slave ID (0x11)

    FreeModbus源码解析

    参考:https://blog.csdn.net/u014748120/article/details/80313215

    待续。。。 

    Modbus通信实现

    本文测试主机为 arm-linux,可以使用 libmodbus 静态库实现modbus通信,为追求可移植性,本文主要使用 freemodbus 来实现。

    1. libmodbus使用

    ubuntu系统使用libmodbus可以使用以下命令安装

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

    使用文档参考:https://libmodbus.org/documentation/

    库参考手册:https://libmodbus.org/docs/v3.1.4/

    移植到arm的话则需下载源码进行交叉编译  http://libmodbus.org/releases/libmodbus-3.1.4.tar.gz

    解压安装

    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

    在我的应用程序工程里面新建一个 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
    ");
            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
    ", modbus_strerror(errno));
            return -1;
        }
    
        int i,rc;
        uint16_t tab_reg[64] = {0}; //定义存放数据的数组
        while (1)
        {
            printf("
    ----------------
    ");
            //读取保持寄存器的值,可读取多个连续输入保持寄存器
            rc = modbus_read_registers(ctx, 0, 10, tab_reg);
            if (rc == -1)
            {
                fprintf(stderr,"%s
    ", modbus_strerror(errno));
                return -1;
            }
            for (i=0; i<10; i++)
            {
                printf("reg[%d] = %d(0x%x)
    ", i, tab_reg[i], tab_reg[i]);
            }
    
            usleep(5000000);
        }
        modbus_close(ctx);  //关闭modbus连接
        modbus_free(ctx);   //释放modbus资源,使用完libmodbus需要释放掉
    
        return 0;
    }

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

    modbus从机模拟

    Modbus slave测试工具可以用来做modbus从机设备,从而实现arm控制板通过串口与PC端模拟的modbus从机进行通信测试。

    Modbus slave下载地址:https://www.modbustools.com/download/ModbusSlaveSetup64Bit.exe

    然后设置 setup->slave definition   从机ID、设置为保存寄存器,10条

    同时我们也给寄存器设置一些值

    开发板运行测试程序后,成功读取modbus从机寄存器值

     2.freemodbus在linux上的使用

    待续。。。

  • 相关阅读:
    晨读,难道只是为了完成任务而读的吗?
    集合还有这么优雅的运算法?
    Java中的TreeSet集合会自动将元素升序排序
    CSS3的几个变形案例……
    “老师,请您多关注一下我吧!!!”
    jsp中使用cookie时报错……
    为什么要有周考?周考是用来干什么的?
    今天,我们就来抽个奖!
    今天 ,给大家变个魔术!!!
    Google Maps Api 多坐标分类标记,在地图上显示海量坐标,并分组显示。
  • 原文地址:https://www.cnblogs.com/silencehuan/p/11283084.html
Copyright © 2011-2022 走看看