(一)背景
项目需要采集RTU设备(工业仪表)的数据,其中涉及Modbus协议及数据转换,因为之前没接触过这块内容,所以准备在Linux环境下移植第三方库 -- libmodbus到开发板,以节省开发时间成本。
(二)调试工具
Modbus Poll、Modbus Slave、Configure Virtual Serial Port Driver(虚拟串口工具)。
使用说明参见:https://blog.csdn.net/echoszf/article/details/77702599
(三)移植步骤
主要说明ARM开发板移植部分,这部分自己遇到的问题比较多,虚拟机中Linux移植部分参考比较多,自己主要参考了以下文档:https://blog.csdn.net/u010168781/article/details/73924748 https://blog.csdn.net/zgkxzx/article/details/78231171
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/ 即可解决交叉编译命令找不到的问题。更多见文档《ZLG开发指南》,我这里使用的是一款ZLG的开发板)
(3)copy可执行文件至 /nfsroot 目录,再至ARM开发板 /mnt 目录,执行 ./modbus-tcp-test 即可运行应用程序。借助调试助手Modbus Slave测试结果如下图
(四)测试程序
/*************************
**
** modbus-rtu-test.c
** 移植libmodbus库到ZLG开发板,并测试成功
**
**************************/
#include
#include
#include
#include
#include
#include //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;
}