Modbus学习记录(3)

这篇具有很好参考价值的文章主要介绍了Modbus学习记录(3)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文只列举了常用的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。文章来源地址https://www.toymoban.com/news/detail-403883.html

到了这里,关于Modbus学习记录(3)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • git 常用命令学习记录

    git缩写参数介绍,所有命令都可以添加此参数 初始化 配置 增加删除文件 代码提交 标签命令 分支命令 远程同步 解决提交拉取的时候输入密码问题 撤销

    2024年02月15日
    浏览(40)
  • 多示例学习 (multi-instance learning, MIL) 学习路线 (归类、重点文章列举、持续更新)

    说明 :本文在于能够让大家能够更加快速地了解MIL这个领域,因此将从以下几个方面重点介绍MIL (这里不详细介绍每一篇文章,只做概述)。 注1 :欢迎和我进一步交流,可以加入我建立的QQ群 (2024年1月15日建立,没啥人hhh); 注2 :如果给出的文章包含代码,可以点击其名称缩

    2024年01月18日
    浏览(90)
  • 深度学习Pytorch常用api详解记录

    对象 :给定的序列化张量,即 Tensor 型。 功能 :实现两个张量在指定维度上的拼接。 输出 :拼接后的张量。 函数以及参数 : torch.cat( tensor , dim ) ,官方给出的有四个参数,但是我们平时只会用到前两个参数即可。 tensor :有相同形状的张量序列,所有的张量需要有相同的

    2024年02月09日
    浏览(44)
  • 网页设计学习记录-常用圆角按钮css

    效果图

    2024年02月07日
    浏览(36)
  • Modbus通讯协议常用功能码解释

     Modbus是一种单主站的主/从通讯模式。Modbus网络上只有一个主站,主站在Modbus网络上没有地址,从站的地址范围为0-247,其中0为广播地址,从站的实际地址范围为1-247。 代码 名称 作用 01 读取线圈状态 取得一组逻辑线圈的当前状态(ON/OFF) 02 读取输入状态 取得一组开关输入

    2023年04月08日
    浏览(45)
  • Mybatis - 常用 SQL 语句设计思路及具体实现 - 学习记录

    使用 Mybatis,那么在 xml 文件内,最好 不要使用任何的注释符号 ,否则会报错 Could not set parameters for mapping解决方法 xml文件内有注释符号导致的 补充提醒: 因为批量操作会拼接成很长很长的mysql语句,所以mysql server在接收数据包的时候,对这个数据包的大小是有设置项限制的

    2024年02月09日
    浏览(39)
  • 通过modbus tcp 和台达PLC通信测试记录

    安装台达梯形图软件 “WPLSoft” http://downloadcenter.delta-china.com.cn/DownloadCenter?v=1q=WPLsort_expr=cdatesort_dir=DESC 2.硬件连接 2.1 电脑网卡 连接PLC以太网, IP设为192.168.1.x网段,PLC默认IP为192.168.1.5. 2.2 PLC 供电24V, S/S输入公共端接GND,UP0/ZP0输出驱动电源的端口接GND / 24V 2.3 在 PLC X0输入触

    2024年02月08日
    浏览(49)
  • S7-1200PLC Modbus通信踩坑记录

    先放结论,两个大坑: 1.数据地址加4万或40万,来帮助PLC确定Modbus功能代码; 2.和某些设备通信时,需要给数据地址+1。 本文内容 :帮读者找到通信失败的原因,不是完整的教程。 硬件设备 :CPU1212C,485通信模块CM1241,Modbus从机(比如变送器,变频器)。 编程软件 :TIA P

    2024年02月04日
    浏览(56)
  • 学习记录: requests 不同请求方式传参和常用的方法

    requests.Request(url) 构造一个请求,支持以下各种方式 requests.get() 发送get请求 requests.post() 发送post请求 requests.head() 获取HTML的头部信息 requests.put() 发送put请求 requests.patch() 提交局部修改的请求 requests.delete() 提交删除请求 语法构造 requests.get(url,params=None) 参数说明 url:需要爬取的

    2024年02月09日
    浏览(41)
  • 通过Python连接 modbus tcp 和台达PLC通信测试记录

    安装台达梯形图软件 “WPLSoft” http://downloadcenter.delta-china.com.cn/DownloadCenter?v=1q=WPLsort_expr=cdatesort_dir=DESC 2.硬件连接 2.1 电脑网卡 连接PLC以太网, IP设为192.168.1.x网段,PLC默认IP为192.168.1.5. 2.2 PLC 供电24V, S/S输入公共端接GND,UP0/ZP0输出驱动电源的端口接GND / 24V 2.3 在 PLC X0输入触

    2024年01月23日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包