写在文章最开头简单介绍一下,我这篇文字是基于什么背景而写下的,以便各位能更快速地判断本文是否符合您的需要。
文章背景:目前我自己本人是一名大四学生,由于近期在做毕业设计,需要在linux系统下读取一款压力传感器的数值,这款传感器采用了RS485转USB连接到电脑,想要读取传感器数据,就需要通过电脑向传感器发送读取指令(例如:FE 04 00 00 00 01 25 C5),传感器会返回相同格式的一串指令(地址码+功能码+数据区+校验码),由于我做的项目是一个大型项目的一个小分支,我需要读取这个数据,并且可以使用。如果仅仅是为了看到显示的数值,可以尝试使用带CRC校验的串口助手。
接下来我将进入正体和大家分享一下自己如何在ubuntu20.04上下载并应用libmodbus库读取传感器数据。
1.下载libmodbus库
安装建议参考这篇文章:
Linux编译安装libmodbus库_一只嵌入式爱好者的博客-CSDN博客_安装libmodbus
按照这个文章安装下来,至于后面的使用部分,文章写的多少有点玄学,并且有点跨度较大,难以理解,只要执行到sudo make install就可以了。至于安装上之后是否真的有用,我觉得应该作为一个环境放在系统里,虽然我没有引用下载下来的头文件,因为引用的时候,总是会在响应时间那里报错。个人建议自己重新按照CMake,将所有文件重新编译一次生成一个新的so库和头文件,特别是从站地址大于247的情况,可以通过修改modbus_rtu.c文件下的一个参数,将247修改为255就可以实现从站地址的扩充,因为libmodbus库默认的范围到247。
2.学习CMake
http://file.ncnynl.com/ros/CMake%20Practice.pdf
下载下来这篇文章,跟着里面的步骤从t1做到t4,并且自己适当扩展一下,因为后面我们所有需要用的东西都得依靠CMake。
这里是一个错误,需要将括号里的内容修改为hello ${SRC_LIST}
4.按照CMake编译一个新的libmodbus库(因为我自己的传感器从站地址是254,需要修改)
链接: https://pan.baidu.com/s/1n-sFp6sAPbZa4c-7lm6-BQ 提取码: l900
这是我自己开发所需要的文档之类的其中:
(1)有重要的头文件放在h文件夹里,下载好的libmodbus库只有四个头文件没有config.h,这个头文件是我从windows系统上安装libmodbus做测试的时候,在VS上编译生成dll库的时候,在x64文件家里找到的,抱着试试看的心理复制到了ubuntu上,发现可以使用。
(2)C和C++两个文件夹放了我自己写的两种语言版本的程序,我自己测试后都是可以直接运行的。
(3)modbus文件夹放置了修改libmodbus库所需要的c文件和h文件,编译该文件夹之后会在你学习CMake时生成libhello.so的地方生成libmodbus.so这一步一定要做,通过指令下载的libmodbus库会遇到这一段程序报错。
struct timeval t;
t.tv_sec=0;
t.tv_usec=1000000; //set modbus time 1000ms
modbus_set_response_timeout(ctx,&t);
提取出文档之后,打开modbus文档,在里面添加一个build文件夹,按照CMake的步骤执行就可以生成所需要的头文件和库文件了。生成之后,可以在/usr/include里面找到modbus文件夹,把我分享的h文件夹里的文件复制到modbus文件夹里,替换掉之前的那些文件。如果提示你不可以粘贴,就用sudo cp -i modbus.h /usr/include/modbus 这条指令挨个复制进去。
如果需要从站地址的参数,可以找到lib文件夹里的modbus-rtu.c进行修改。
static int _modbus_set_slave(modbus_t *ctx, int slave)
{
/* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
if (slave >= 0 && slave <= 255) {
ctx->slave = slave;
} else {
errno = EINVAL;
return -1;
}
return 0;
}
直接修改这个数值就可以,我给的文件是我已经修改过的文件,原来安装的是247。
4.运行代码
在我分享的百度网盘链接里,我会给出C++和C两个版本,但都需要用CMake来运行,直接用编译器会出现头文件报错,因为我们的都文件声明链接都在CmakeList.txt中。编译器打开项目,需要一整个文件全放进去,我不太喜欢VS Code,所以我都直接用CMake来运行。
C文件夹里面应该有三个东西,一个是编译位置build文件夹,一个是程序所在地lib文件夹和一个声明CMakeList.txt。最重要的文件放在lib里面
main.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include "modbus.h"
char* getDateTime();
int main(int argc, char const *argv[])
{
modbus_t *ctx;
uint16_t tab_reg[64];
int rc=0;
int i=0;
ctx = modbus_new_rtu("/dev/ttyUSB0", 9600,'N',8,2);//配置端口,“”内写的是端口,Win系统下是COM*,Ubuntu是/dev/ttyusb*
modbus_set_slave(ctx,254);//设置从站地址,就是指令的前两位十六进制换算成十进制 例:FE(H)=254(D)
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
struct timeval t;
t.tv_sec=0;
t.tv_usec=1000000; //set modbus time 1000ms
modbus_set_response_timeout(ctx,&t);//设置响应时间
while (1) {
char* nowtime = getDateTime();
rc = modbus_read_input_registers(ctx,0,1, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s error-test\n", modbus_strerror(errno));
return -1;
}
printf("%s:压力值:%d g \n十六进制显示:(0x%X)\n",nowtime, tab_reg[0], tab_reg[0]);
usleep(10);
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
char* getDateTime()//获取当前时间
{
static char nowtime[20];
time_t rawtime;
struct tm* ltime;
time(&rawtime);
ltime = localtime(&rawtime);
strftime(nowtime, 20, "%Y-%m-%d %H:%M:%S", ltime);
return nowtime;
}
CMakeList.txt
ADD_EXECUTABLE(main main.c)//编译main.c后生成可执行文件main
INCLUDE_DIRECTORIES(/usr/include/modbus)//头文件所在位置
TARGET_LINK_LIBRARIES(main libmodbus.so)//连接库
5.运行结果
C语言版本运行结果(这个需要端口真实的接传感器,Windows可以用modbus slave模拟)
C++版本
博主QQ:3122899873 有具体遇到的问题可以加QQ来问,也可以留言,看到都会尽量回复!