在 C 中使用 Modbus 创建一个简单的 Client/Server

Create a simple Client/Server using Modbus in C

我目前正在从事一个项目,该项目将允许不同的自动化进行通信。为此,我想创建一个使用 modbus 协议进行通信的客户端和服务器。我不确定现在是否要使用 ModBus/TCP、ModBus/RTU 或 ModBus/ASCII。

我在 C 中搜索了 client/server 示例,我可以找到库,但没有简单的通信示例。我想从头开始,所以图书馆不是我要找的。

我要问的是,是否有人可以给我一个用 C 语言为客户端编写的简单代码 and/or 一个使用 Modbus 进行通信的服务器,因为我不确定我将使用什么类型Modbus 将是一个很大的帮助 (RTU/TCP/ASCII)。

越简单越好,我希望代码演示的是,例如:对服务器的初始化、请求、应答、关闭连接。

非常感谢您的宝贵时间。

三件事:

  1. 当您开发自己的客户端和服务器组件时,我建议您仅在严格要求或方便且开放的情况下使用 Modbus(即其他制造商必须能够通过以下方式与您的客户端或服务器组件通信)标准化协议的手段 - 和 Modbus 适合)。
  2. 请注意,Modbus TCP 不仅仅是 TCP/IP 上的 Modbus RTU(/ASCII)(仍然允许,当然,UDP 也将被允许)。需要考虑一些重要的差异。
  3. 我了解到您需要更深入地了解Modbus。那时,一旦你的 C 程序中有一个开放的串行通道或(侦听)TCP 套接字,你就可以从简单的 Modbus requests/responses.
  4. 开始

看看这个short but quite complete description, and also at the documentation of this constantly updated library


这是 Linux 的超级简化 RTU 示例,基于 libmodbus
请允许我对 C99 的紧凑性进行一些放松。
在现实世界中,您还应该正确处理 SIGTERM 等信号...
Linux 内核 2.6.28 之后还有一个 modbus_rtu_set_serial_mode(RS232 与 RS485)函数。您可能会发现其他库可以在您的平台上更轻松地使用 RS485。

主片段

//Create a new RTU context with proper serial parameters (in this example,
//device name /dev/ttyS0, baud rate 9600, no parity bit, 8 data bits, 1 stop bit)
modbus_t *ctx = modbus_new_rtu("/dev/ttyS0", 9600, 'N', 8, 1);
if (!ctx) {
    fprintf(stderr, "Failed to create the context: %s\n", modbus_strerror(errno));
    exit(1);
}

if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Unable to connect: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    exit(1);
}

//Set the Modbus address of the remote slave (to 3)
modbus_set_slave(ctx, 3);


uint16_t reg[5];// will store read registers values

//Read 5 holding registers starting from address 10
int num = modbus_read_registers(ctx, 10, 5, reg);
if (num != 5) {// number of read registers is not the one expected
    fprintf(stderr, "Failed to read: %s\n", modbus_strerror(errno));
}

modbus_close(ctx);
modbus_free(ctx);

从属片段

//Prepare a Modbus mapping with 30 holding registers
//(plus no output coil, one input coil and two input registers)
//This will also automatically set the value of each register to 0
modbus_mapping_t *mapping = modbus_mapping_new(0, 1, 30, 2);
if (!mapping) {
    fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno));
    exit(1);
}


//Example: set register 12 to integer value 623
mapping->tab_registers[12] = 623;


modbus_t *ctx = modbus_new_rtu("/dev/ttyS0", 9600, 'N', 8, 1);
if (!ctx) {
    fprintf(stderr, "Failed to create the context: %s\n", modbus_strerror(errno));
    exit(1);
}

//Set the Modbus address of this slave (to 3)
modbus_set_slave(ctx, 3);


if (modbus_connect(ctx) == -1) {
    fprintf(stderr, "Unable to connect: %s\n", modbus_strerror(errno));
    modbus_free(ctx);
    exit(1);
}


uint8_t req[MODBUS_RTU_MAX_ADU_LENGTH];// request buffer
int len;// length of the request/response

while(1) {
    len = modbus_receive(ctx, req);
    if (len == -1) break;

    len = modbus_reply(ctx, req, len, mapping);
    if (len == -1) break;
}
printf("Exit the loop: %s\n", modbus_strerror(errno));

modbus_mapping_free(mapping);
modbus_close(ctx);
modbus_free(ctx);