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.a
或 libmodbus.so
。
-l
后跟的参数通常是没有前导 lib
和后缀 .a
或 .so
的库名。例如,-lmodbus
实际上指向的是 libmodbus.a
或 libmodbus.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)
已经通讯上了。