libmodbus的编译和使用
libmodbus 是支持Linux,Mac OS X,QNX和win32 的一个modbus库,支持modbus TCP和RTU 两种模式。
libmodbus 的官网:https://www.libmodbus.org/
当前版本为:v3.1.6
编译
我在win10 下的wsl 下编译的,相信在ubuntu linux 下也大同小异。
下载解压 libmodbus 的源码,F:lib modbus-3.1.6文件夹中。
进入wsl 的console,输入下述命令完成编译
cd /mnt/f/libmodbus-3.1.6
./configure
make
libmodbus 包中包含了tests 目录,其中有一些测试程序,已经同时被编译。
运行测试程序
./bandwidth_server_one
另外开启一个wsl console 窗口
输入 ./bandwidth_client
可以看到输出信息
bandwidth_client /bandwidth_server是用来测试modbus TCP 速率的测试程序。相对比较简单。下面列出了bandwidth_client 的程序源码
/*
* Copyright © 2008-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#ifndef _MSC_VER
#include <unistd.h>
#include <sys/time.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <modbus.h>
#define G_MSEC_PER_SEC 1000
static uint32_t gettime_ms(void)
{
struct timeval tv;
#if !defined(_MSC_VER)
gettimeofday(&tv, NULL);
return (uint32_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
#else
return GetTickCount();
#endif
}
enum {
TCP,
RTU
};
/* Tests based on PI-MBUS-300 documentation */
int main(int argc, char *argv[])
{
uint8_t *tab_bit;
uint16_t *tab_reg;
modbus_t *ctx;
int i;
int nb_points;
double elapsed;
uint32_t start;
uint32_t end;
uint32_t bytes;
uint32_t rate;
int rc;
int n_loop;
int use_backend;
if (argc > 1) {
if (strcmp(argv[1], "tcp") == 0) {
use_backend = TCP;
n_loop = 100000;
} else if (strcmp(argv[1], "rtu") == 0) {
use_backend = RTU;
n_loop = 100;
} else {
printf("Usage:\n %s [tcp|rtu] - Modbus client to measure data bandwith\n\n", argv[0]);
exit(1);
}
} else {
/* By default */
use_backend = TCP;
n_loop = 100000;
}
if (use_backend == TCP) {
ctx = modbus_new_tcp("127.0.0.1", 1502);
} else {
ctx = modbus_new_rtu("/dev/ttyUSB1", 115200, 'N', 8, 1);
modbus_set_slave(ctx, 1);
}
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n",
modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
/* Allocate and initialize the memory to store the status */
tab_bit = (uint8_t *) malloc(MODBUS_MAX_READ_BITS * sizeof(uint8_t));
memset(tab_bit, 0, MODBUS_MAX_READ_BITS * sizeof(uint8_t));
/* Allocate and initialize the memory to store the registers */
tab_reg = (uint16_t *) malloc(MODBUS_MAX_READ_REGISTERS * sizeof(uint16_t));
memset(tab_reg, 0, MODBUS_MAX_READ_REGISTERS * sizeof(uint16_t));
printf("READ BITS\n\n");
nb_points = MODBUS_MAX_READ_BITS;
start = gettime_ms();
for (i=0; i<n_loop; i++) {
rc = modbus_read_bits(ctx, 0, nb_points, tab_bit);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
}
end = gettime_ms();
elapsed = end - start;
rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start);
printf("Transfert rate in points/seconds:\n");
printf("* %d points/s\n", rate);
printf("\n");
bytes = n_loop * (nb_points / 8) + ((nb_points % 8) ? 1 : 0);
rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
printf("Values:\n");
printf("* %d x %d values\n", n_loop, nb_points);
printf("* %.3f ms for %d bytes\n", elapsed, bytes);
printf("* %d KiB/s\n", rate);
printf("\n");
/* TCP: Query and reponse header and values */
bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0);
printf("Values and TCP Modbus overhead:\n");
printf("* %d x %d bytes\n", n_loop, bytes);
bytes = n_loop * bytes;
rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
printf("* %.3f ms for %d bytes\n", elapsed, bytes);
printf("* %d KiB/s\n", rate);
printf("\n\n");
printf("READ REGISTERS\n\n");
nb_points = MODBUS_MAX_READ_REGISTERS;
start = gettime_ms();
for (i=0; i<n_loop; i++) {
rc = modbus_read_registers(ctx, 0, nb_points, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
}
end = gettime_ms();
elapsed = end - start;
rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start);
printf("Transfert rate in points/seconds:\n");
printf("* %d registers/s\n", rate);
printf("\n");
bytes = n_loop * nb_points * sizeof(uint16_t);
rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
printf("Values:\n");
printf("* %d x %d values\n", n_loop, nb_points);
printf("* %.3f ms for %d bytes\n", elapsed, bytes);
printf("* %d KiB/s\n", rate);
printf("\n");
/* TCP:Query and reponse header and values */
bytes = 12 + 9 + (nb_points * sizeof(uint16_t));
printf("Values and TCP Modbus overhead:\n");
printf("* %d x %d bytes\n", n_loop, bytes);
bytes = n_loop * bytes;
rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
printf("* %.3f ms for %d bytes\n", elapsed, bytes);
printf("* %d KiB/s\n", rate);
printf("\n\n");
printf("WRITE AND READ REGISTERS\n\n");
nb_points = MODBUS_MAX_WR_WRITE_REGISTERS;
start = gettime_ms();
for (i=0; i<n_loop; i++) {
rc = modbus_write_and_read_registers(ctx,
0, nb_points, tab_reg,
0, nb_points, tab_reg);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}
}
end = gettime_ms();
elapsed = end - start;
rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start);
printf("Transfert rate in points/seconds:\n");
printf("* %d registers/s\n", rate);
printf("\n");
bytes = n_loop * nb_points * sizeof(uint16_t);
rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
printf("Values:\n");
printf("* %d x %d values\n", n_loop, nb_points);
printf("* %.3f ms for %d bytes\n", elapsed, bytes);
printf("* %d KiB/s\n", rate);
printf("\n");
/* TCP:Query and reponse header and values */
bytes = 12 + 9 + (nb_points * sizeof(uint16_t));
printf("Values and TCP Modbus overhead:\n");
printf("* %d x %d bytes\n", n_loop, bytes);
bytes = n_loop * bytes;
rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
printf("* %.3f ms for %d bytes\n", elapsed, bytes);
printf("* %d KiB/s\n", rate);
printf("\n");
/* Free the memory */
free(tab_bit);
free(tab_reg);
/* Close the connection */
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
上面的例子测试读10万个点,读10万个寄存器,读写十万次的时间。
主要用法
上下文类型context
前面已经提到,libmodbus 支持TCP和RTU 两种通信方式,前一种是支持TCP/IP 协议的,而RTU 是支持RS485 串口的协议。libmodbus 库的设计将TCP/RTU 模式的实现细节在用户端屏蔽掉了。modbus 的类型数据放置在一个结构类型中,当新建一个modbus 接口时,填入有关的参数,并将这个包含接口参数的结构指针返回给用户,这个指针称为上下文类型。
例如:
在以后的各种操作中,用户只要带有contex 参数就可以了,不再关心是modbus TCP 还是modbus RTU 。这两种模式的各种函数都是一样的。
modbus_t *ctx;
ctx = modbus_new_tcp("127.0.0.1", 1502);
if (ctx == NULL) {
fprintf(stderr, "Unable to allocate libmodbus context\n");
return -1;
}
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
显然,这是一种优雅的程序设计方式。
读比特位
rc = modbus_write_bit(ctx, addr, tab_rq_bits[0]);
写比特位
rc = modbus_read_bits(ctx, addr, 1, tab_rp_bits);
读寄存器
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
写寄存器
int modbus_write_register(modbus_t *ctx, int addr, const uint16_t value);
读写寄存器
int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb, const uint16_t *src, int read_addr, int read_nb, const uint16_t *dest);
更多推荐
所有评论(0)