本文只列举了常用的API,其他的API参考官方API文档:https://libmodbus.org/docs/v3.1.4/
初始化相关API
modbus_new_rtu()
modbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);
功能: 函数应该分配和初始化一个modbus_t结构,以便在串行线上以RTU模式通信。
参数:
- device:参数指定操作系统处理的串口的名称,例如。“/ dev / ttyS0”或“/ dev /
ttyUSB0”。 - baud:指定通信的波特率,例如。9600、19200、57600、115200等
- parity:奇偶校验参数可以有以下值之一: N没有 E为偶校验 O为奇校验
- data_bits参数指定数据的位数,允许的值为5、6、7和8。
- stop_bits参数指定stop的位,允许的值是1和2。
一旦modbus_t结构被初始化,你必须用modbus_set_slave(3)设置你的设备的从机,并用modbus_connect(3)连接到串行总线。
返回值: 如果成功,函数将返回一个指向modbus_t结构体的指针。否则,它将返回NULL并将errno设置为EINVAL(给出了一个无效参数)
例子:
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;
}
modbus_new_tcp()
modbus_t *modbus_new_tcp(const char *ip, int port);
功能: modbus_new_tcp()函数应该分配和初始化一个modbus_t结构体来与Modbus TCP IPv4服务器通信。
参数:
- ip指定客户端想要建立连接的服务器的ip地址。NULL值可以用来监听服务器模式下的任何地址。
- port参数是要使用的TCP端口。将端口设置为MODBUS_TCP_DEFAULT_PORT,使用默认的502端口。使用大于或等于1024的端口号很方便,因为它不需要拥有管理员权限。
返回: 如果成功,函数将返回一个指向modbus_t结构体的指针。否则,它将返回NULL并将errno设置为EINVAL(An invalid IP address was given.)
例子:
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;
}
modbus_new_tcp_pi()
modbus_t *modbus_new_tcp_pi(const char *node, const char *service);
功能: 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的端口号是很方便的,因为它不需要拥有管理员权限。
返回: 如果成功,函数将返回一个指向modbus_t结构体的指针。否则,它将返回NULL并将errno设置为EINVAL(节点字符串为空或已被截断。服务字符串为空或已被截断)。
例子:
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;
}
连接相关API
建立和关闭与Modbus设备的连接提供以下功能:
modbus_connect()
int modbus_connect(modbus_t *ctx);
功能: 函数应该使用参数中给出的libmodbus上下文信息建立到Modbus服务器、网络或总线的连接。
参数: ctx:指向modbus_t结构体的指针
返回: 如果成功,函数将返回0。否则,它将返回-1,并将errno设置为底层平台的系统调用定义的值之一。
例子:
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()
void modbus_close(modbus_t *ctx);
功能: 函数应该关闭与上下文中设置的后端建立的连接。
参数: ctx:指向modbus_t结构体的指针
无返回值
例子:
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);
modbus_flush()
int modbus_flush(modbus_t *ctx);
功能: 函数将丢弃接收到的数据,但不将数据读到套接字或与上下文ctx相关的文件描述符中。
参数: ctx:指向modbus_t结构体的指针
返回: 如果成功,函数将返回0或刷新的字节数。否则返回-1并设置errno。
Client/Master中的相关API
modbus_read_bits()
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
功能: modbus_read_bits()函数将从远端设备的地址addr开始读取数量为nb的bits(线圈)的状态。
参数:
- ctx:指向modbus_t结构体的指针
- addr:要读取的远端设备的起始地址
- nb:读取的线圈数量
- dest:读取的结果以无符号字节(8位)的形式存储在dest数组中
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint8_t))。 该功能使用Modbus功能码0x01(读取线圈状态)。 返回: 如果成功,函数将返回读取的位数。否则返回-1并设置errno。 错误:EMBMDATA(请求的位太多)
例子:
addr = ADDRESS_START;
ret = modbus_write_bits(ctx, addr,nums, tab_rq_bits);
if (nums != ret)
{
printf("Error modbus_write_bit: %d\n", ret);
printf("Address: %d value: %d\n", addr, tab_rq_bits[0]);
}
modbus_read_input_bits()
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
功能: modbus_read_bits()函数将从远端设备的地址addr开始读取数量为nb的bits(输入离散量)的状态。
参数:
- ctx:指向modbus_t结构体的指针
- addr:要读取的远端设备的起始地址
- nb:读取的输入离散量数量
- dest:读取的结果以无符号字节(8位)的形式存储在dest数组中
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint8_t))。 该功能使用Modbus功能码0x02(读取输入离散量状态)。
返回: 如果成功,函数将返回读取的位数。否则返回-1并设置errno。 错误:EMBMDATA(请求的位太多)
modbus_read_registers()
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
功能: 函数将从远端设备的地址addr开始读取数量为nb的保持寄存器的内容。
参数:
- ctx:指向modbus_t结构体的指针
- addr:要读取的远端设备的起始地址
- nb:读取的保持寄存器数量
- dest:读取结果以字值(16位)的形式存储在dest数组中。
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint16_t))。 该函数使用Modbus函数代码0x03(读取保持寄存器)。
返回: 如果成功,函数将返回读取的位数。否则返回-1并设置errno。 错误:EMBMDATA(请求的位太多)
例子:
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);
modbus_read_input_registers()
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
功能: 函数将从远端设备的地址addr开始读取数量为nb的输入寄存器的内容。
参数:
- ctx:指向modbus_t结构体的指针
- addr:要读取的远端设备的起始地址
- nb:读取的输入寄存器数量
- dest:读取结果以字值(16位)的形式存储在dest数组中。
你必须注意分配足够的内存来存储结果在dest(至少nb * sizeof(uint16_t))。 该函数使用Modbus函数代码0x04(读取输入寄存器)。持有寄存器和输入寄存器有不同的历史意义,但现在更常见的是只使用保持寄存器。
返回: 如果成功,函数将返回读取的位数。否则返回-1并设置errno。 错误:EMBMDATA(请求的位太多)
modbus_write_bit()
int modbus_write_bit(modbus_t *ctx, int addr, int status);
功能: 函数将单个线圈状态写入远端设备的地址addr。
参数:
- ctx:指向modbus_t结构体的指针
- addr:要读取的远端设备的起始地址
- status:开关量 0或1
该函数使用Modbus函数代码0x05(强制单线圈)。
返回: 如果成功,函数将返回1。否则返回-1并设置errno。
modbus_write_register()
int modbus_write_register(modbus_t *ctx, int addr, int value);
功能: 函数的作用是:将保存值寄存器的值写入远端设备的地址addr。
参数:
- ctx:指向modbus_t结构体的指针
- addr:要读取的远端设备的起始地址
- status:要写入的字数据(16位)
该函数使用Modbus函数代码0x06(预设单寄存器)。
返回: 如果成功,函数将返回1。否则返回-1并设置errno。
modbus_write_bits()
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);
功能: 函数将从src写入远端设备地址addr的nb个bits(线圈)的状态。
参数: src数组必须包含设置为TRUE或FALSE的字节。 该函数使用Modbus函数代码0x0F(写多个线圈)。
返回: 如果成功,函数将返回写入的位数。否则返回-1并设置errno。
modbus_write_registers()
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);
功能: 函数的作用是:从远端设备的地址addr的数组src中写入nb持有寄存器的内容。
参数:
- ctx:指向modbus_t结构体的指针
- addr:要写入的远端设备的起始地址
- nb:写入的保持寄存器数量
- dest:写入的数据以字值(16位)的形式存储在dest数组中。
该函数使用Modbus函数代码0x10(写多个保持寄存器)。
返回: 如果成功,函数将返回写入的位数。否则返回-1并设置errno。
Server/Slave中的相关API
modbus_tcp_listen()
int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
功能:函数应该创建一个套接字并监听指定IP地址上的最大nb_connection传入连接。
参数:
- ctx:必须是已经被分配并使用modbus_new_tcp(3)初始化的才能设置监听的IP地址,如果IP地址设置为NULL,则任何地址都将被监听。
- nb_connection:最大连接个数
返回: 如果成功,函数将返回一个新的套接字。否则返回-1并设置errno。
modbus_tcp_accept()
int modbus_tcp_accept(modbus_t *ctx, int *socketfd);
功能: 函数将提取挂起连接队列中的第一个连接,创建一个新的套接字并将其存储在参数中给出的libmodbus上下文中。如果可用,将调用带有SOCK_CLOEXEC的accept4(),而不是accept()。 参数:
- ctx:已分配的modbus_t结构体。
- socketfd:连接队列中的第一个套接字指针
返回: 如果成功,函数将返回一个新的套接字。否则返回-1并设置errno。
例子:
...
ctx = modbus_new_tcp("127.0.0.1", 502);
s = modbus_tcp_listen(ctx, 1);
modbus_tcp_accept(ctx, &s);
...
close(s)
modbus_free(ctx);
modbus_mapping_new()
modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers);
功能:函数应该分配四个数组来存储位、输入位、寄存器和输入寄存器。指针存储在modbus_mapping_t结构中。数组中的所有值都初始化为0。 这个函数相当于调用modbus_mapping_new_start_address()函数,所有起始地址都为0。 如果不需要为特定类型的数据分配数组,则可以在参数中传递零值,相关指针将为NULL。 这个函数是方便处理请求在ModbusServer/Slave。
参数: nb_bits:存放线圈寄存器需要的内存大小 nb_input_bits:存放离散输入寄存器需要的内存大小 nb_registers:存放保持寄存器需要的内存大小 nb_input_registers:存放输入寄存器需要的数据大小
返回: 如果成功,函数将返回新分配的结构体指针。否则返回NULL并设置errno。
modbus_mapping_free()
void modbus_mapping_free(modbus_mapping_t *mb_mapping);
功能: 该函数将释放mb_mapping_t结构的四个数组,最后释放mb_mapping_t指针。
参数: mb_mapping:modbus_mapping_new()返回的结构体指针。
无返回值
modbus_receive()
int modbus_receive(modbus_t *ctx, uint8_t *req);
功能: 函数将从ctx的套接字接收一个指示请求。Modbus从机/服务器接收和分析主机/客户端发送的指示请求。
参数:
- ctx:已经建立连接的modbus_t结构体指针
- req:获取到的请求ADU队列
返回: 函数将指示请求存储在req中,如果成功则返回请求长度。如果指示请求被忽略,返回的请求长度可以为0。(例如在RTU模式下查询另一个slave)。否则返回-1并设置errno。
modbus_reply()
int modbus_reply(modbus_t *ctx, const uint8_t *req, int req_length, modbus_mapping_t *mb_mapping);
功能: 函数将对收到的请求发送响应。对参数中给出的请求req进行分析,然后通过modbus上下文ctx的信息构建并发送响应。 如果请求指示读或写一个值,操作将根据操作数据的类型在modbus映射mb_mapping中完成。 如果发生错误,将发送异常响应。 本功能是针对Modbus服务器设计的。
参数:
- ctx:已经建立连接的modbus_t结构体指针
- req:modbus_receive从ctx的套接字接收到的指示请求
- req_length:req的长度,一般就是modbus_receive()的返回值
- mb_mapping:modbus_mapping_new()分配的map结构体指针
返回: 如果成功,函数将返回响应的长度。否则返回-1并设置errno。
通用的相关API
modbus_free()
void modbus_free(modbus_t *ctx);
功能: 函数的作用是释放一个已分配的modbus_t结构体。
参数: 已分配的modbus_t结构体。
无返回值
modbus_set_slave()
int modbus_set_slave(modbus_t *ctx, int slave);
功能: modbus_set_slave()函数将在libmodbus上下文中设置从机号。
参数: 这种行为取决于网络和设备的角色: RTU 定义远端设备在主模式下通话的从机ID,或者在从模式下设置内部从机ID。根据协议,Modbus设备必须只接受持有其从机号或特殊广播号的消息。 TCP 只有当消息必须到达串行网络上的设备时,从机号才需要在TCP中。但没有从机值,故障的远端设备或软件将丢弃请求!特殊值MODBUS_TCP_SLAVE (0xFF)可以在TCP模式下使用,使用默认值。 广播地址为“MODBUS_BROADCAST_ADDRESS”。当您希望网络中的所有Modbus设备都接收到请求时,必须使用这个特殊值。
返回值: 如果成功,函数将返回0。否则,它将返回-1并将errno设置为EINVAL(设置了错误的从机号)
例子:
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;
}
modbus_set_debug()
int modbus_set_debug(modbus_t *ctx, int flag);
功能: modbus_set_debug()函数应该通过使用参数标志来设置modbus_t上下文的调试标志。
参数:
- ctx:指向modbus_t结构体的指针
- flag:默认情况下,布尔标志设置为FALSE。当标志值设置为TRUE时,许多详细消息将显示在stdout和stderr上。例如,该标志用于显示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>
返回: 如果成功,函数将返回0。否则返回-1并设置errno。
|