首页 > 其他分享 >libmodbus从机回应

libmodbus从机回应

时间:2025-01-12 20:58:45浏览次数:3  
标签:Modbus libmodbus 请求 回应 mapping modbus 响应 从机 寄存器

文章目录


一、modbus_mapping_new_start_address函数

modbus_mapping_new_start_addresslibmodbus 库中的一个函数,用于创建一个新的 modbus_mapping_t 结构体,并分配内存以存储 Modbus 数据区的映射。这些数据区包括离散输出(bits)、离散输入(input bits)、保持寄存器(registers)和输入寄存器(input registers)。这个函数通过传入的参数来定义各个数据区的起始地址和数量,并为这些数据区分配内存。

函数原型

modbus_mapping_t *modbus_mapping_new_start_address(
    unsigned int start_bits,
    unsigned int nb_bits,
    unsigned int start_input_bits,
    unsigned int nb_input_bits,
    unsigned int start_registers,
    unsigned int nb_registers,
    unsigned int start_input_registers,
    unsigned int nb_input_registers
);

参数说明

  • start_bits:离散输出(Coils)区的起始地址。
  • nb_bits:离散输出(Coils)的数量。
  • start_input_bits:离散输入(Discrete Inputs)区的起始地址。
  • nb_input_bits:离散输入(Discrete Inputs)的数量。
  • start_registers:保持寄存器(Holding Registers)区的起始地址。
  • nb_registers:保持寄存器(Holding Registers)的数量。
  • start_input_registers:输入寄存器(Input Registers)区的起始地址。
  • nb_input_registers:输入寄存器(Input Registers)的数量。

功能描述

modbus_mapping_new_start_address 的主要作用是为 modbus_mapping_t 结构体分配内存,并初始化指向这些数据区的指针。这些数据区的起始地址和数量由传入的参数决定。该函数在成功时返回一个指向 modbus_mapping_t 结构体的指针,在失败时返回 NULL,并将 errno 设置为 ENOMEM(内存不足)。

工作原理

  1. 内存分配

    • 根据每种数据区的数量(例如 nb_bits, nb_input_bits 等),该函数为每个数据区分配足够的内存空间。
    • 这些内存空间用于存储数据,例如离散输出的位、输入寄存器的值等。
  2. 初始化映射结构

    • 函数会将数据区的指针存储到返回的 modbus_mapping_t 结构体中,使得每个数据区能够通过指针直接访问。
    • 每个数据区的起始地址由用户提供,并且数据区的起始地址与 Modbus 地址的约定相对应。
  3. 返回值

    • 如果成功,返回一个指向 modbus_mapping_t 结构体的指针,用户可以通过该结构体访问和修改 Modbus 数据。
    • 如果内存分配失败,返回 NULL,并且 errno 被设置为 ENOMEM,表示内存不足。

返回结构体:modbus_mapping_t

modbus_mapping_t 结构体是一个包含多个指向数据区的指针的结构体,通常包括以下内容:

  • nb_bits:离散输出(Coils)的数量。
  • nb_input_bits:离散输入(Discrete Inputs)的数量。
  • nb_registers:保持寄存器(Holding Registers)的数量。
  • nb_input_registers:输入寄存器(Input Registers)的数量。
  • tab_bits:指向离散输出数据的指针。
  • tab_input_bits:指向离散输入数据的指针。
  • tab_registers:指向保持寄存器数据的指针。
  • tab_input_registers:指向输入寄存器数据的指针。

示例代码

#include <modbus.h>
#include <stdio.h>

int main() {
    // 创建 Modbus 映射,指定起始地址和数据区数量
    modbus_mapping_t *mb_mapping = modbus_mapping_new_start_address(
        0,  // 离散输出的起始地址
        100, // 离散输出的数量
        100, // 离散输入的起始地址
        100, // 离散输入的数量
        1,  // 保持寄存器的起始地址
        100, // 保持寄存器的数量
        0,  // 输入寄存器的起始地址
        100  // 输入寄存器的数量
    );

    if (mb_mapping == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        return -1;
    }

    // 访问映射中的数据
    mb_mapping->tab_bits[0] = 1;  // 设置第一个离散输出为 1
    mb_mapping->tab_registers[0] = 1234;  // 设置第一个保持寄存器为 1234

    // 打印一些数据
    printf("First coil: %d\n", mb_mapping->tab_bits[0]);
    printf("First register: %d\n", mb_mapping->tab_registers[0]);

    // 释放映射内存
    modbus_mapping_free(mb_mapping);

    return 0;
}

错误处理

如果内存分配失败(如系统内存不足),modbus_mapping_new_start_address 函数会返回 NULL,并将 errno 设置为 ENOMEM,用户应当检查返回值并根据需要进行错误处理。

总结

  • modbus_mapping_new_start_address 用于创建一个新的 Modbus 数据映射结构,并为各个数据区分配内存。
  • 它接受多个参数来指定数据区的起始地址和数量,这些参数将用于初始化 modbus_mapping_t 结构体。
  • 返回的结构体包含指向各个数据区的指针,用户可以用来读取和写入 Modbus 数据。
  • 内存分配失败时,函数返回 NULL,并设置 errnoENOMEM

二、modbus_reply函数

modbus_replylibmodbus 库中的一个重要函数,用于处理接收到的 Modbus 请求并发送相应的响应。该函数根据收到的请求数据构造一个响应,并通过 Modbus 协议将响应发送回客户端。若发生错误,函数将根据错误类型构造相应的错误响应。

函数原型

int modbus_reply(modbus_t *ctx,
                 const uint8_t *req,
                 int req_length,
                 modbus_mapping_t *mb_mapping);

参数说明

  • ctx:一个指向 modbus_t 类型的指针,表示 Modbus 上下文。该上下文包含与通信相关的所有设置(如端口、协议类型、从站地址等)。

  • req:指向接收到的请求数据的指针,req 是一个字节数组,包含了接收到的 Modbus 请求报文。

  • req_length:请求数据的长度,单位为字节。它告诉 modbus_reply 函数请求数据的大小。

  • mb_mapping:指向 modbus_mapping_t 类型的指针。modbus_mapping_t 是 Modbus 映射结构,包含了寄存器和位的内存映射(例如,离散输出、输入寄存器等)。此参数用于执行实际的 Modbus 数据操作。

功能描述

modbus_reply 函数的主要功能是根据接收到的 Modbus 请求,分析请求内容,构造响应并将其发送回请求方。它通过以下步骤完成操作:

  1. 分析请求

    • 解析 req 中的请求数据,确定请求的功能码、请求的目标地址、请求的寄存器地址和长度等信息。
    • 根据请求的内容,判断应该执行哪种操作(读取、写入寄存器,或是错误响应等)。
  2. 执行操作

    • 根据请求的类型,执行实际的操作。比如:
      • 读取数据:根据请求的数据类型(如离散输出、保持寄存器等),从 mb_mapping 中提取相应的数据。
      • 写入数据:根据请求的目标地址和写入的值,修改 mb_mapping 中相应的数据区。
  3. 构建响应

    • 如果请求处理成功,构建一个符合 Modbus 协议格式的响应报文。
    • 如果发生错误(如非法操作、地址越界等),则根据错误类型构建相应的错误响应。
  4. 发送响应

    • 将构建好的响应数据通过 ctx 中配置的通信通道(如串口、TCP 等)发送回客户端。

错误处理

如果在请求分析或数据处理过程中发生错误,modbus_reply 会根据错误类型构造错误响应。Modbus 错误响应的格式通常为:

  • 功能码保持不变。
  • 错误标识符会在功能码的基础上加上 0x80(例如,如果原功能码是 0x03(读取保持寄存器),则错误响应的功能码将是 0x83)。
  • 错误代码指示具体错误类型,比如地址越界、非法功能码等。

返回值

  • 如果成功,返回发送的字节数,即响应的长度。
  • 如果失败,返回 -1,表示出现了错误。

Modbus 响应格式

Modbus 响应包含以下几个部分:

  1. 功能码:与请求的功能码相同,若发生错误则将功能码加上 0x80。
  2. 字节数:响应中有效数据的字节数。
  3. 数据:响应的数据(根据请求的类型,可能是寄存器的值、离散输出的状态等)。
  4. 错误代码(如果发生错误):如非法功能码、非法数据等。

示例代码

#include <modbus.h>
#include <stdio.h>

int main() {
    // 创建 Modbus TCP 上下文
    modbus_t *ctx = modbus_new_tcp("127.0.0.1", 502);
    if (ctx == NULL) {
        fprintf(stderr, "Unable to create Modbus context\n");
        return -1;
    }

    // 创建 Modbus 映射结构,设置初始数据区
    modbus_mapping_t *mb_mapping = modbus_mapping_new_start_address(0, 100, 100, 100, 0, 100);
    if (mb_mapping == NULL) {
        fprintf(stderr, "Unable to create Modbus mapping\n");
        modbus_free(ctx);
        return -1;
    }

    // 假设我们从某种通信协议获取了请求数据
    uint8_t req[256];  // 请求数据
    int req_length = 0; // 假设请求的长度

    // 调用 modbus_reply 处理请求并发送响应
    int ret = modbus_reply(ctx, req, req_length, mb_mapping);
    if (ret == -1) {
        fprintf(stderr, "Error handling Modbus request\n");
    }

    // 释放资源
    modbus_mapping_free(mb_mapping);
    modbus_free(ctx);

    return 0;
}

Modbus 错误响应的示例

如果请求包含错误,例如请求一个不存在的寄存器,modbus_reply 会构建一个错误响应。例如,如果请求读取保持寄存器,但请求的地址超出了有效范围,那么响应的功能码将是原功能码(例如 0x03)加上 0x80,错误代码则会表示“非法地址”。

错误响应格式示例:

// 请求功能码:0x03
// 错误响应功能码:0x83  // 0x03 + 0x80
// 错误代码:0x02  // Illegal Data Address (非法地址)

总结

  • modbus_reply 函数用于处理接收到的 Modbus 请求,并发送响应。
  • 根据请求类型,它会执行读取或写入操作,并根据需要构造错误响应。
  • 如果操作成功,返回发送的字节数;如果发生错误,返回 -1。
  • 在实际应用中,该函数处理 Modbus 协议的基本通信,包括正常的请求处理和错误处理。

标签:Modbus,libmodbus,请求,回应,mapping,modbus,响应,从机,寄存器
From: https://blog.csdn.net/m0_49476241/article/details/145087306

相关文章

  • 优化检索增强生成(RAG)管道:实现更智能AI回应的高级技术
    RAG系统(面向企业RAG(RetrievalAugmentedGeneration)系统的多维检索框架)通过从大规模知识库中检索相关信息,并基于这些信息进行生成,为用户提供个性化的答案。这种结合信息检索和生成的方法,使得RAG系统在处理复杂问题和生成详细回答方面具有显著优势。然而,要充分发挥RAG系统的潜力......
  • libmodbus源码中重要的两个结构体讲解
    文章目录一、libmodbus重要数据结构讲解**1.结构体`_modbus`**定义成员解析小结**2.结构体`_modbus_backend`**定义成员解析小结**3.两者关系和工作流程****关系****工作流程**一、libmodbus重要数据结构讲解这两个结构体是libmodbus的核心,定义了Modbu......
  • 如何提前预测足球冷门比赛?从机构走势和模型模拟的分歧点入手
    我们知道,足球是圆的,足球比赛是一项复杂的团队运动,有很多的不确定性,容易产生一些让人大跌眼镜的“冷门”,比如卡塔尔世界杯冠军阿根廷的首战居然被沙特逆转了,这也是足球的魅力所在。但这种冷门比赛毕竟是低概率事件,在赛前是否有迹可循呢?当然,基本面因素决定了体育竞技实力,球队内......
  • liunx esm8000交叉编译libmodbus库
    使用esm8000编译器编译libmodbus库1.下载安装下载压缩包下载地址libmodbus-3.1.6.tar.gz解压压缩包进入到下载压缩包的文件夹下输入命令tar-xzvflibmodbus-3.1.6.tar.gz进入解压的文件下,创建文件夹,设置文件夹权限cdlibmodbus-3.1.6mkdirinstallchmod777instal......
  • 向带有BLE从机的代码中移植BackupOTA备份升级
    目录Backup升级方式,涉及到头/源文件的修改,代码改动量相比Onlyupdata升级方式来讲要更大。Backup升级的优点:升级无需跳转,通过基于24年9月9日的CH592EVT移植后的APP层工程见链接:通过网盘分享的文件:592Peripheral_Extract_BackupOTA.zip链接:https://pan.baidu.com/s/17lTmvSdYH......
  • 深入理解人工智能:从机器学习到深度学习
    深入理解人工智能:从机器学习到深度学习前言人工智能(AI)实际应用示例代码机器学习(ML)分类常见算法示例代码深度学习(DL)应用示例代码神经网络(NN)研究方向示例代码总结前言  在这个信息爆炸的时代,人工智能(AI)正逐渐成为我们生活中不可或缺的一部分。从智能手机中的语音......
  • STM32CubeMX+usart+DMA+Modbus从机
    前言单片机型号STM32f103zet6使用USART1串口来实现DMA收发使用DMA1通道5,来传输USART1接收的数据使用DMA1通道4,来传输USART1发送的数据实现了Modbus从机协议(03和06功能)1.准备工作modbuspoll和modbusslave模拟软件下载链接:https://pan.baidu.com/s/1cX8HC-rm3gsM......
  • 微信自动回复设置,让每一次消息都及时回应!
    当微信有大量的消息需要回复时,该如何提升回复效率呢?很简单,通过使用个微管理系统进行微信自动回复设置,助你轻松应对海量信息。1、自动通过好友开启此功能后,系统会自动处理所有新的好友请求,无需你亲自一一通过验证。这不仅节省了时间,更保证了你不会错过任何潜在的客户。2、......
  • 一文迅速上手 ESP32 bluedroid 蓝牙从机开发
    前言该博客主要针对希望迅速上手ESP32蓝牙从机开发人员,因此,很多蓝牙技术细节知识并不会进行介绍,仅仅介绍我认为需要了解的API函数和回调内容。本文主要是基于gatt_serverdemo来微调进行进行讲解。代码#include<stdio.h>#include<stdlib.h>#include<string.h>#include<i......
  • 为什么Java仍旧生机盎然——对“为什么Java正在消亡”的回应
    [图片上传失败...(image-599293-1649288200226)]0.阅读完本文你将会了解Java作为热门语言之一所面临的争议了解Java的生态环境和未来1.前言原文标题:WhyJavaIsPerfectlyAlive——Aresponseto"WhyJavaIsDying"原文地址:https://betterprogramming.pub/why-......