10

I am currently working on a project which will allow different automates to communicate. To do so, I would like to create a client and a server that will talk using the modbus protocol. I am not sure if I want to be using ModBus/TCP, ModBus/RTU or ModBus/ASCII for now.

I have searched for client/server examples in C and I could find libraries but no simple example of communication. I would like to start from scratch so libraries are not what I am looking for.

What I am asking for is if someone could give me a simple code written in C for a client and/or a server that communicate using Modbus, since I am not sure of what I will be using any type of Modbus would be a great help (RTU/TCP/ASCII).

The simpler the better, what I would like the code to demonstrate is, for example : an initialization to the server, a request, an answer, closing the connection.

Thank you very much for your time.

4

1 回答 1

20

三件事:

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

看看这个简短但非常完整的描述,以及这个不断更新的库的文档。


这是一个基于libmodbus的 Linux 超级简化 RTU 示例。
请允许我放松一下 C99 以保持紧凑。
在现实世界中,您还应该正确处理 SIGTERM 等信号…… Linux 内核 2.6.28 及更高版本
还有一个(RS232 与 RS485)功能。modbus_rtu_set_serial_mode您可能会发现其他库可以在您的平台上更轻松地使用 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);
于 2015-04-14T14:24:51.353 回答