编译libmodbus库及使用

1.下载源码

cd ~

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

2.设置编译环境:

打开“~/.bashrc"文件,在最后行添加,以便导入编译器常用的环境变量

export KERNELDIR=/home/dengxm2024/linuxProgDir/linuxkerneldir/linux-2.6.35.3
export CROSS_COMPILE=arm-fsl-linux-gnueabi-
export ARCH=arm
export PATH=/opt/arm-fsl-linux-gnueabi/bin:$PATH
export LD_LIBRARY_PATH=/opt/arm-fsl-linux-gnueabi/lib:$LD_LIBRARY_PATH
export CC=arm-fsl-linux-gnueabi-gcc
export CXX=arm-fsl-linux-gnueabi-g++
export AR=arm-fsl-linux-gnueabi-ar
export RANLIB=arm-fsl-linux-gnueabi-ranlib
export NM=arm-fsl-linux-gnueabi-nm
export LD=arm-fsl-linux-gnueabi-ld
export STRIP=arm-fsl-linux-gnueabi-strip

2.编译源码:

进入源码文件夹:

cd libmodbus

运行automake  autoconfgure脚本来生成Makefile文件:

./configure --host=arm-fsl-linux-gnueabi --enable-static --prefix=/home/dengxm2024/libmodbus_install/

--host=arm-fsl-linux-gnueabi   指定交叉编译器的前缀

--enable-static  静态编译

prefix=/home/dengxm2024/libmodbus_install/  指定库编译完成后的编译结果存放的路径

运行CMAKE编译命令:

make

安装生成的库:

make install

做完上述步骤可以看见在"~/libmodbus_install"生成了头文件及库文件

dengxm2024@PC-202105142413:~/libmodbus_install$ ls
include  lib  share

3.使用上面输出的库

新建文件/home/dengxm2024/linuxProgDir/imx280astudy/userside_code/libmodbustest/version.c

/*
 * Copyright © 2008-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include <modbus/modbus-version.h>
#include <modbus/modbus.h>

int main(void)
{
    printf("Compiled with libmodbus version %s (%06X)\n", LIBMODBUS_VERSION_STRING, LIBMODBUS_VERSION_HEX);
    printf("Linked with libmodbus version %d.%d.%d\n",
           LIBMODBUS_VERSION_MAJOR, LIBMODBUS_VERSION_MINOR, LIBMODBUS_VERSION_MICRO);

    if (LIBMODBUS_VERSION_CHECK(2, 1, 0)) {
        printf("The functions to read/write float values are available (2.1.0).\n");
    }

    if (LIBMODBUS_VERSION_CHECK(2, 1, 1)) {
        printf("Oh gosh, brand new API (2.1.1)!\n");
    }

    return 0;
}

.新建/home/dengxm2024/linuxProgDir/imx280astudy/userside_code/libmodbustest/Makefile

# 定义libmodbus库头文件的路径
HEADERS_DIR := /home/dengxm2024/linuxProgDir/imx280astudy/userside_code/libmodbustest/libmodbus_install/include

# 添加头文件路径到编译器的搜索路径中
CFLAGS += -I$(HEADERS_DIR)

EXEC = ./version 
OBJS = version.o
SRC  = version.c
# 指定编译器前缀
CC = $(CROSS_COMPILE)gcc

LDFLAGS += 

all:$(EXEC)

$(EXEC):$(OBJS)
	$(CC) $(LDFLAGS) -o $@ $(OBJS) -pthread

%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@ -pthread

clean:
	@rm -vf $(EXEC) *.o *~

把库文件夹~/libmodbus_install复制到项目文件夹

cp -r ~/libmodbus_install/ ~/linuxProgDir/imx280astudy/userside_code/libmodbustest

项目结构如下:

在终端窗口的项目文件夹中执行make

编译成功,生成version可执行文件。

4.测试运行

将执行文件复制到开发板当中测试运行。

复制version到web服务器

cp version /mnt/d/imx280a_exe_folder/

打开开发板终端窗口,从web服务器获取version文件

wget http://192.168.0.233:443/imx280a_exe_folder/version

给version添加可执行属性

chmod +x version

执行version查看结果

./version

root@EasyARM-iMX28x ~# ./version
Compiled with libmodbus version 3.1.4 (030104)
Linked with libmodbus version 3.1.4
The functions to read/write float values are available (2.1.0).
Oh gosh, brand new API (2.1.1)!

至此,使用libmodbus库进行开发的初步步骤就完成了。

测试modbus主站代码:

/home/dengxm2024/linuxProgDir/imx280astudy/userside_code/libmodbustest/modbustcpclient.c

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
 
 
#include <modbus/modbus.h>
#include <modbus/modbus-tcp.h>
 
#define LOOP          1
#define SERVER_ID     17
#define ADDRESS_START 0
#define ADDRESS_END   9
 
 
int main(void)
{
    modbus_t *ctx;
    int rc;
    int nb_fail;
    int nb_loop;
    int addr;
    int nb;
    uint8_t *tab_bits;
    uint8_t *tab_in_bits;
    uint16_t *tab_registers;
    uint16_t *tab_in_registers;
 
 
    ctx = modbus_new_tcp("192.168.0.233", 502);
    modbus_set_slave(ctx, SERVER_ID);
    modbus_set_debug(ctx, TRUE);
 
 
    if (modbus_connect(ctx) == -1) 
    {
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
 
 
    /* Allocate and initialize the different memory spaces */
    nb = ADDRESS_END - ADDRESS_START;
 
 
    tab_bits = (uint8_t *) malloc(nb * sizeof(uint8_t));
    memset(tab_bits, 0, nb * sizeof(uint8_t));
 
 
    tab_in_bits = (uint8_t *) malloc(nb * sizeof(uint8_t));
    memset(tab_in_bits, 0, nb * sizeof(uint8_t));
 
 
    tab_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
    memset(tab_registers, 0, nb * sizeof(uint16_t));
 
 
    tab_in_registers = (uint16_t *) malloc(nb * sizeof(uint16_t));
    memset(tab_in_registers, 0, nb * sizeof(uint16_t));
 
 
 
 
    nb_loop = nb_fail = 0;
    while (nb_loop++ < LOOP) 
    {
        for (addr = ADDRESS_START; addr < ADDRESS_END; addr++) 
        {
            int i;
 
 
            nb = ADDRESS_END - addr;
 
 
            /* read BIT */
            
            rc = modbus_read_bits(ctx, addr, 1, tab_bits);
            if (rc != 1 ) 
            {
                printf("ERROR modbus_read_bits single (%d)\n", rc);
                printf("address = %d\n", addr);
                nb_fail++;
            }
            else
            {
                printf("Address = %d, value %d (0x%X) \n",
                                   addr,
                                   tab_bits[0],
                                   tab_bits[0]);
            }
            
 
 
            /* MULTIPLE BITS */
            
            rc = modbus_read_bits(ctx, addr, nb, tab_bits);
            if (rc != nb) 
            {
                printf("ERROR modbus_read_bits\n");
                printf("Address = %d, nb = %d\n", addr, nb);
                nb_fail++;
            } 
            else 
            {
                for (i = 0; i < nb; i++) 
                {
                    
                        printf("Address = %d, value %d (0x%X) \n",
                                addr+i,
                                tab_bits[i],
                                tab_bits[i]);
 
 
                }
            }
 
 
            //read input bits
            //modbus_read_input_bits
            
 
 
            /* SINGLE REGISTER */
            rc = modbus_read_registers(ctx, addr, 1, tab_registers);
            if (rc != 1) 
            {
                printf("ERROR modbus_read_registers single (%d)\n", rc);
                printf("Address = %d\n", addr);
                nb_fail++;
            } 
            else 
            {
                    printf("Address = %d, value = %d (0x%X) \n",
                            addr,
                            tab_registers[0],
                            tab_registers[0]);
            }
            
 
 
            /* MULTIPLE REGISTERS */
            
            rc = modbus_read_registers(ctx, addr, nb, tab_registers);
            if (rc != nb) 
            {
                printf("ERROR modbus_read_registers (%d)\n", rc);
                printf("Address = %d, nb = %d\n", addr, nb);
                nb_fail++;
            } 
            else 
            {
                for ( i = 0; i < nb; i++) 
                {
                        printf("Address = %d, value %d (0x%X) \n",
                                addr+i,
                                tab_registers[i],
                                tab_registers[i]);
 
 
                }
            }
            // read intput registers
            //modbus_read_input_registers
 
 
            sleep(5);
        }
 
 
        printf("Test: ");
        if (nb_fail)
            printf("%d FAILS\n", nb_fail);
        else
            printf("SUCCESS\n");
    }
 
 
    /* Free the memory */
    free(tab_bits);
    free(tab_in_bits);
    free(tab_registers);
    free(tab_in_registers);
 
 
    /* Close the connection */
    modbus_close(ctx);
    modbus_free(ctx);
 
 
    return 0;
}

上面的Makefile要修改一下了:

# 定义libmodbus库头文件的路径
HEADERS_DIR := /home/dengxm2024/linuxProgDir/imx280astudy/userside_code/libmodbustest/libmodbus_install/include

# 添加头文件路径到编译器的搜索路径中
CFLAGS += -I$(HEADERS_DIR)


#指定libmodbus库路径及库名称
LDFLAGS += -L$(CURDIR)/libmodbus_install/lib -lmodbus
#LDFLAGS += -L/home/dengxm2024/linuxProgDir/imx280astudy/userside_code/libmodbustest/libmodbus_install/lib -lmodbus
#显式链接库
#LDFLAGS += -lmodbus
EXEC = ./modbustcpclient
OBJS = modbustcpclient.o
SRC  = modbustcpclient.c
# 指定编译器前缀
CC = $(CROSS_COMPILE)gcc

LDFLAGS += 

all:$(EXEC)

$(EXEC):$(OBJS)
	$(CC) $(LDFLAGS) -o $@ $(OBJS) -pthread

%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@ -pthread

clean:
	@rm -vf $(EXEC) *.o *~

#指定libmodbus库路径及库名称
LDFLAGS += -L$(CURDIR)/libmodbus_install/lib -lmodbus

这步很重要。

$(CURDIR)是Makefile文件所在路径。

在使用 GCC(GNU Compiler Collection)或类似的编译器进行链接时,-l 选项用于指定要链接的库。具体来说,-lmodbus 告诉链接器要链接名为 libmodbus 的库。

当你使用 -l 选项时,编译器会查找一个名为 lib[库名].a 的静态库或 lib[库名].so 的共享库(取决于你的系统配置和库的类型)。在你给出的例子中,-lmodbus 将查找 libmodbus.alibmodbus.so

-l 后跟的参数通常是没有前导 lib 和后缀 .a.so 的库名。例如,-lmodbus 实际上指向的是 libmodbus.alibmodbus.so

此外,-L 选项用于指定链接器搜索库的附加目录。在你的例子中,-L/path/to/libmodbus/lib 告诉链接器在 /path/to/libmodbus/lib 目录下查找库文件。如果省略 -L 选项,链接器将只在标准系统库目录中搜索。

因此,arm-linux-gnueabihf-gcc -o myapp myapp.c -L/path/to/libmodbus/lib -lmodbus 这条命令的意思是:

  • 使用 arm-linux-gnueabihf-gcc 编译器(一个针对 ARM 架构的交叉编译器)。
  • 将 myapp.c 源文件编译并链接成一个可执行文件,输出文件名为 myapp
  • 在链接阶段,链接器会额外搜索 /path/to/libmodbus/lib 目录。
  • 链接名为 modbus 的库(即 libmodbus.a 或 libmodbus.so)。

确保 -L-l 选项正确使用,是确保程序可以正确链接到所需库的关键。如果链接器找不到指定的库,你将收到类似 "undefined reference" 的链接错误。

编译测试:

modbus模拟器:

把编译结果复制到开发板上面:

libmodbus.a         libmodbus.so        libmodbus.so.5.1.0
libmodbus.la        libmodbus.so.5      pkgconfig

把库文件的动态链接库复制到开发板/usr/lib里面,运行时需要调用

root@EasyARM-iMX28x ~# ./modbustcpclient 
Connecting to 192.168.0.233:502
[00][01][00][00][00][06][11][01][00][00][00][01]
Waiting for a confirmation...
<00><01><00><00><00><04><11><01><01><01>
Address = 0, value 1 (0x1) 
[00][02][00][00][00][06][11][01][00][00][00][09]
Waiting for a confirmation...
<00><02><00><00><00><05><11><01><02><DF><01>
Address = 0, value 1 (0x1) 
Address = 1, value 1 (0x1) 
Address = 2, value 1 (0x1) 
Address = 3, value 1 (0x1) 
Address = 4, value 1 (0x1) 
Address = 5, value 0 (0x0) 
Address = 6, value 1 (0x1) 
Address = 7, value 1 (0x1) 
Address = 8, value 1 (0x1) 

已经通讯上了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值