11.2
libmodbus源码框架分析
libmodbus作为一个优秀且免费开源的跨平台支持RTU 和 TCP模式的Modbus开发库,非常值得大家借鉴和学习。本章对libmodbus源代码进行阅读和分析。
11.2.1
核心函数
以Modbus RTU协议为例,主设备、从设备初始化后:
①主设备就可以启动请求,即“发送消息”给从设备。
②从设备接收到请求后构造数据,启动响应即“发送回复”。
③主机收到响应后,会“检查响应”。
如下图所示:
分析“libmodbus-3.1.10\tests\unit-test-client.c”、“libmodbus-3.1.10\tests\unit-test-server.c”,可以得到下面核心函数的使用过程:
11.2.2
框架与数据结构
站在APP开发的角度来说,使用上一节里介绍的libmodbus函数即可。但是,数据的传输必定涉及到底层数据传输。所以,从数据的收发过程,可以把使用libmodbus的源码分为3层:
①APP:它知道要做什么,主设备要读写哪些寄存,从设备提供、接收什么数据。
②Modbus核心层:向上提供接口函数,向下调用底层代码构造数据包并发送、接收数据包并解析。
③后端(数据传输):进行硬件相关的数据封包与发送、接收与解包。
对于核心层、后端,抽象出了如下结构体:
核心层modbus_t结构体的成员含义如下:
后端modbus_backend_t结构体的成员含义如下:
成员 | 含义 |
unsigned int backend_type; | 后端类型,是RTU还是TCP |
unsigned int header_length; | 头部长度,比如RTU数据包前面需要有1字节的设备地址,头部长度就是1 |
unsigned int checksum_length; | 校验码长度,RTU的校验码是2字节 |
unsigned int max_adu_length; | ADU(数据包)最大长度 |
set_slave | 设置从站地址 |
build_request_basis | 设置RTU请求包的基本数据,这些数据的格式是一样的,比如req[0]是从设备地址,req[1]是功能码,req[2]和req[3]是寄存器地址,req[4]和req[5]是寄存器数量 |
build_response_basis | 设置RTU回应包的基本数据,这些数据的格式是一样的,比如req[0]是从设备地址,req[1]是功能码 |
prepare_response_tid | 生产传输标识TID,在TCP中使用 |
send_msg_pre | 发送消息前的准备工作,对于RTU是填充CRC检验码,对于TCP是填充头部的Length |
send | 发送数据包 |
receive | 接收数据包 |
recv | 接收原始数据,receive会调用recv得到原始数据然后解析出数据包 |
check_integrity | 检查数据包的完整性 |
pre_check_confirmation | 检查响应数据包是否有效时,先执行pre_check_confirmation做一些简单的检查 |
connect | 硬件相关的连接,对于RTU就是打开串口、设置串口波特率等;对于TCP则是连接对端 |
is_connected | 判断是否已经连接 |
close | 关闭连接 |
flush | 清空接收到的、未处理的数据 |
select | 阻塞一段时间以等待数据 |
free | 释放分配的modbus_t等结构体 |
如您在使用瑞萨MCU/MPU产品中有任何问题,可识别下方二维码或复制网址到浏览器中打开,进入瑞萨技术论坛寻找答案或获取在线技术支持。
https://community-ja.renesas.com/zh/forums-groups/mcu-mpu/
未完待续
推荐阅读
(0x0B)获取通信事件计数器与(0x0C)获取通信事件记录 - RZ MPU工业控制教程连载(34)
写多个线圈与写多个保持寄存器 - RZ MPU工业控制教程连载(35)
报告从站ID与Modbus异常响应 - RZ MPU工业控制教程连载(36)