【modbus协议】libmodbus库移植基于linux平台

文章目录

  • 下载库函数源码
  • 编译路径添加
  • libmodbus 源码分析
    • 核心数据结构
    • 常用接口函数
  • 开发 TCP Server 端
  • 开发TCP Client 端

下载库函数源码

在这里插入图片描述

编译路径添加

在这里插入图片描述
在这里插入图片描述

libmodbus 源码分析

核心数据结构

  • modbus_t结构体:
    这是 libmodbus 的核心数据结构,代表一个 Modbus 上下文。它包含了与 Modbus 通信相关的各种信息,如通信方式(串口或 TCP)、设备地址、端口号等。
struct _modbus {/* Slave address */// 存储 Modbus 从设备地址。在 Modbus 通信中,主设备通过指定从设备地址来与特定的从设备进行通信。int slave;/* Socket or file descriptor */// 存储套接字描述符或文件描述符。根据通信方式的不同,这个值可以是一个套接字描述符(用于 TCP 通信)或文件描述符(用于串口通信)。int s;// 调试标志。如果设置为非零值,表示启用调试模式,可以输出更多的调试信息。int debug;// 错误恢复标志。用于指示是否启用错误恢复机制,例如在通信出现错误时尝试重新连接或采取其他恢复措施。int error_recovery;// 响应超时时间。这是一个结构体 timeval,用于指定在等待从设备响应时的超时时间。如果在这个时间内没有收到响应,将认为通信出现错误。struct timeval response_timeout;// 字节超时时间。同样是一个结构体 timeval,用于指定在接收单个字节时的超时时间。如果在这个时间内没有接收到下一个字节,也将认为通信出现错误。struct timeval byte_timeout;// 指示超时时间。这个超时时间的具体用途可能因实现而异,可能用于等待某些特定的指示或事件。struct timeval indication_timeout;// 指向特定后端实现的指针。Modbus 库可能支持多种不同的通信后端,例如不同的操作系统或硬件平台。这个指针指向相应的后端实现结构体。const modbus_backend_t *backend;// 后端数据指针。用于存储特定于后端实现的数据。不同的后端可能需要不同的数据结构来存储其特定的状态信息。void *backend_data;
};
  • modbus_mapping_t
    用于映射 Modbus 寄存器和线圈的数据结构。它包含了输入寄存器、输出寄存器、输入线圈和输出线圈的内存映射,方便开发者在应用程序中访问和操作 Modbus 设备的数据
typedef struct _modbus_mapping_t {int nb_bits;// 表示映射的线圈(位)的总数。在 Modbus 协议中,线圈通常用于表示离散的开/关状态。int start_bits;// 映射的线圈的起始地址。这是相对于 Modbus 地址空间的起始位置。int nb_input_bits;// 表示映射的离散输入(只读位)的总数。离散输入通常用于反映外部设备的状态,不能被写入。int start_input_bits;// 映射的离散输入的起始地址。同样是相对于 Modbus 地址空间的起始位置。int nb_input_registers;// 表示映射的输入寄存器的总数。输入寄存器通常用于存储只读的 16 位数据,例如传感器的测量值。int start_input_registers;// 映射的输入寄存器的起始地址。在 Modbus 地址空间中的起始位置。int nb_registers;// 表示映射的保持寄存器的总数。保持寄存器可用于存储可读可写的 16 位数据,通常用于配置参数或存储设备状态。int start_registers;// 映射的保持寄存器的起始地址。相对于 Modbus 地址空间的起始位置。uint8_t *tab_bits;// 指向一个字节数组的指针,用于存储线圈(位)的状态。每个字节可以表示 8 个位的状态。uint8_t *tab_input_bits;// 指向一个字节数组的指针,用于存储离散输入(只读位)的状态。同样每个字节可以表示 8 个位的状态。uint16_t *tab_input_registers;// 指向一个 16 位无符号整数数组的指针,用于存储输入寄存器的值。uint16_t *tab_registers;// 指向一个 16 位无符号整数数组的指针,用于存储保持寄存器的值。
} modbus_mapping_t;
  • modbus_backend_t:
typedef struct _modbus_backend {unsigned int backend_type;// 表示后端的类型标识。可能用于区分不同的通信方式(如串口、TCP 等)或特定的实现。unsigned int header_length;// 表示通信协议头部的长度。不同的通信方式可能有不同长度的头部信息。unsigned int checksum_length;// 表示校验和的长度。用于确定在通信中使用的校验和数据的长度。unsigned int max_adu_length;// 表示最大应用数据单元(Application Data Unit,ADU)的长度。ADU 是 Modbus 协议中在通信中传输的数据单元。int (*set_slave) (modbus_t *ctx, int slave);// 这是一个函数指针,用于设置 Modbus 从设备地址。接收一个指向 modbus_t 结构体的指针和一个整数表示从设备地址,返回一个整数表示操作的结果状态。int (*build_request_basis) (modbus_t *ctx, int function, int addr,int nb, uint8_t *req);// 函数指针,用于构建基本的请求。接收 modbus_t 结构体指针、功能码、地址、数量和一个指向请求数据的指针,返回一个整数表示操作的结果状态。int (*build_response_basis) (sft_t *sft, uint8_t *rsp);// 函数指针,用于构建基本的响应。接收一个指向特定结构体的指针和一个指向响应数据的指针,返回一个整数表示操作的结果状态。int (*prepare_response_tid) (const uint8_t *req, int *req_length);// 函数指针,用于准备带有事务标识符的响应。接收一个指向请求数据的指针和一个指向请求长度的指针,返回一个整数表示操作的结果状态。int (*send_msg_pre) (uint8_t *req, int req_length);// 函数指针,在发送消息之前执行一些预处理操作。接收一个指向请求数据的指针和请求长度,返回一个整数表示操作的结果状态。ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);// 函数指针,用于发送数据。接收一个指向 modbus_t 结构体的指针、指向请求数据的指针和请求长度,返回实际发送的字节数。int (*receive) (modbus_t *ctx, uint8_t *req);// 函数指针,用于接收数据。接收一个指向 modbus_t 结构体的指针和一个指向接收缓冲区的指针,返回一个整数表示操作的结果状态。ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);// 函数指针,用于接收特定长度的数据。接收一个指向 modbus_t 结构体的指针、指向响应数据的指针和响应长度,返回实际接收的字节数。int (*check_integrity) (modbus_t *ctx, uint8_t *msg,const int msg_length);// 函数指针,用于检查消息的完整性。接收一个指向 modbus_t 结构体的指针、指向消息数据的指针和消息长度,返回一个整数表示消息是否完整。int (*pre_check_confirmation) (modbus_t *ctx, const uint8_t *req,const uint8_t *rsp, int rsp_length);// 函数指针,在检查确认之前执行一些预处理操作。接收一个指向 modbus_t 结构体的指针、指向请求数据的指针、指向响应数据的指针和响应长度,返回一个整数表示操作的结果状态。int (*connect) (modbus_t *ctx);// 函数指针,用于建立连接。接收一个指向 modbus_t 结构体的指针,返回一个整数表示连接操作的结果状态。void (*close) (modbus_t *ctx);// 函数指针,用于关闭连接。接收一个指向 modbus_t 结构体的指针,无返回值。int (*flush) (modbus_t *ctx);// 函数指针,用于刷新缓冲区。接收一个指向 modbus_t 结构体的指针,返回一个整数表示操作的结果状态。int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);// 函数指针,用于执行 select 操作。接收一个指向 modbus_t 结构体的指针、一个文件描述符集合指针、一个时间结构指针和消息长度,返回一个整数表示操作的结果状态。void (*free) (modbus_t *ctx);// 函数指针,用于释放资源。接收一个指向 modbus_t 结构体的指针,无返回值。
} modbus_backend_t;

常用接口函数

以下是对 libmodbus 库常用接口函数的详细介绍:

一、创建和释放上下文

  1. modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit)

    • 功能:创建一个用于 Modbus RTU 通信的上下文。
    • 参数:
      • device:串口设备名称,例如 “/dev/ttyS0”。这是与 Modbus 设备进行通信的物理串口设备的路径。
      • baud:波特率,常见的值有 9600、19200 等。决定了数据在串口上传输的速度。
      • parity:校验位,‘N’ 表示无校验,‘E’ 表示偶校验,‘O’ 表示奇校验。用于检测数据传输中的错误。
      • data_bit:数据位数,通常为 7 或 8。表示每个数据字节中的有效数据位数。
      • stop_bit:停止位数,常见的值为 1 或 2。用于标识一个数据帧的结束。
    • 返回值:如果创建成功,返回一个指向 modbus_t 结构体的指针,该结构体代表创建的 Modbus 上下文;如果创建失败,返回 NULL
  2. modbus_new_tcp(const char *ip_address, int port)

    • 功能:创建一个用于 Modbus TCP 通信的上下文。
    • 参数:
      • ip_address:服务器 IP 地址,例如 “192.168.1.100”。指定要连接的 Modbus TCP 服务器的 IP 地址。
      • port:端口号,通常为 502。这是 Modbus TCP 通信使用的端口号。
    • 返回值:如果创建成功,返回一个指向 modbus_t 结构体的指针,该结构体代表创建的 Modbus 上下文;如果创建失败,返回 NULL
  3. modbus_free(modbus_t *ctx)

    • 功能:释放 Modbus 上下文占用的资源。
    • 参数:
      • ctx:指向要释放的 modbus_t 结构体的指针。这个指针是之前通过 modbus_new_rtumodbus_new_tcp 创建的 Modbus 上下文。
    • 返回值:无。

二、设置参数

  1. modbus_set_slave(modbus_t *ctx, int slave)

    • 功能:设置 Modbus 从设备地址。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • slave:从设备地址,通常是一个整数,范围在 1 到 247 之间。在 Modbus 网络中,每个设备都有一个唯一的地址,主设备通过这个地址来与特定的从设备进行通信。
    • 返回值:无。
  2. modbus_set_debug(modbus_t *ctx, int debug)

    • 功能:设置调试模式。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • debug:非零值表示开启调试模式,零表示关闭调试模式。当开启调试模式时,库可能会输出更多的调试信息,帮助开发者诊断问题。
    • 返回值:无。

三、连接和断开连接

  1. modbus_connect(modbus_t *ctx)

    • 功能:建立与 Modbus 设备的连接。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
    • 返回值:如果连接成功,返回 0;如果连接失败,返回 -1。
  2. modbus_close(modbus_t *ctx)

    • 功能:关闭与 Modbus 设备的连接。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
    • 返回值:无。

四、读取数据

  1. modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)

    • 功能:读取线圈状态。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • addr:起始地址,线圈在 Modbus 地址空间中的位置。
      • nb:要读取的线圈数量。
      • dest:存储读取结果的缓冲区。这个缓冲区应该足够大,以存储 nb 个线圈的状态。每个线圈的状态用一个字节中的一位表示,0 表示关闭,1 表示打开。
    • 返回值:如果读取成功,返回读取的字节数;如果读取失败,返回 -1。
  2. modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)

    • 功能:读取离散输入状态。
    • 参数和返回值与 modbus_read_bits 类似,但离散输入是只读的,不能被写入。
  3. modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)

    • 功能:读取保持寄存器的值。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • addr:起始地址,保持寄存器在 Modbus 地址空间中的位置。
      • nb:要读取的寄存器数量。
      • dest:存储读取结果的缓冲区。这个缓冲区应该足够大,以存储 nb 个 16 位的寄存器值。
    • 返回值:如果读取成功,返回读取的字节数(通常是 nb 乘以 2);如果读取失败,返回 -1。
  4. modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)

    • 功能:读取输入寄存器的值。
    • 参数和返回值与 modbus_read_registers 类似,但输入寄存器也是只读的。

五、写入数据

  1. modbus_write_bit(modbus_t *ctx, int addr, int status)

    • 功能:写入单个线圈状态。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • addr:地址,要写入的线圈在 Modbus 地址空间中的位置。
      • status:0 表示关闭线圈,非零值表示打开线圈。
    • 返回值:如果写入成功,返回 1;如果写入失败,返回 -1。
  2. modbus_write_register(modbus_t *ctx, int addr, int value)

    • 功能:写入单个保持寄存器的值。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • addr:地址,要写入的保持寄存器在 Modbus 地址空间中的位置。
      • value:要写入的值,一个 16 位的整数。
    • 返回值:如果写入成功,返回 1;如果写入失败,返回 -1。
  3. modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data)

    • 功能:写入多个线圈状态。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • addr:起始地址,要写入的第一个线圈在 Modbus 地址空间中的位置。
      • nb:要写入的线圈数量。
      • data:存储要写入的线圈状态的缓冲区。这个缓冲区中的每个字节表示 8 个线圈的状态,0 表示关闭,1 表示打开。
    • 返回值:如果写入成功,返回写入的字节数;如果写入失败,返回 -1。
  4. modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data)

    • 功能:写入多个保持寄存器的值。
    • 参数:
      • ctx:指向 Modbus 上下文的指针。
      • addr:起始地址,要写入的第一个保持寄存器在 Modbus 地址空间中的位置。
      • nb:要写入的寄存器数量。
      • data:存储要写入的值的缓冲区。这个缓冲区中的每个元素都是一个 16 位的整数,表示要写入的保持寄存器的值。
    • 返回值:如果写入成功,返回写入的字节数(通常是 nb 乘以 2);如果写入失败,返回 -1。

开发 TCP Server 端

待补充

开发TCP Client 端

待补充

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58089.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OSPF特殊区域及其他特性

不用的链路这状态信息没必要一直保存,要不路由器承受不了。用OSPF 特殊区域解决 1. Stub区域和Totally Stub区域 R1作为ASBR引入多个外部网段,如果Area 2是普通区域,则R3将向该区域注入5类和4类LSA。 当把Area 2配置为Stub区域后&#xff1a…

node升级package.json中的版本

由于项目使用时间过老,升级对应包版本,可以使用新功能 1.使用npm-check-updates这个工具,先全局安装 npm install -g npm-check-updates2.检查package.json中dependencies的最新版本 ncu3.更新dependencies到新版本 ncu -u也是一样的 npx…

探索Python安全字符串处理的奥秘:MarkupSafe库揭秘

文章目录 探索Python安全字符串处理的奥秘:MarkupSafe库揭秘第一部分:背景介绍第二部分:MarkupSafe是什么?第三部分:如何安装MarkupSafe?第四部分:MarkupSafe的简单使用方法1. 使用escape函数2.…

机器视觉运动控制一体机在DELTA并联机械手视觉上下料应用

市场应用背景 DELTA并联机械手是由三个相同的支链所组成,每个支链包含一个转动关节和一个移动关节,具有结构紧凑、占地面积小、高速高灵活性等特点,可在有限的空间内进行高效的作业,广泛应用于柔性上下料、包装、分拣、装配等需要…

【C++】类和对象(二):this指针

大家好,我是苏貝,本篇博客带大家了解C的this指针,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 目录 1 this指针的引出2 this指针的特性 1 this指针的引出 我们先来定义一个日期类Date 问&am…

华为原生鸿蒙操作系统的发布有何重大意义和影响:

#1024程序员节 | 征文# 一、华为原生鸿蒙操作系统的发布对中国的意义可以从多个层面进行分析: 1. 技术自主创新 鸿蒙操作系统的推出标志着中国在操作系统领域的自主创新能力的提升。过去,中国在高端操作系统方面依赖于外国技术,鸿蒙的发布…

开发涉及的安全规范整理

文章目录 前言安全场景与措施API调用方式鉴权参数校验日志打印数据保存加密 总结 前言 这篇文章我们来整理下写代码和方案设计中的安全规范问题,内容偏服务端,即使是入门的新人,如果你对安全有所了解会让成熟规范的团队对你高看一眼。安全经常…

用HTML构建酷炫的文件上传下载界面

1. 基础HTML结构 首先&#xff0c;我们构建一个基本的HTML结构&#xff0c;包括一个表单用于文件上传&#xff0c;以及一个列表用于展示已上传文件&#xff1a; HTML <!DOCTYPE html> <html> <head><title>酷炫文件上传下载</title><link …

健康养生的重要性

养生之道&#xff0c;健康相随 在快节奏的现代生活中&#xff0c;养生健康已成为我们不可忽视的话题。随着生活水平的提高&#xff0c;人们越来越注重身体的保养与健康的维护。那么&#xff0c;如何才能做到养生健康&#xff0c;让身体与心灵都得到滋养呢&#xff1f; 首先&a…

鱼跃医疗助力退役军人事务部“高原情暖老兵项目”

10月17日-22日&#xff0c;在退役军人事务部指导下&#xff0c;中国老龄事业发展基金会联合腾讯SSV时光实验室、腾讯天籁实验室等机构发起的“情暖老兵&#xff0c;守望相助—老兵听力关怀计划”项目走进西藏&#xff0c;为退伍老兵提供听力健康筛查服务。西藏鱼跃医疗投资有限…

fastGpt

参考本地部署FastGPT使用在线大语言模型 1 rockylinx 1 ollama安装 在rockylinux中安装的&#xff0c;ollama由1.5G&#xff0c;还是比较大&#xff0c;所有采用在windows下下载&#xff0c;然后安装的方式&#xff0c;linux安装 tar -C /usr -xzf ollama-linux-amd64.tgz #…

U-net医学分割网络——学习笔记

《U-Net: Convolutional Networks for Biomedical Image Segmentation》 一、提出背景 U-Net 的提出是为了解决生物医学图像分割的几个关键问题&#xff1a;需要像素级的精确分割、标注数据稀缺、滑动窗口方法效率低以及多尺度特征融合的需求。U-Net 通过对称的 U 型全卷积结…

Redis+Lua限流的四种算法

1. 固定窗口&#xff08;Fixed Window&#xff09; 原理&#xff1a; 固定窗口算法将时间划分为固定的时间段&#xff08;窗口&#xff09;&#xff0c;比如 1 秒、1 分钟等。在每个时间段内&#xff0c;允许最多一定数量的请求。如果请求超出配额&#xff0c;则拒绝。 优点…

【linux网络编程】| 网络套接字socket | 初识网络开发

前言&#xff1a;本篇内容将要正式进入网络的编程当中。 本篇的目的是为了能够看完就可以上手写一些网络代码了。 但是本篇也并不会单纯的只讲接口&#xff0c; 前面还是会铺垫一些理论知识更好的认识网络传输。下面&#xff0c; 开始我们的学习吧! ps&#xff1a;本篇内容的某…

摄像头点击器常见问题——摄像头视窗打开慢

【嵌入式开发】可编程4k蓝牙摄像头点击器_能编程的摄像头-CSDN博客 拥有上述文章产品的朋友出现标题所述问题&#xff0c;可继续往下阅读 出现以上问题&#xff0c;摄像头画面打开较慢&#xff0c;可以按以下操作进行设置 在环境变量里设置一下这个参数&#xff0c;值设置为1&…

美国超大型数据泄露事件曝光:超1亿人数据被盗

联合健康&#xff08;UnitedHealth&#xff09;首次证实&#xff0c;在 Change Healthcare 勒索软件攻击中&#xff0c;有超过 1 亿人的个人信息和医疗保健数据被盗&#xff0c;这是近年来最大的医疗保健数据泄露事件。 今年 5 月&#xff0c;UnitedHealth 首席执行官安德鲁-威…

深入理解gPTP时间同步过程

泛化精确时间协议(gPTP)是一个用于实现精确时间同步的协议,特别适用于分布式系统中需要高度协调的操作,比如汽车电子、工业自动化等。 gPTP通过同步主节点(Time Master)和从节点(Time Slave)的时钟,实现全局一致的时间参考。 以下是gPTP实现主从时间同步的详细过程:…

Uni-App-03

登录功能开发 实现POST提交 HTTP协议规定请求消息内容类型(Content-Type)有哪些&#xff1f;—— 只有四种 text/plain 没有编码的普通数据 application/x-www-form-urlencoded 编码后的普通数据 multipart/form-data 请求主体中包含文件上传域 application/json 请求主体是 J…

基于SpringBoot的“高校校园点餐系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“高校校园点餐系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 前台首页功能界面图 用户注册、登录界面图 我…

【C++ | 数据结构】八大常用排序算法详解

1. 排序的稳定性 排序是我们生活中经常会面对的问题&#xff0c;小朋友站队的时候会按照从矮到高的顺序排列&#xff1b;老师查看上课出勤情况时&#xff0c;会按照学生的学号点名&#xff1b;高考录取时&#xff0c;会按照成绩总分降序依次录取等等。那么对于排序它是如何定义…