一、modbusTcp的报文结构
cpp
TCP ADU结构(最大260字节):
┌──────────────────┬─────────────────────┐
│ MBAP头 │ PDU │
│ 7字节 │ 1-253字节 │
└──────────────────┴─────────────────────┘
总长度 = 7 + 253 = 260字节
MBAP头内容:
#pragma pack(push, 1)
typedef struct {
uint16_t transaction_id; // 事务标识符
uint16_t protocol_id; // 协议标识符(0x0000)
uint16_t length; // 后续字节数(PDU长度 + 1)
uint8_t unit_id; // 单元标识符(相当于RTU地址)
} modbus_tcp_header_t;
#pragma pack(pop)
PDU内容:
功能码+数据
二、封装libmodbus为静态库
将最新的libmodbus库编译为静态库并放到指定文件夹,主要涉及下载源码、配置编译环境、执行交叉编译等步骤。下面我为你详细梳理一下流程,并提供一个清晰的步骤表格。
📥 1. 获取源代码
首先,你需要下载libmodbus库的源代码。推荐通过Git获取最新版本,因为某些新版本(如3.1.4及以上)的编译配置可能需要使用autogen.sh脚本生成configure文件,而Git仓库通常包含这些必要的自动化工具脚本
git clone git://github.com/stephane/libmodbus.git
cd libmodbus
⚙️ 2. 准备编译环境
在编译前,需要确保你的系统具备必要的编译工具。如果是从Git克隆的代码,这一步是必须的
-
在Ubuntu/Debian系统上,可以使用以下命令安装:
sudo apt-get install automake autoconf libtool
-
执行自动化脚本,生成
configure配置文件:./autogen.sh
🔧 3. 配置编译参数
接下来,你需要配置编译参数,以生成静态库并指定安装目录。假设你希望将编译好的静态库安装到 /home/yourusername/mylibs/libmodbus目录下。
在libmodbus源码目录下,执行以下命令
# 创建一个目录用于存放编译产出,例如名为 "install"
mkdir -p /home/yourusername/mylibs/libmodbus
# 运行configure脚本进行配置
./configure --enable-static --prefix=/home/yourusername/mylibs/libmodbus
参数说明:
-
--enable-static:告诉编译系统生成静态库(.a文件) -
--prefix=/path/to/your/folder:指定库的安装路径,编译后的文件将存放在此路径下的lib和include目录中
🛠️ 4. 编译和安装
配置完成后,就可以开始编译并安装了
# 编译源码
make
# 将编译好的库和头文件安装到 --prefix 指定的目录中
make install
📁 5. 最终成果
执行完 make install后,你会在之前通过 --prefix指定的文件夹(例如 /home/yourusername/mylibs/libmodbus)中看到以下结构
/home/yourusername/mylibs/libmodbus/
├── include/
│ └── modbus/ # 头文件目录
│ ├── modbus.h # 主要的头文件
│ ├── modbus-version.h
│ ├── modbus-rtu.h
│ └── modbus-tcp.h
└── lib/ # 库文件目录
├── libmodbus.a # 静态库文件
├── libmodbus.la
└── pkgconfig/
三、发送用户自定义功能码
cpp
modbus_t *ctx;
/* 第一位是地址,第二位是功能码,后面是数据内容,无需添加crc校验码,库中会自动添加*/
uint8_t raw_req[] = { 0xFF, 0x64, 0x00, 0x01, 0x0, 0x05 };
int req_length;
uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];
ctx = modbus_new_tcp("127.0.0.1", 1502);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
req_length = modbus_send_raw_request(ctx, raw_req, 6 * sizeof(uint8_t));
modbus_receive_confirmation(ctx, rsp);
modbus_close(ctx);
modbus_free(ctx);
出现TCP粘包问题,且数据接收不完整

解决办法:修改libmodbus底层驱动函数,详细的可以看下面的文章
Users functions by demiurg-spb · Pull Request #522 · stephane/libmodbus · GitHub
cpp
//response_len为想要接收的数据长度, 不含从站地址和功能码
int send_rc = modbus_send_generic_request(m_ctx, request_data, request_len, *response_len);
if (send_rc == -1)
{
return MB_DRIVER_SEND_CUSTOM_ERR;
}
int full_response_len = modbus_receive_confirmation(m_ctx, response_data);
if (full_response_len == -1)
{
return MB_DRIVER_SEND_CUSTOM_ERR;
}