当前位置:   article > 正文

libmodbus

libmodbus

1 简介

  • A Modbus library for Linux, Mac OS X, FreeBSD, QNX and Win32.
  • libmodbus is a free software library to send/receive data according to the Modbus protocol. This library is written in C and supports RTU (serial) and TCP (Ethernet) communications.
  • The license of libmodbus is LGPL v2.1+ and the licence of programs in the tests directory is BSD 3-clause.

2 库使用

2.1 直接加入工程中

在这里插入图片描述

3 函数接口流程

modbus_t *mb;
uint16_t tab_reg[32];

mb = modbus_new_tcp("127.0.0.1", 1502);
modbus_connect(mb);

/* Read 5 registers from the address 0 */
modbus_read_registers(mb, 0, 5, tab_reg);

modbus_close(mb);
modbus_free(mb);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

4 接口概述

  • 下面概述了libmodbus的概念,描述了libmodbus如何抽象出不同硬件和平台的Modbus通信。
  • Modbus协议包含许多变体(例如。串行RTU或Ehternet TCP),为了简化变体的实现,该库被设计为使用每个变体的后端。后端也是一种方便的方式来满足其他需求(例如。实时操作)。每个后端都提供一个特定的函数来创建一个新的modbus_t上下文。modbus_t上下文是一个不透明的结构,包含根据所选的变体与其他Modbus设备建立连接所需的所有信息。

RTU Context

RTU后端(远程终端单元)用于串行通信,并利用紧凑的二进制数据表示进行协议通信。RTU格式遵循命令/数据,采用循环冗余校验和的错误校验机制,保证数据的可靠性。Modbus RTU是Modbus最常用的实现。一个Modbus RTU消息必须连续传输,没有字符间的犹豫(摘自维基百科,Modbus, http://en.wikipedia.org/wiki/Modbus(截至2011年3月13日20:51 GMT)。

Modbus RTU帧调用一个处理Modbus请求的设备/服务的slave和一个发送请求的客户端master。通信总是由主机发起的。

许多Modbus设备可以连接在同一物理链路上,所以在发送消息之前,必须用modbus_set_slave(3)设置从设备(接收设备)。如果你运行一个slave,它的slave号将被用来过滤收到的消息。

RTU的libmodbus实现并不像原始Modbus规范中所述的那样基于时间,而是以尽可能快的速度发送所有字节,当所有期望的字符都被接收到时,响应或指示就被认为是完整的。这个实现提供了非常快速的通信,但你必须注意将从服务器的响应超时设置为小于主服务器的响应超时(否则当一个从服务器没有响应时,其他从服务器可能会忽略主服务器请求)。

  • 创建一个Modbus RTU上下文
    modbus_new_rtu(3)
0 链接  https://libmodbus.org/docs/v3.1.4/modbus_new_rtu.html
1 函数原型
modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);
2 函数介绍
modbus_new_rtu()函数将分配和初始化一个modbus_t结构,以便在串行线路上以RTU方式通信。
3 示例
modbus_t *ctx;

ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1);
if (ctx == NULL) {
    fprintf(stderr, "Unable to create the libmodbus context\n");
    return -1;
}

modbus_set_slave(ctx, YOUR_DEVICE_ID);

if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 设置串行模式
    modbus_rtu_get_serial_mode(3)
0 链接  https://libmodbus.org/docs/v3.1.4/modbus_rtu_get_serial_mode.html
1 函数原型
int modbus_rtu_get_serial_mode(modbus_t *ctx);
2 函数介绍
modbus_rtu_get_serial_mode()函数将返回libmodbus上下文当前使用的串行模式:
MODBUS_RTU_RS232
MODBUS_RTU_RS485
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

modbus_rtu_set_serial_mode(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_rtu_set_serial_mode.html
1 函数原型
int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
2 函数介绍
modbus_rtu_set_serial_mode()函数设置所选的串行模式:
MODBUS_RTU_RS232
MODBUS_RTU_RS485
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

modbus_rtu_get_rts(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_rtu_get_rts.html
1 函数原型
int modbus_rtu_get_rts(modbus_t *ctx);
2 函数介绍
modbus_rtu_get_rts()函数将获取libmodbus上下文ctx的当前发送请求模式。可能的返回值有:
MODBUS_RTU_RTS_NONE
MODBUS_RTU_RTS_UP
MODBUS_RTU_RTS_DOWN
这个函数只能与RTU后端上下文一起使用。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

modbus_rtu_set_rts(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_rtu_set_rts.html
1 函数原型
int modbus_rtu_set_rts(modbus_t *ctx, int mode)
2 函数介绍
modbus_rtu_set_rts()函数设置发送请求模式,以便在RS485串行总线上进行通信。默认模式为MODBUS_RTU_RTS_NONE,在线上写入数据前不发出信号。

要使能RTS模式,必须使用“MODBUS_RTU_RTS_UP”或“MODBUS_RTU_RTS_DOWN”,这两种模式同时使能RTS模式和设置极性。当MODBUS_RTU_RTS_UP被使用时,一个ioctl调用是启用RTS标志的,然后数据在延迟1毫秒后被写入总线上,然后另一个ioctl调用是禁用RTS标志的,并且再次发生1毫秒的延迟。MODBUS_RTU_RTS_DOWN模式应用相同的过程,但带有反转的RTS标志。

这个函数只能与RTU后端上下文一起使用。
3 示例
modbus_t *ctx;
uint16_t tab_reg[10];

ctx = modbus_new_rtu("/dev/ttyS0", 115200, 'N', 8, 1);
modbus_set_slave(ctx, 1);
modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);

if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}

rc = modbus_read_registers(ctx, 0, 7, tab_reg);
if (rc == -1) {
    fprintf(stderr, "%s\n", modbus_strerror(errno));
    return -1;
}

modbus_close(ctx);
modbus_free(ctx);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

modbus_rtu_set_custom_rts(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_rtu_set_custom_rts.html
1 函数原型
int modbus_rtu_set_custom_rts(modbus_t *ctx, void (set_rts) (modbus_t ctx, int on))
2 函数介绍
modbus_rtu_set_custom_rts()函数将设置一个自定义函数,当在传输前后设置RTS引脚时将调用该函数。默认情况下,它被设置为使用ioctl调用切换RTS引脚的内部函数。

注意,该函数遵循RTS模式,调用时必须使用MODBUS_RTU_RTS_UP或MODBUS_RTU_RTS_DOWN值。

这个函数只能与RTU后端上下文一起使用。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

modbus_rtu_get_rts_delay(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_rtu_get_rts_delay.html
1 函数原型
int modbus_rtu_get_rts_delay(modbus_t *ctx);
2 函数介绍
modbus_rtu_get_rts_delay()函数将获取libmodbus上下文ctx的当前发送请求延迟时间。

这个函数只能与RTU后端上下文一起使用。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

modbus_rtu_set_rts_delay(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_rtu_set_rts_delay.html  
1 函数原型
int modbus_rtu_set_rts_delay(modbus_t *ctx, int us);
2 函数介绍
函数的作用是:设置libmodbus上下文ctx的发送请求延迟时间。

这个函数只能与RTU后端上下文一起使用。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

TCP (IPv4) Context

TCP后端实现了Modbus变体,用于在TCP/IPv4网络上进行通信。它不需要校验和计算,因为较低的层负责相同的工作。

  • 创建一个Modbus TCP上下文
    modbus_new_tcp(3)
0 链接  https://libmodbus.org/docs/v3.1.4/modbus_new_tcp.html
1 函数原型
modbus_t *modbus_new_tcp(const char *ip, int port);
2 函数介绍
modbus_new_tcp()函数将分配并初始化一个modbus_t结构来与Modbus TCP IPv4服务器通信。

参数ip指定客户端想要建立连接的服务器的ip地址。NULL值可以用来侦听服务器模式下的任何地址。

port参数是要使用的TCP端口。设置端口为“MODBUS_TCP_DEFAULT_PORT”,使用默认端口502。使用大于或等于1024的端口号很方便,因为不需要具有管理员权限。
3 示例
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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

TCP PI (IPv4 and IPv6) Context

TCP PI(协议独立)后端实现Modbus变体,用于TCP IPv4和IPv6网络上的通信。它不需要校验和计算,因为较低的层负责相同的工作。

与TCP IPv4唯一的后端相反,TCP PI后端提供主机名解析,但它消耗大约1Kb的额外内存。

  • 创建一个Modbus TCP上下文
    modbus_new_tcp_pi(3)
0 链接  https://libmodbus.org/docs/v3.1.4/modbus_new_tcp_pi.html  
1 函数原型
modbus_t *modbus_new_tcp_pi(const char *node, const char *service);
2 函数介绍
modbus_new_tcp_pi()函数将分配和初始化一个modbus_t结构,以与Modbus TCP IPv4或IPv6服务器通信。

node参数指定要连接的主机的主机名或IP地址,例如。“192.168.0.5”,“::1”或“server.com”。NULL值可以用来侦听服务器模式下的任何地址。

参数service是要连接的服务名/端口号。要使用默认的Modbus端口,请使用字符串“502”。在许多Unix系统上,使用大于或等于1024的端口号很方便,因为不需要具有管理员特权。
3 示例
modbus_t *ctx;

ctx = modbus_new_tcp_pi("::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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Common

在使用任何libmodbus函数之前,调用者必须使用上面解释的函数分配和初始化modbus_t上下文,然后提供以下函数来修改和释放上下文:

释放libmodbus上下文

modbus_free(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_free.html 
1 函数原型
void modbus_free(modbus_t *ctx);
2 函数介绍
modbus_free()函数将释放一个已分配的modbus_t结构。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

设置从机ID

modbus_set_slave(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_slave.html
1 函数原型
int modbus_set_slave(modbus_t *ctx, int slave);
2 函数介绍
modbus_set_slave()函数将在libmodbus上下文中设置从机编号。
行为取决于网络和设备的角色:
RTU
定义远端设备的从ID,以便在主模式下进行会话,或者在从模式下设置内部从ID。根据协议,Modbus设备必须只接受持有其从号或特殊广播号的消息。
TCP
只有在TCP中,如果消息必须到达串行网络中的设备,才需要slave号。一些不兼容的设备或软件(如modpoll)使用slave ID作为单位标识符,这是不正确的(参考Modbus Messaging Implementation Guide v1.0b第23),但如果没有slave值,故障的远程设备或软件将放弃请求!在TCP模式下,可以使用特殊值MODBUS_TCP_SLAVE (0xFF)恢复默认值。

广播地址为MODBUS_BROADCAST_ADDRESS。当您希望网络上的所有Modbus设备接收请求时,必须使用此特殊值。
3 示例
modbus_t *ctx;

ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1);
if (ctx == NULL) {
    fprintf(stderr, "Unable to create the libmodbus context\n");
    return -1;
}

rc = modbus_set_slave(ctx, YOUR_DEVICE_ID);
if (rc == -1) {
    fprintf(stderr, "Invalid slave ID\n");
    modbus_free(ctx);
    return -1;
}

if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

启用调试模式

modbus_set_debug(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_debug.html  
1 函数原型
int modbus_set_debug(modbus_t *ctx, int flag);
2 函数介绍
modbus_set_debug()函数将通过参数标志设置modbus_t上下文的调试标志。默认情况下,布尔标志被设置为FALSE。当该标志值设置为TRUE时,将在stdoutstderr上显示许多详细消息。例如,该标志用于显示Modbus消息的字节。
[00][14][00][00][00][06][12][03][00][6B][00][03]
Waiting for a confirmation…
<00><14><00><00><00><09><12><03><06><02><2B><00><00><00><00>
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

超时设置

modbus_get_byte_timeout(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_byte_timeout.html
1 函数原型
int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
2 函数介绍
modbus_get_byte_timeout()函数将同一消息的两个连续字节之间的超时时间存储在to_sec和to_usec参数中。
3 示例
uint32_t to_sec;
uint32_t to_usec;

/* Save original timeout */
modbus_get_byte_timeout(ctx, &to_sec, &to_usec);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

modbus_set_byte_timeout(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_byte_timeout.html
1 函数原型
void modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
2 函数介绍
modbus_set_byte_timeout()函数的作用是:设置同一消息两个连续字节之间的超时时间。超时是select()返回之前所经过的时间的上限,如果所经过的时间比定义的超时时间长,则等待响应的函数将引发ETIMEDOUT错误。

to_usec参数的值必须在0999999之间。

如果to_sec和to_usec都为零,则这个超时将不会被使用。在这种情况下,modbus_set_response_timeout()管理响应的整个处理,必须在响应超时超时之前接收完整的确认响应。当设置了字节超时时,响应超时仅用于等待响应的第一个字节。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

modbus_get_response_timeout(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_response_timeout.html
1 函数原型
int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
2 函数介绍
modbus_get_response_timeout()函数将返回to_sec和to_usec参数中等待响应的超时时间。
3 示例
uint32_t old_response_to_sec;
uint32_t old_response_to_usec;

/* Save original timeout */
modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);

/* Define a new and too short timeout! */
modbus_set_response_timeout(ctx, 0, 0);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

modbus_set_response_timeout(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_response_timeout.html
1 函数原型
int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
2 函数介绍
modbus_set_response_timeout()函数将设置等待响应的超时时间。当设置字节超时时,如果响应的第一个字节经过的时间比给定的超时时间长,则等待响应的函数将引发ETIMEDOUT错误。当字节超时被禁用时,必须在响应超时过期之前接收完整的确认响应。

to_usec参数的值必须在0999999之间。
3 示例
uint32_t old_response_to_sec;
uint32_t old_response_to_usec;

/* Save original timeout */
modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);

/* Define a new timeout of 200ms */
modbus_set_response_timeout(ctx, 0, 200000);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

错误恢复模式

modbus_set_error_recovery(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_error_recovery.html
1 函数原型
int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
2 函数介绍
modbus_set_error_recovery()函数将设置错误恢复模式,当连接失败或接收到的字节不是预期的时候应用。参数error_recovery可以按位或包含0个或多个以下常量。

默认情况下没有错误恢复(MODBUS_ERROR_RECOVERY_NONE),因此应用程序负责控制libmodbus函数返回的错误值,并在必要时处理它们。

当设置了MODBUS_ERROR_RECOVERY_LINK时,库将在libmodbus上下文响应超时定义的延迟之后尝试重新连接。这种模式会尝试无限的关闭/连接循环,直到send调用成功,并且只会尝试一次,在select/read调用中重新建立连接(如果连接断开,在重新连接后读取的值肯定不再可用,除了slave/server)。在某些情况下,这种模式也会在基于当前响应超时的延迟之后运行刷新请求(例如。选择呼叫超时)。如果到远程目标单元的网络故障,重新连接尝试可能会挂起几秒钟。

当设置了MODBUS_ERROR_RECOVERY_PROTOCOL时,将使用sleep和flush序列来清理正在进行的通信,这可能发生在消息长度无效、TID错误或接收到的函数代码不是预期的时候。响应超时延迟将用于休眠。

模是掩模值,所以它们是互补的。

不建议启用从服务器/服务器的错误恢复。
3 示例
modbus_set_error_recovery(ctx,
                          MODBUS_ERROR_RECOVERY_LINK |
                          MODBUS_ERROR_RECOVERY_PROTOCOL);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

内部套接字的Setter/getter

modbus_set_socket(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_socket.html
1 函数原型
int modbus_set_socket(modbus_t *ctx, int s);
2 函数介绍
函数的作用是:在libmodbus上下文中设置套接字或文件描述符。此功能对于管理到同一服务器的多个客户端连接非常有用。
3 示例
ctx = modbus_new_tcp("127.0.0.1", 1502);
server_socket = modbus_tcp_listen(ctx, NB_CONNECTION);

FD_ZERO(&rdset);
FD_SET(server_socket, &rdset);

/* .... */

if (FD_ISSET(master_socket, &rdset)) {
    modbus_set_socket(ctx, master_socket);
    rc = modbus_receive(ctx, query);
    if (rc != -1) {
        modbus_reply(ctx, query, rc, mb_mapping);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

modbus_get_socket(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_socket.html
1 函数原型
int modbus_get_socket(modbus_t *ctx);
2 函数介绍
函数的作用是:返回libmodbus上下文的当前套接字或文件描述符。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

头信息

modbus_get_header_length(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_header_length.html
1 函数原型
int modbus_get_header_length(modbus_t *ctx);
2 函数介绍
modbus_get_header_length()函数将从后端检索当前头的长度。该函数便于操作消息,因此仅限于低级操作。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

用于数据操作的宏

  • MODBUS_GET_HIGH_BYTE(data),从一个字节中提取高字节
  • MODBUS_GET_LOW_BYTE(data),从一个字节中提取低字节
  • MODBUS_GET_INT64_FROM_INT16(tab_int16, index),从tab_int16开始的第四个int16构建一个int64 [index]
  • MODBUS_GET_INT32_FROM_INT16(tab_int16, index),从tab_int16开始的两个int16构建一个int32 [index]
  • MODBUS_GET_INT16_FROM_INT8(tab_int8, index),从tab_int8开始的两个int8构建一个int16 [index]
  • MODBUS_SET_INT16_TO_INT8(tab_int8, index, value),将一个int16值设置为从tab_int8[index]开始的前两个字节
  • MODBUS_SET_INT32_TO_INT16(tab_int16, index, value),将一个int32值设置为从tab_int16开始的两个int16[index]
  • MODBUS_SET_INT64_TO_INT16(tab_int16, index, value),将一个int64值设置为从tab_int16开始的四个int16[index]

位和字节的处理

modbus_set_bits_from_byte(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_bits_from_byte.html
1 函数原型
void modbus_set_bits_from_byte(uint8_t *dest, int index, const uint8_t value);
2 函数介绍
modbus_set_bits_from_byte()函数的作用是:从一个字节中设置多个位。字节值的所有8位将从索引位置开始写入dest数组。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_set_bits_from_bytes(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_bits_from_bytes.html
1 函数原型
void modbus_set_bits_from_bytes(uint8_t *dest, int index, unsigned int nb_bits, const uint8_t *tab_byte);
2 函数介绍
modbus_set_bits_from_bytes函数将通过读取字节数组来设置位。从数组tab_byte的第一个位置读取的字节的所有位都被写入dest数组中从位置索引处开始的位。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_get_byte_from_bits(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_byte_from_bits.html
1 函数原型
uint8_t modbus_get_byte_from_bits(const uint8_t *src, int index, unsigned int nb_bits);
2 函数介绍
modbus_get_byte_from_bits()函数将从许多位中提取一个值。所有来自src的位置索引的nb_bits位将被读取为单个值。要获得一个完整的字节,请将nb_bits设置为83 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

设置或获取浮点数

modbus_get_float_abcd(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_float_abcd.html
1 函数原型
float modbus_get_float_abcd(const uint16_t *src);
2 函数介绍
modbus_get_float_abcd()函数将获得一个普通Modbus格式的4字节浮点数。src数组必须是指向两个16位值的指针,例如,如果第一个字被设置为0x0020,第二个字被设置为0xF147,浮点值将被读取为123456.03 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_set_float_abcd(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_float_abcd.html
1 函数原型
void modbus_set_float_abcd(float f, uint16_t *dest);
2 函数介绍
modbus_set_float_abcd()函数将一个普通Modbus格式的浮点数设置为4字节。dest数组必须是指向两个16位值的指针,以便能够存储转换的全部结果。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_get_float_badc(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_float_badc.html
1 函数原型
float modbus_get_float_badc(const uint16_t *src);
2 函数介绍
modbus_get_float_badc()函数将从4字节中获取一个浮点数,并交换字节(BADC而不是ABCD)。src数组必须是指向两个16位值的指针,例如,如果第一个字被设置为0x2000,第二个字被设置为0x47F1,浮点值将被读取为123456.03 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_set_float_badc(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_float_badc.html
1 函数原型
void modbus_set_float_badc(float f, uint16_t *dest);
2 函数介绍
modbus_set_float_badc()函数将一个浮点数设置为4字节的Modbus格式(BADC而不是ABCD)。dest数组必须是指向两个16位值的指针,以便能够存储转换的全部结果。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_get_float_cdab(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_float_cdab.html
1 函数原型
float modbus_get_float_cdab(const uint16_t *src);
2 函数介绍
modbus_get_float_cdab()函数将从4个字节中获取一个浮点数,并交换单词(CDAB顺序而不是ABCD)。src数组必须是指向两个16位值的指针,例如,如果第一个字被设置为F147,第二个字被设置为0x0020,浮点值将被读取为123456.03 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_set_float_cdab(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_float_cdab.html
1 函数原型
void modbus_set_float_cdab(float f, uint16_t *dest);
2 函数介绍
modbus_set_float_cdab()函数将一个浮点数设置为4字节的Modbus格式(按CDAB顺序而不是ABCD)。dest数组必须是指向两个16位值的指针,以便能够存储转换的全部结果。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_get_float_dcba(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_float_dcba.html
1 函数原型
float modbus_get_float_dcba(const uint16_t *src);
2 函数介绍
modbus_get_float_dcba()函数将获得一个4字节的Modbus反格式浮点数(DCBA顺序而不是ABCD)。src数组必须是指向两个16位值的指针,例如,如果第一个字被设置为0x47F1,第二个字被设置为0x2000,浮点值将被读取为123456.03 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_set_float_dcba(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_float_dcba.html
1 函数原型
void modbus_set_float_dcba(float f, uint16_t *dest);
2 函数介绍
modbus_set_float_dcba()函数将一个浮点数按Modbus格式(DCBA顺序)设置为4字节。dest数组必须是指向两个16位值的指针,以便能够存储转换的全部结果。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

modbus_get_float(3) (deprecated)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_get_float.html
1 函数原型
float modbus_get_float(const uint16_t *src);
Warning, this function is deprecated since libmodbus v3.2.0 and has been replaced by modbus_get_float_dcba().
2 函数介绍
modbus_get_float()函数将从Modbus格式的4字节(DCBA字节顺序)中获得一个浮点数。src数组必须是指向两个16位值的指针,例如,如果第一个字被设置为0x4465,第二个字被设置为0x229a,浮点值将是916.5406493 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

modbus_set_float(3) (deprecated)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_set_float.html
1 函数原型
void modbus_set_float(float f, uint16_t *dest);
Warning, this function is deprecated since libmodbus v3.2.0 and has been replaced by modbus_set_float_dcba().
2 函数介绍
modbus_set_float()函数将一个浮点数设置为4字节的Modbus格式(ABCD)。dest数组必须是指向两个16位值的指针,以便能够存储转换的全部结果。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

连接

Modbus设备建立和关闭连接提供以下功能:

建立连接

modbus_connect(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_connect.html
1 函数原型
int modbus_connect(modbus_t *ctx);
2 函数介绍
modbus_connect()函数将使用参数中给出的libmodbus context的上下文信息建立到Modbus服务器、网络或总线的连接。
3 示例
modbus_t *ctx;

ctx = modbus_new_tcp("127.0.0.1", 502);
if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

关闭连接

modbus_close(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_close.html
1 函数原型
void modbus_close(modbus_t *ctx);
2 函数介绍
modbus_close()函数将关闭上下文中与后端设置建立的连接。
3 示例
modbus_t *ctx;

ctx = modbus_new_tcp("127.0.0.1", 502);
if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}

modbus_close(ctx);
modbus_free(ctx);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

清空连接

modbus_flush(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_flush.html
1 函数原型
int modbus_flush(modbus_t *ctx);
2 函数介绍
modbus_flush()函数将丢弃接收到但未读到套接字或与上下文ctx关联的文件描述符的数据。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

客户端

Modbus协议定义了不同的数据类型和函数,用于从远程设备读写数据。客户端发送Modbus请求使用的功能如下:

读取数据

modbus_read_bits(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_read_bits.html
1 函数原型
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
2 函数介绍
modbus_read_bits()函数将读取nb位(线圈)的状态到远端设备的地址addr。读取的结果存储在dest数组中,为设置为TRUE或FALSE的无符号字节(8)。
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint8_t))。
该函数使用Modbus函数代码0x01(读取线圈状态)3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

modbus_read_input_bits(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_read_input_bits.html
1 函数原型
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
2 函数介绍
modbus_read_input_bits()函数将nb输入位的内容读给远端设备的地址addr。读取的结果存储在dest数组中,为设置为TRUE或FALSE的无符号字节(8)。
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint8_t))。
该函数使用Modbus函数代码0x02(读取输入状态)3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

modbus_read_registers(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_read_registers.html
1 函数原型
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
2 函数介绍
modbus_read_registers()函数的作用是:将nb保持寄存器的内容读取到远端设备的地址addr。读取结果以字值(16)的形式存储在dest数组中。
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint16_t))。
该函数使用Modbus函数代码0x03(读取保持寄存器)3 示例
modbus_t *ctx;
uint16_t tab_reg[64];
int rc;
int i;

ctx = modbus_new_tcp("127.0.0.1", 1502);
if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}

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 < rc; i++) {
    printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
}

modbus_close(ctx);
modbus_free(ctx);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

modbus_read_input_registers(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_read_input_registers.html
1 函数原型
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
2 函数介绍
modbus_read_input_registers()函数的作用是:读取nb输入寄存器的内容到远程设备的地址addr。读取的结果作为字值(16)存储在dest数组中。
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint16_t))。
该函数使用Modbus函数代码0x04(读取输入寄存器)。保持寄存器和输入寄存器有不同的历史意义,但现在更常见的是只使用保持寄存器。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

modbus_report_slave_id(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_report_slave_id.html
1 函数原型
int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
2 函数介绍
modbus_report_slave_id()函数会向控制器发送一个请求,以获取控制器的描述信息。
存储在dest中的响应包含:
slave ID,这个唯一ID实际上根本不是唯一的,所以不可能依赖它来知道响应中的信息是如何打包的。
运行指示灯状态(0x00 = OFF, 0xFF = ON)
特定于每个控制器的附加数据。例如,libmodbus以字符串的形式返回库的版本。
函数从响应写入最多max_dest字节到dest,因此必须确保dest足够大。
3 示例
uint8_t tab_bytes[MODBUS_MAX_PDU_LENGTH];

...

rc = modbus_report_slave_id(ctx, MODBUS_MAX_PDU_LENGTH, tab_bytes);
if (rc > 1) {
    printf("Run Status Indicator: %s\n", tab_bytes[1] ? "ON" : "OFF");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

写入数据

modbus_write_bit(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_write_bit.html
1 函数原型
int modbus_write_bit(modbus_t *ctx, int addr, int status);
2 函数介绍
modbus_write_bit()函数将写入远程设备地址addr处的status状态。该值必须设置为TRUE或FALSE。
功能使用Modbus功能代码0x05 (force single coil)3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

modbus_write_register(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_write_register.html
1 函数原型
int modbus_write_register(modbus_t *ctx, int addr, int value);
2 函数介绍
modbus_write_register()函数将写入远程设备地址addr处的寄存器值。
功能使用Modbus功能码0x06(预设单寄存器)3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

modbus_write_bits(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_write_bits.html
1 函数原型
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
2 函数介绍
modbus_write_bits()函数将从src中写入nb位(线圈)的状态,地址为远端设备的addr。src数组必须包含设置为TRUE或FALSE的字节。
功能使用Modbus功能代码0x0F(强制多个线圈)3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

modbus_write_registers(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_write_registers.html
1 函数原型
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
2 函数介绍
modbus_write_register()函数将从远端设备的地址为addr的数组src中写入nb保持寄存器的内容。
该函数使用Modbus函数代码0x10(预置多个寄存器)3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

写入与读取数据

modbus_write_and_read_registers(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_write_and_read_registers.html
1 函数原型
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);
2 函数介绍
modbus_write_and_read_registers()函数将src数组中write_nb保持寄存器的内容写到远端设备的write_addr地址,然后将read_nb保持寄存器的内容写到远端设备的read_addr地址。读取结果以字值(16)的形式存储在dest数组中。
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint16_t))。
该函数使用Modbus函数代码0x17(/读寄存器)3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

原始请求

modbus_send_raw_request(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_send_raw_request.html
1 函数原型
int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length);
2 函数介绍
modbus_send_raw_request()函数将通过上下文ctx的套接字发送请求。这个函数必须用于调试目的,因为您必须小心手工发出有效的请求。该函数只添加到消息,头或CRC的选定后端,所以raw_req必须启动,并包含至少一个奴隶/单位标识符和函数代码。此函数可用于发送库未处理的请求。
libmodbus的公共头提供了一个支持的Modbus函数代码列表,以MODBUS_FC_为前缀(例如:modbus_fc_read_holding_register)来帮助构建原始请求。
3 示例
modbus_t *ctx;
/* Read 5 holding registers from address 1 */
uint8_t raw_req[] = { 0xFF, MODBUS_FC_READ_HOLDING_REGISTERS, 0x00, 0x01, 0x0, 0x05 };
int req_length;
uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];

ctx = modbus_new_tcp("127.0.0.1", 1502);
if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}

req_length = modbus_send_raw_request(ctx, raw_req, 6 * sizeof(uint8_t));
modbus_receive_confirmation(ctx, rsp);

modbus_close(ctx);
modbus_free(ctx);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

modbus_receive_confirmation(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_receive_confirmation.html
1 函数原型
int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
2 函数介绍
modbus_receive_confirmation()函数将通过上下文ctx的套接字接收请求。必须将此函数用于调试目的,因为接收到的响应不会根据初始请求进行检查。此函数可用于接收库未处理的请求。
响应的最大大小取决于所使用的后端,在RTU中rsp数组必须是MODBUS_RTU_MAX_ADU_LENGTH字节,在TCP中必须是MODBUS_TCP_MAX_ADU_LENGTH字节。如果你想编写与两者兼容的代码,你可以使用常量MODBUS_MAX_ADU_LENGTH(所有libmodbus后端的最大值)。注意分配足够的内存来存储响应,以避免服务器崩溃。
3 示例
uint8_t rsp[MODBUS_MAX_ADU_LENGTH];
rc = modbus_receive_confirmation(ctx, rsp);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

异常响应

modbus_reply_exception(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_reply_exception.html
1 函数原型
*int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int exception_code);
2 函数介绍
modbus_reply_exception()函数将根据参数中的exception_code发送一个异常响应。
libmodbus提供了如下异常代码:
MODBUS_EXCEPTION_ILLEGAL_FUNCTION (1)
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS (2)
MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE (3)
MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE (4)
MODBUS_EXCEPTION_ACKNOWLEDGE (5)
MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY (6)
MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE (7)
MODBUS_EXCEPTION_MEMORY_PARITY (8)
MODBUS_EXCEPTION_NOT_DEFINED (9)
MODBUS_EXCEPTION_GATEWAY_PATH (10)
MODBUS_EXCEPTION_GATEWAY_TARGET (11)
需要初始请求请求来构建有效响应。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

服务端

服务器正在等待来自客户端的请求,当它关心请求时,就必须响应。libmodbus提供了以下函数来处理请求:

数据映射

modbus_mapping_new(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_mapping_new.html
1 函数原型
modbus_mapping_t modbus_mapping_new(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers);*
DESCRIPTION
2 函数介绍
modbus_mapping_new()函数将分配四个数组来存储位、输入位、寄存器和输入寄存器。指针存储在modbus_mapping_t结构中。数组的所有值都初始化为零。
这个函数相当于调用modbus_mapping_new_start_address(3)函数,所有起始地址都为0。
如果不需要为特定类型的数据分配数组,则可以在参数中传递0值,相关的指针将为NULL。
这个功能可以方便地处理Modbus服务器/从服务器中的请求。
3 示例
/* The first value of each array is accessible from the 0 address. */
mb_mapping = modbus_mapping_new(BITS_ADDRESS + BITS_NB,
                                INPUT_BITS_ADDRESS + INPUT_BITS_NB,
                                REGISTERS_ADDRESS + REGISTERS_NB,
                                INPUT_REGISTERS_ADDRESS + INPUT_REGISTERS_NB);
if (mb_mapping == NULL) {
    fprintf(stderr, "Failed to allocate the mapping: %s\n",
            modbus_strerror(errno));
    modbus_free(ctx);
    return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

modbus_mapping_free(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_mapping_free.html
1 函数原型
void modbus_mapping_free(modbus_mapping_t *mb_mapping);
2 函数介绍
该函数将释放mb_mapping_t结构的四个数组,最后释放mb_mapping引用的mb_mapping_t。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

接收

modbus_receive(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_receive.html
1 函数原型
int modbus_receive(modbus_t *ctx, uint8_t *req);
2 函数介绍
modbus_receive()函数将从上下文ctx的套接字接收指示请求。该功能用于Modbus从端/服务器端接收和分析主端/客户端发出的指示请求。
如果需要使用上下文ctx中定义的套接字或文件描述符以外的其他套接字或文件描述符,请参见modbus_set_socket(3)函数。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

回复

modbus_reply(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_reply.html 
1 函数原型
*int modbus_reply(modbus_t *ctx, const uint8_t *req, int req_length, modbus_mapping_t *mb_mapping);
2 函数介绍
modbus_reply()函数将对接收到的请求发送一个响应。对参数中给出的请求请求进行分析,然后利用modbus上下文ctx的信息构建并发送响应。
如果请求指示读或写一个值,操作将根据操作数据的类型在modbus映射mb_mapping中完成。
如果发生错误,将发送异常响应。
本功能是为Modbus服务器设计的。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

modbus_reply_exception(3)

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_reply_exception.html
1 函数原型
*int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int exception_code);
2 函数介绍
modbus_reply_exception()函数将根据参数中的exception_code发送一个异常响应。
libmodbus提供了如下异常代码:
MODBUS_EXCEPTION_ILLEGAL_FUNCTION (1)
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS (2)
MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE (3)
MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE (4)
MODBUS_EXCEPTION_ACKNOWLEDGE (5)
MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY (6)
MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE (7)
MODBUS_EXCEPTION_MEMORY_PARITY (8)
MODBUS_EXCEPTION_NOT_DEFINED (9)
MODBUS_EXCEPTION_GATEWAY_PATH (10)
MODBUS_EXCEPTION_GATEWAY_TARGET (11)
需要初始请求请求来构建有效响应。
3 示例
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

错误处理

libmodbus函数使用POSIX系统上的标准约定来处理错误。一般来说,这意味着在失败时,libmodbus函数将返回NULL值(如果返回指针)或负数(如果返回整数),并且实际的错误代码将存储在errno变量中。
modbus_strerror()函数用于将libmodbus特有的错误码转换为错误消息字符串;
具体请参见modbus_strerror(3)。

0 链接  https://libmodbus.org/docs/v3.1.4/modbus_strerror.html
1 函数原型
const char *modbus_strerror(int errnum);
2 函数介绍
modbus_strerror()函数将返回一个指向错误消息字符串的指针,该字符串对应于errnum参数指定的错误号。由于libmodbus在操作系统定义的错误号之上定义了更多的错误号,应用程序应该优先使用modbus_strerror()而不是标准的strerror()函数。
3 示例
if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    abort();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

参考

1、libmodbus官方
2、libmodbus源码
3、libmodbus官方手册中文翻译
4、Qt-libmodbus
5、在windows平台上使用Qt和libmodbus库实现modbus主机功能
6、QtCreator中直接在项目中使用libmodbus源码
7、ubuntu下libmodbus库的使用
8、libmodbus(7) Manual Page
9、Modbus wiki
10、libmodbus 源码分析(1)基本框架、关键数据结构、接口
11、libmodbus源码分析(2)主机(客户端)功能源码分析
12、libmodbus源码分析(3)从机(服务端)功能源码分析

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/971436
推荐阅读
  

闽ICP备14008679号