Modbus开源库_Libmodbus
Libmodbus库得介绍。
1、Libmodbus简介
在单片机上常用的Modbus库有FreeModbus和Libmodbus,这里介绍Libmodbus。
(1)Libmodbus是一个免费的跨平台支持RTU和TCP的Modbus库,遵循LGPL V2.1+协议。
(2)支持Linux、Mac OsX、FreeBSD、QNX和Windows等操作系统。
(3)支持主、从模式。
(4)稍加修改就可以在裸机、FreeRTOS、RT-Thread上使用。
2、Libmodbus的下载和源码介绍
(1)下载地址:https://github.com/stephane/libmodbus
(2)源码浏览
在目录 “ libmodbus-3.1.10\libmodbus-3.1.10\src” 下存在如下文件:
- modbus.c:modbus的统一接口层。
- modbus-data.c:一些数据处理的辅助函数。
- modbus-rtu.c:ModbusRtu模式相关程序,一般使用串口。
- modbus-tcp.c:ModbusTcp相关协议,使用以太网。
(3)源码分层
libmodbus通过抽象出这些层次,提供了一个跨平台的API,使得在不同硬件和平台上实现Modbus通信变得更加容易。用户在使用libmodbus时,可以根据需要选择不同的后端(如RTU或TCP),而核心层和应用层的代码可以保持不变,从而提高了代码的可移植性和可维护性。
APP | 应用层(APP):这一层是用户直接交互的层面,它知道要做什么,比如主设备需要读写哪些寄存器,从设备需要提供或接收什么数据。 |
modbus.c | Modbus核心层:这一层向上提供接口函数,向下调用底层代码构造数据包,发送、接收数据包并解析。它负责Modbus协议的具体实现,包括读写操作的逻辑处理。 |
modbus-rtu.c、modbus-tcp.c | 后端(数据传输层):这一层负责硬件相关的数据封包与发送、接收与解包。它处理与不同网络(如串行RTU或以太网TCP IPv4/IPv6)的通信细节。 |
物理层 | 串口或以太网等 |
3、modbus.c文件核心函数介绍
(1)modbus_read_bits函数
- 函数原型:int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
- 函数功能:读布尔量(读数字量输出)
参数 | 说明 |
---|---|
modbus_t *ctx |
指向Modbus上下文的指针,包含了与Modbus设备通信所需的所有信息。 |
int addr |
要读取的线圈的起始地址。 |
int nb |
要读取的线圈的起始地址 |
uint8_t *dest |
指向目标数组的指针,用于存储读取的线圈状态。 |
返回值 | -1;读取失败;n:读取线圈的梳理nb |
(2)modbus_read_input_bits函数
- 函数原型:int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
- 函数功能:读布尔量(读数字量输入/离散输入状态)
(3)modbus_write_bit函数
(4)modbus_write_bits函数
(5)modbus_read_registers函数
- 函数原型:int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
- 函数功能:读模拟量(读输出模拟量AO)
(6)modbus_read_input_registers函数
- 函数原型:int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
- 函数功能:读模拟量(读输入模拟量/AI)
(7)modbus_write_register函数
- 函数原型:int modbus_write_register(modbus_t *ctx, int addr, const uint16_t value)
- 函数功能:写单个输出模拟量
- 函数调用了write_single,write_single调用了函数send_msg、_modbus_receive_msg、check_confirmation。
- send_msg:发送消息
- _modbus_receive_msg:接收消息
- check_confirmation:检查
(8)modbus_write_registers函数
- 函数原型:int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src)
- 功能:写多个输出模拟量
- modbus_write_registers调用了函数send_msg、_modbus_receive_msg、check_confirmation。
- send_msg:发送消息
- _modbus_receive_msg:接收消息
- check_confirmation:检查
(9)send_msg函数
- 函数原型:static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
- 函数功能:发送消息
- 调用函数ctx->backend->send_msg_pre(msg, msg_length)
- 发送消息的准备函数
- prepare:准备;backend:后端
- 调用函数ctx->backend->send(ctx, msg, msg_length);
- 发送真正的消息
- backend是一个非常重要的结构体,该结构体由modbus-rtu.c或者modbus-tcp构造。
4、modbus-rtu.c核心函数介绍
(1)主要工作就是构造这个结构体。
// clang-format off
const modbus_backend_t _modbus_rtu_backend = {
_MODBUS_BACKEND_TYPE_RTU,
_MODBUS_RTU_HEADER_LENGTH,
_MODBUS_RTU_CHECKSUM_LENGTH,
MODBUS_RTU_MAX_ADU_LENGTH,
_modbus_set_slave,
_modbus_rtu_build_request_basis,
_modbus_rtu_build_response_basis,
_modbus_rtu_prepare_response_tid,
_modbus_rtu_send_msg_pre,
/* 发送 */
_modbus_rtu_send,
_modbus_rtu_receive,
/* 接收 */
_modbus_rtu_recv,
_modbus_rtu_check_integrity,
_modbus_rtu_pre_check_confirmation,
_modbus_rtu_connect,
_modbus_rtu_is_connected,
_modbus_rtu_close,
_modbus_rtu_flush,
_modbus_rtu_select,
_modbus_rtu_free
};
5、mosbus-tcp核心函数介绍
(1)主要工作就是构造这个结构体。
const modbus_backend_t _modbus_tcp_pi_backend = {
_MODBUS_BACKEND_TYPE_TCP,
_MODBUS_TCP_HEADER_LENGTH,
_MODBUS_TCP_CHECKSUM_LENGTH,
MODBUS_TCP_MAX_ADU_LENGTH,
_modbus_set_slave,
_modbus_tcp_build_request_basis,
_modbus_tcp_build_response_basis,
_modbus_tcp_prepare_response_tid,
_modbus_tcp_send_msg_pre,
/* 网络发送 */
_modbus_tcp_send,
_modbus_tcp_receive,
/* 网络接收 */
_modbus_tcp_recv,
_modbus_tcp_check_integrity,
_modbus_tcp_pre_check_confirmation,
_modbus_tcp_pi_connect,
_modbus_tcp_is_connected,
_modbus_tcp_close,
_modbus_tcp_flush,
_modbus_tcp_select,
_modbus_tcp_pi_free
};
6、modbus-data.c文件核心函数介绍
(1)bswap_16函数:实现16位无符号整数的字节交换。
- 将数据从大端序(big-endian)转换为小端序(little-endian),或者从小端序转换为大端序。
#if !defined(bswap_16)
/* 如果bswap_16没有被定义,编译器会发出一个警告信息,提示用户正在使用C函数作为字节交换的后备方案。 */
# warning "Fallback on C functions for bswap_16"
static inline uint16_t bswap_16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
#endif
(2)bswap_16函数:实现32位无符号整数的字节交换。
- 将数据从大端序(big-endian)转换为小端序(little-endian),或者从小端序转换为大端序。
# warning "Fallback on C functions for bswap_32"
static inline uint32_t bswap_32(uint32_t x)
{
return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
}
#endif
7、modbus_backend结构体
typedef struct _modbus_backend {
unsigned int backend_type;
unsigned int header_length;
unsigned int checksum_length;
unsigned int max_adu_length;
int (*set_slave)(modbus_t *ctx, int slave);
int (*build_request_basis)(
modbus_t *ctx, int function, int addr, int nb, uint8_t *req);
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);
int (*receive)(modbus_t *ctx, uint8_t *req);
/* 接收消息 */
ssize_t (*recv)(modbus_t *ctx, uint8_t *rsp, int rsp_length);
int (*check_integrity)(modbus_t *ctx, uint8_t *msg, const int msg_length);
int (*pre_check_confirmation)(modbus_t *ctx,
const uint8_t *req,
const uint8_t *rsp,
int rsp_length);
/* 连接相关,TCP中需要建立连接 */
int (*connect)(modbus_t *ctx);
unsigned int (*is_connected)(modbus_t *ctx);
void (*close)(modbus_t *ctx);
int (*flush)(modbus_t *ctx);
int (*select)(modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
void (*free)(modbus_t *ctx);
} modbus_backend_t;
(1)涉及硬件操作的函数
- ssize_t (*send)(modbus_t *ctx, const uint8_t *req, int req_length);
- ssize_t (*recv)(modbus_t *ctx, uint8_t *rsp, int rsp_length);
8、unit-test-client.c文件
(1)单元测试客户端程序,客户端主动发送消息,然后接收服务器的应答。
(2)根据use_backend确认modbus的通信方式。
if (use_backend == TCP)
{
ctx = modbus_new_tcp(ip_or_device, 1502);
} else if (use_backend == TCP_PI) {
ctx = modbus_new_tcp_pi(ip_or_device, "1502");
} else {
ctx = modbus_new_rtu(ip_or_device, 115200, 'N', 8, 1);
}
if (ctx == NULL) {
fprintf(stderr, "Unable to allocate libmodbus context\n");
return -1;
}
(3)modbus_new_rtu(ip_or_device, 115200, 'N', 8, 1);
- ip_or_device:串口设备号
- 115200:串口波特率
- 'N': 校验相关
- 8:数据位
- 1:停止位

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)