Modbus
1. Mdobus
1.2 ModbusTCP
2. libmodbus库
libmodbus 是支持Linux,Mac OS X,window 的一个开源库,支持modbus TCP和modbus RTU 两种模式。
2.1 libmodbus下载
目录结果
- docs目录 libmodbus库API接口说明文档
- m4目录 存放GUN m4文件
- src目录 libmodbus源代码
- tests目录自带的测试代码
2.2 libmodbus编译动态库
打开src文件目录如下:
注意:
- .js文件,双击js文件时需要选择打开方式时,右键打开方式选择【Microsoft ® Windows Based Script Host】
- 不能有中文路径,也不能放桌面
32位动态库
1、进入 src/win32 文件夹,双击src\win32\configure.js,生成一些配置文件,其中 modbus-version.h 被生成到上一级文件夹中,config.h生成在该路径下。
2、用Visual Studio 2019打开文件modbus-9.sln。
3、查看项目头文件下的modbus-version.h文件,发现路径不存在,此时移除此文件,在项目上右键添加现有项,找到上一步生成的modbus-version.h,其路径在win32的上一级目录。
4、32位下选择debug和release模式下分别编译,编译成功后在win32路径下生成对应的debug/release版本的modbus.dll和modbus.lib
64位动态库
1、进入 src/win32 文件夹,双击src\win32\configure.js,生成一些配置文件,其中 modbus-version.h 被生成到上一级文件夹中,config.h生成在该路径下。
2、用Visual Studio 2019打开文件modbus-9.sln。
3、查看项目头文件下的modbus-version.h文件,发现路径不存在,此时移除此文件,在项目上右键添加现有项,找到上一步生成的modbus-version.h,其路径在win32的上一级目录。
4、Visual Studio 2019将编译平台的配置管理器修改为release-x64,重新编译
5、编译后报LNK2019错误
6、原因是64位缺少依赖库ws2_32.lib,在属性-链接器-输入-附加依赖项-<编辑…>,添加后,重新编译
7、编译后报LNK2019和LNK1120错误
8、原因是没有main函数,项目不能生成exe。属性-常规-配置类型-动态库(.dll),修改后,重新编译
9、64位下选择debug和release模式下分别编译,编译成功后在win32/x64/Release路径下生成对应modbus.dll和modbus.lib
3. C++
工程配置
- pro文件配置
INCLUDEPATH += $$PWD/lib/libmodbus/include
LIBS += $$PWD/lib/libmodbus/bin/modbus.lib
运行exe时,将modbus.dll copy到其路径下。
Modbus TCP 示例
Modbus TCP 服务器示例
#include <modbus.h>
#include <stdio.h>
int main()
{
modbus_t *ctx = modbus_new_tcp("127.0.0.1", 502);
modbus_mapping_t *mb_mapping;
if (ctx == NULL) {
fprintf(stderr, "Unable to create the libmodbus context\n");
return -1;
}
mb_mapping = modbus_mapping_new(0, 0, 100, 0);
if (mb_mapping == NULL) {
fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
while (true) {
uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
int rc = modbus_receive(ctx, query);
if (rc > 0) {
modbus_reply(ctx, query, rc, mb_mapping);
}
}
modbus_mapping_free(mb_mapping);
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
Modbus TCP 客户端示例
#include <modbus.h>
#include <stdio.h>
int main()
{
modbus_t *ctx = modbus_new_tcp("127.0.0.1", 502);
if (modbus_connect(ctx) == -1) {
fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
modbus_free(ctx);
return -1;
}
uint16_t tab_reg[1];
tab_reg[0] = 1234;
int rc = modbus_write_registers(ctx, 0, 1, tab_reg);
if (rc == 1) {
printf("Write successful\n");
} else {
fprintf(stderr, "Write failed: %s\n", modbus_strerror(errno));
}
uint16_t read_reg;
rc = modbus_read_registers(ctx, 0, 1, &read_reg);
if (rc == 1) {
printf("Read value: %d\n", read_reg);
} else {
fprintf(stderr, "Read failed: %s\n", modbus_strerror(errno));
}
modbus_close(ctx);
modbus_free(ctx);
return 0;
}
libmodbus函数说明
在Modbus通讯协议中,有几种常见的读取数据的函数,包括modbus_read_bits、modbus_read_input_bits和modbus_read_registers。这些函数用于读取不同类型的数据,下面是它们的区别:
函数 | 用途 | 说明 |
---|---|---|
modbus_read_bits | 读取线圈(Coils)数据 | 用于读取线圈(Coils)数据,即开关量数据。 线圈数据通常是输出数据,可由Modbus设备的控制逻辑进行操作。 线圈数据的地址范围是从0开始,通常用于控制或监控开关状态。 读取的数据是布尔类型,每个位代表一个开关状态。 |
modbus_read_input_bits | 读取输入线圈(Input Coils)数据 | 用于读取输入线圈(Input Coils)数据,即输入开关量数据。 输入线圈数据通常是输入数据,表示外部设备的状态。 输入线圈数据的地址范围也是从0开始,通常用于监控外部设备状态。 读取的数据是布尔类型,每个位代表一个开关状态。 |
modbus_read_registers | 读取保持寄存器(Holding Registers)数据 | 用于读取保持寄存器(Holding Registers)数据,即16位寄存器数据。 保持寄存器数据通常用于存储控制器内部的数据,如整数、浮点数等。 保持寄存器数据的地址范围也是从0开始,通常用于传输16位二进制数据。 读取的数据是16位整数类型。 |
在Modbus通讯协议中,MODBUS_FC_READ_COILS和MODBUS_FC_READ_DISCRETE_INPUTS是两种不同的功能码,用于读取不同类型的数据,分别是线圈(Coils)数据和离散输入(Discrete Inputs)数据。以下是它们的区别:
功能码 | 说明 | ||
---|---|---|---|
MODBUS_FC_READ_COILS | 0x01 | 读取可写的输出线圈数据 | 功能码为0x01,用于读取线圈(Coils)数据。 线圈数据通常是输出数据,可由Modbus设备的控制逻辑进行操作。 线圈数据的地址范围是从0开始,每个线圈代表一个开关状态。 读取的数据是布尔类型,每个位代表一个开关状态。 适用于读取可写的输出线圈数据。 |
MODBUS_FC_READ_DISCRETE_INPUTS | 0x02 | 读取只读的输入线圈数据 | 功能码为0x02,用于读取离散输入(Discrete Inputs)数据。 离散输入数据通常是输入数据,表示外部设备的状态。 离散输入数据的地址范围也是从0开始,每个位代表一个开关状态。 读取的数据是布尔类型,每个位代表一个开关状态。 适用于读取只读的输入线圈数据。 |