agile_modbus:基于纯C的轻量级Modbus协议栈项目

用户可借助该项目实现Modbus RTU和TCP协议的通信功能。它采用纯C开发,不依赖硬件接口,支持多主多从及自定义协议,具备简单易用的API,可在各类硬件上灵活部署。【此简介由AI生成】

分支4Tags7
文件最后提交记录最后更新时间
1 年前
2 年前
1 年前
2 年前
2 年前
2 年前
2 年前
1 年前
2 年前
4 年前
2 年前
4 年前

敏捷Modbus

1. 引言

敏捷Modbus是一种轻量级的Modbus协议栈,满足用户在各种场景下的需求。

  • 在线文档:API手册

  • 文件夹examples提供了PC端示例代码

  • 查看MCU上的示例请参考mcu_demos

  • 支持基于RT-Thread的AT32F437启动加载器进行Modbus固件升级:AT32F437_Boot

  • 支持基于RT-Thread的HPM6750启动加载器进行Modbus固件升级:HPM6750_Boot

1.1. 特性

  1. 支持rtu和tcp协议,采用纯C语言开发,不涉及任何硬件接口,可直接用于任何形式的硬件。
  2. 因使用纯C语言且不涉及硬件细节,可在串口上运行tcp协议,在网络上运行rtu协议。
  3. 支持自定义符合Modbus格式的协议。
  4. 同时支持多个主站与多个从站操作。
  5. 使用简单,仅需初始化rtu或tcp句柄,并调用相应API完成数据封装和解封。

1.2. 目录结构

名称 描述
doc 文档资料
examples 示例代码
figures 材料文件
inc 头文件
src 源代码
util 提供简单实用组件

1.3. 许可证

敏捷Modbus遵循Apache-2.0许可证,详细信息参见LICENSE文件。

2. 应用敏捷Modbus

请查阅帮助文档doc/doxygen/Agile_Modbus.chm

2.1. 移植指南

  • 用户需要实现硬件接口的发送数据等待接收数据结束以及清空接收缓冲区功能。

    对于等待接收数据结束的操作,提供以下思路:

    1. 常规方法

      每隔约20/50毫秒(此时间可根据波特率及硬件情况调整,仅为参考值)从硬件接口读取数据存入缓冲区并更新偏移量,直至无法读取或缓冲区满,则停止读取。

      此法适用于裸机系统和操作系统环境,可通过selectsemaphore实现阻塞效果。

    2. 串口DMA + IDLE中断模式

      配置DMA + IDLE中断,中断中设置标志位,并由应用程序检测该标志是否被设置。

      然而,此方案容易出现问题,若字节稍有错位就可能不成帧。建议优先选择第一种方式。

  • 主控机:

    1. agile_modbus_rtu_init / agile_modbus_tcp_init 初始化RTU/TCP环境
    2. agile_modbus_set_slave 设置从站地址
    3. 清除接收缓存
    4. agile_modbus_serialize_xxx 封装请求数据
    5. 发送数据
    6. 等待接收数据结束
    7. agile_modbus_deserialize_xxx 解析响应数据
    8. 数据处理由用户执行
  • 从机:

    1. 实现类型agile_modbus_slave_callback_t回调函数
    2. agile_modbus_rtu_init / aggle_modbus_tcp_init 初始化RTU/TCP环境
    3. agile_modbus_set_slave 设置从站地址
    4. 等待接收数据结束
    5. agile_modbus_slave_handle 处理请求数据
    6. 清空接收缓冲区(非必需)
    7. 发送数据
  • 特殊功能码

    需要调用agile_modbus_set_compute_meta_length_after_function_cbagile_modbus_set_compute_data_length_after_meta_cb API来设置处理主从模式下特殊功能码所需的回调。

    • agile_modbus_set_compute_meta_length_after_function_cb

      当`msg_type == AGILE_MODBUS_MSG_INDICATION`,返回主机请求消息的数据元素长度(uint8_t类型),如果不是特殊功能码,必须返回0。
      
      当`msg_type == MSG_CONFIRMATION` ,返回从应答消息的数据元素长度(uint8_t类型),如果不是特殊功能码,必须返回1。
      
    • agile_modbus_set_compute_data_length_after_meta_cb

      当`msg_type == AGILE_MODBUS_MSG_INDICATION`,返回主机请求消息后数据元素之后的数据长度,如果不是特殊功能码,必须返回0。
      
      当`msg_type == MSG_CONFIRMATION`,返回从应答消息后数据元素之后的数据长度,如果不是特殊功能码,必须返回0。
      
  • agile_modbus_rtu_init / agile_modbus_tcp_init

    初始化RTU/TCP环境时,用户需传入发送缓冲区接收缓冲区。推荐两者大小均为AGILE_MODBUS_MAX_ADU_LENGTH(260)字节。特殊功能码根据约定由用户确定。

    但针对内存小的MCU,这两个缓冲区也可以设定得较小,所有API会判断缓冲区大小:

    发送缓冲区设置:如果预期请求数据长度预期响应数据长度大于设定发送缓冲区大小,则返回异常。

    接收缓冲区设置:如果主机所请求消息长度大于设定接收缓冲区大小,将返回异常。这合情合理,使用小型内存MCU作为从机时,某些功能码必然受限。

2.2. 主机端

详情见2.1. 移植指南

2.3. 从机端

2.3.1. 接口描述

agile_modbus_slave_handle介绍

int agile_modbus_slave_handle(agile_modbus_t *ctx, int msg_length, uint8_t slave_strict,
                              agile_modbus_slave_callback_t slave_cb, const void *slave_data, int *frame_length);
  • msg_length: 接收到数据后的长度,即等待数据接收结束后的数据量。

  • slave_strict: 奴隶地址严格检查标志(0:不判断地址是否一致,交由用户回调处理;1:地址必须一致,否则不触发回调,也不打包响应数据)。

  • slave_cb: 用户实现并传递的agile_modbus_slave_callback_t类型回调函数。若为NULL,则对所有功能码都能响应并成功,但寄存器数据默认为0。

  • slave_data: 回调函数的私有数据指针。

  • frame_length: 获取解析出的Modbus数据帧长度,其含义包括:

    1. 数据末尾有脏数据:仍能成功解析,并告诉用户实际的Modbus帧长,供用户处理。
    2. 数据粘包情况:数据包含一个完整的Modbus数据帧加上部分下一个Modbus数据帧。用户获得真实的Modbus帧长度后,可移除已处理的数据帧,并重新读取硬件接口的当前剩余部分形成新帧。
    3. 在Modbus广播传输大数据(如固件升级的自定义功能码广播)时常用。普通从机响应是一问一答模式,仅处理完整数据帧,建议执行“清除接收缓存”。

agile_modbus_slave_callback_t介绍

typedef int (*agile_modbus_slave_callback_t)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data);

此回调用于处理从机请求,参数包含处理上下文、从机信息和私有数据。返回值反映操作状态(正常=0,异常<0,其中-AGILE_MODBUS_EXCEPTION_UNKNOW(-255)表示未知异常,不打包响应数据;其他负数代码为特定异常响应数据准备)。

agile_modbus_slave_info结构体包含从机地址、功能码属性等关键信息,以及处理特殊功能码时需更新的rsp_length指针(处理过程中不得随意更改),地址、数量(nb)、缓冲区发送索引等,根据不同的功能码需求使用。

不同功能码使用agile_modbus_slave_info

详细描述了在不同功能码处理中agile_modbus_slave_info的特性和所需API调用,如:

  • 对于读写线圈、寄存器的功能码,需注意地址、数量和数据字段的正确处理。
  • 自定义功能码时,利用回调直接处理特定数据。

简单从机访问接口

agile_modbus提供agile_modbus_slave_util_callback,简化用户接入过程。通过示例代码展示如何结合agile_modbus_slave_util_t结构体简单配置回调逻辑。

agile_modbus_slave_util_callbackagile_modbus_slave_util_t介绍

它们构成了一种便利的机制,允许通过预定义的映射表来直接管理寄存器数据,减少了用户的编码复杂度,特别是通过addr_checkspecial_functiondone等接口提供了地址验证、特殊功能处理及操作完成后的额外控制点。用户只需填充相应的注册表定义和逻辑,即可支持标准及特定功能码的处理。

2.4. 示例

示例文件位于examples文件夹中,可在WSLLinux环境下编译和运行。

  • RTU/TCP主从设备实例

    • 特殊功能码应用实例

      文件通过RTU点对点传输:展示了特殊功能码的应用。

      RTU广播方式传输文件:演示了在agile_modbus_slave_handle中使用frame_length的方法。

  • mcu_demos提供了微控制器(MCU)上的示例代码。

  • AT32F437_Boot: 支持Modbus固件升级的基于RT-Thread的AT32F437引导加载程序。

  • HPM6750_Boot: 在HPM6750上实现的,同样支持通过Modbus进行固件升级的RT-Thread引导加载程序。

2.5. Doxygen文档生成

  • 使用Doxywizard打开Doxyfile并执行。生成的文件位于doxygen/output目录下。
  • 需要调整Graphviz路径。
  • 默认生成HTML格式而非chm格式。若启用chm,需指定hhc.exe路径进行更改。

3. 支持

如果你的问题因Agile Modbus得到解决,不妨扫描上方二维码请我喝一杯咖啡吧~

4. 联系方式与致谢

项目介绍

用户可借助该项目实现Modbus RTU和TCP协议的通信功能。它采用纯C开发,不依赖硬件接口,支持多主多从及自定义协议,具备简单易用的API,可在各类硬件上灵活部署。【此简介由AI生成】

定制我的领域