移植libmodbus到ARM开发板总结

(一)背景

        项目需要采集RTU设备(工业仪表)的数据,其中涉及Modbus协议及数据转换,因为之前没接触过这块内容,所以准备在Linux环境下移植libmodbus开源库到开发板,以节省开发时间成本。

(二)调试工具

        Modbus Poll、Modbus Slave、Configure Virtual Serial Port Driver(虚拟串口工具)。

        使用说明参见:ModbusPoll及ModbusSlave安装及使用指南_modbus poll 使用手册_唯变乃不变也的博客-CSDN博客

(三)移植步骤

        主要说明ARM开发板移植部分,这部分自己遇到的问题比较多,虚拟机中Linux移植部分参考比较多,自己主要参考了以下文档:【modbus】libmodbus库的移植与使用_libmodbus移植_郭老二的博客-CSDN博客          linux libmodbus的移植_深秋风瘦的博客-CSDN博客

1、在移植libmodbus到ARM开发板过程中,copy(编译好的、且适用于ARM平台的)动态库(lib*.so*)到/usr/lib目录时,执行cp libmodbus.so* /usr/lib(常用的动态链接库,存放在该目录下)会出现无法创建的问题(cannot create /usr/lib/libmodbus.so*: Read-only file system)。

        解决方法:执行 wr cp libmodbus* /usr/lib  (wr的作用不是太了解只是在一个技术群里面看到的

2、在使用libmodbus库时,只需要libmodbus.so、libmodbus.so.5、libmodbus.so.5.0.5这3个动态库文件,故只copy上述3个文件至ARM开发板的/usr/lib目录即可。

3、编译应用程序

(1)在虚拟机共享文件夹share下编辑应用程序modbus-rtu-test.c,在虚拟机Linux终端/mnt/hgfs/share目录copy至/home/liuxu/libmodbus/libmodbus-3.0.6/tests/目录;

        注:个人没有使用Samba服务器;libmodbus库下载、交叉编译、测试见上面链接。

(2)交叉编译,终端执行:arm-fsl-linux-gnueabi-gcc -o modbus-rtu-test modbus-rtu-test.c -L ../../install/lib/ -lmodbus -I ../../install/include/modbus/, 即可生成ARM平台支持的可执行文件modbus-tcp-test。(其中,在libmodbus目录下有install和libmodbus-3.0.6两个目录)

        注:可能出现arm-fsl-linux-gnueabi-gcc命令未找到的的问题,原因是安装交叉编译器时,环境变量设置的问题。

        解决方案:

        添加工具链路径。在虚拟机Linux终端执行:export PATH=$PATH:/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin/

        验证方法:终端执行echo $PATH, 查看PATH的值,如若看到/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin/ ,即可解决交叉编译命令找不到的问题。

(3)copy可执行文件至 /nfsroot 目录,再至ARM开发板 /mnt 目录,执行 ./modbus-tcp-test 即可运行应用程序。

        借助调试助手Modbus Slave测试结果如下图:

        

(四)测试程序

/*************************
**
** modbus-rtu-test.c 
** 移植libmodbus库到ZLG开发板,并测试成功
**
**************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <modbus.h> //modbus动态库文件

#include "unit-test.h"

int main(int argc, char *argv[])
{
	uint16_t tab_reg[64] = {0}; //定义存放数据的数组
    modbus_t *ctx = NULL;
 
    int rc;
	int i;
							        //以串口的方式创建libmobus实例,并设置参数
	ctx = modbus_new_rtu("/dev/ttySP1", 115200, 'N', 8, 1);					
	if (ctx == NULL)                //使用UART1,对应的设备描述符为ttySP1
	{
    	fprintf(stderr, "Unable to allocate libmodbus contex\n");
    	return -1;
	}
	
	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;
	}
	
	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(3000000);
	}
    modbus_close(ctx);  //关闭modbus连接
	modbus_free(ctx);   //释放modbus资源,使用完libmodbus需要释放掉

	return 0;
}

modbus tcp 测试代码

/*************************
**
** modbus-tcp
** 模拟modbus tcp client
**
**************************/
void *custom_modbus_tcp_client_task(void *arg)
{
    printf("custom_modbus_tcp_client_task!\n");

	int ret;
	int newOkFlag = 0;	
	int connectOkFlag = 0;
	int i;
	uint16 tab_reg[64]; //定义存放数据的数组
	modbus_t *ctx = NULL;

	while (1)
	{
		if (!newOkFlag)
		{
			//1.以tcp的方式创建libmobus实例,并设置ip和端口号
			ctx = modbus_new_tcp("127.0.0.1", 8080);	
			if (NULL == ctx)
			{
				printf("Unable to allocate libmodbus contex\n");
				sleep(5);
				continue;
			}
			newOkFlag = 1;
		}
		
		//2. 设置调试模式
		modbus_set_debug(ctx, 1);
		
		if (!connectOkFlag)
		{
			//3. 连接server
			if (-1 == modbus_connect(ctx))
			{
				printf("Connection failed:%s\n", modbus_strerror(errno));
				sleep(5);
				continue;
			}
			connectOkFlag = 1;
		}
		
		//4. 循环请求服务器
		while (1)
		{
			printf("\n\n-------- [MODBUS] --------\n");

			memset(tab_reg, 0, sizeof(tab_reg));
			//5. 读取保持寄存器的值,可读取多个连续输入保持寄存器
			ret = modbus_read_registers(ctx, 0, 10, tab_reg);
			if (-1 == ret)
			{
				printf("modbus_read_registers: %s\n", modbus_strerror(errno));
				break;
			}
			for (i=0; i<10; i++)
			{
				printf("reg[%d] = %d(0x%x)\n", i, tab_reg[i], tab_reg[i]);
			}
			printf("\n-------- [MODBUS] --------\n\n");
			
			sleep(5);
		}
		
		//6. 释放内存
		modbus_close(ctx);	//关闭modbus连接
		modbus_free(ctx);	//释放modbus资源,使用完libmodbus需要释放掉

		//7. 重置标志
		newOkFlag = 0;
		connectOkFlag = 0;
	}
}
/*************************
**
** modbus-tcp
** 模拟modbus tcp server
**
**************************/
void *custom_modbus_tcp_server_task(void *arg)
{
    printf("custom_modbus_tcp_server_task!\n");

	int ret;
	int sockfd = -1;
	uint8 query[MODBUS_TCP_MAX_ADU_LENGTH];
	modbus_t *ctx = NULL;
	modbus_mapping_t *map = NULL;

	//1.以tcp的方式创建libmobus实例,并设置ip和端口号
	ctx = modbus_new_tcp("127.0.0.1", 8080);	
	if (NULL == ctx)
	{
		printf("Unable to allocate libmodbus contex\n");
		return NULL;
	}

	//2. 设置调试模式
	ret = modbus_set_debug(ctx, TRUE);
	if (-1 == ret)
	{
		printf("modbus_set_debug failed...\n");
		modbus_free(ctx);
		return NULL;
	}

	//3. 申请内存 存放寄存器数据
	map = modbus_mapping_new(500, 500, 500, 500);
	if (NULL == map)
	{
		fprintf(stderr, "Error: mapping %s\n", modbus_strerror(errno));
		modbus_free(ctx);
		return NULL;
	}
#if 1
	map->tab_registers[0] = 0;
	map->tab_registers[1] = 1;
	map->tab_registers[2] = 2;
	map->tab_registers[3] = 3;
	map->tab_registers[4] = 4;
	map->tab_registers[5] = '\0';
#endif
	
	//4. 开始监听端口
	sockfd = modbus_tcp_listen(ctx, 1);
	if (-1 == sockfd)
	{
		printf("modbus_tcp_listen failed...\n");
		modbus_free(ctx);
		return NULL;
	}

	//5. 接受客户端连接
	ret = modbus_tcp_accept(ctx, &sockfd);
	if (-1 == ret)
	{
		printf("modbus_tcp_accept failedl: %s\n", modbus_strerror(errno));
		modbus_free(ctx);
		return NULL;
	}
		
	//6. 循环接受客户端请求,并且响应客户端
	while (1)
	{
		printf("\n\n-------- [MODBUS] --------\n");

		memset(query, 0, sizeof(query));
		//获取查询请求报文
		ret = modbus_receive(ctx, query);
		if (ret >= 0)
		{
			//回复响应报文
			modbus_reply(ctx, query, ret, map);
		}
		else
		{
			printf("Connection close\n");
			modbus_close(ctx);
			//等待下一个客户端连接
			modbus_tcp_accept(ctx, &sockfd);
		}

		printf("\n-------- [MODBUS] --------\n\n");
	}
	
	printf("Quit the loop: %s\n", modbus_strerror(errno));
	
	//6. 释放内存
	modbus_mapping_free(map);
	
	//7. 关闭设备
	modbus_close(ctx);	//关闭modbus连接
	modbus_free(ctx);	//释放modbus资源,使用完libmodbus需要释放掉
}

modbus tcp测试结果

补充学习总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值