C语言 在 C 中使用 Modbus 创建一个简单的客户端/服务器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29602698/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 11:51:29  来源:igfitidea点击:

Create a simple Client/Server using Modbus in C

cnetwork-programmingserial-communicationmodbusmodbus-tcp

提问by PiggyGenius

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.

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

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.

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

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).

我要问的是,如果有人可以给我一个用 C 编写的简单代码,用于使用 Modbus 进行通信的客户端和/或服务器,因为我不确定我将使用任何类型的 Modbus 将是一个很大的帮助(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.

非常感谢您的宝贵时间。

回答by matpop

Three things:

三件事:

  1. As you're developing your own client and server components, I suggest you to use Modbus only if strictly required or convenient with an eye to openness (i.e. other manufacturers must be able to communicate with your client or server components by means of a standardized protocol - and Modbus fits).
  2. Be aware that Modbus TCP isn't just Modbus RTU(/ASCII) over TCP/IP (which is still allowed, of course, also UDP would be allowed). There are some important differences to take into account.
  3. I understand that you need to understand Modbus at a deeper level. At that point, once you have an open serial channel or (listening) TCP socket inside your C program, you may just start with simple Modbus requests/responses.
  1. 当您开发自己的客户端和服务器组件时,我建议您仅在严格要求或方便开放时才使用 Modbus(即其他制造商必须能够通过标准化协议与您的客户端或服务器组件进行通信) - 和 Modbus 适合)。
  2. 请注意,Modbus TCP 不仅仅是 TCP/IP 上的 Modbus RTU(/ASCII)(这仍然是允许的,当然,UDP 也是允许的)。有一些重要的差异需要考虑。
  3. 我知道您需要更深层次地了解 Modbus。那时,一旦您的 C 程序中有一个开放的串行通道或(侦听)TCP 套接字,您就可以从简单的 Modbus 请求/响应开始。

Take a look at this short but quite complete description, and also at the documentation of this constantly updated library.

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



Here's a super-simplified RTU example for Linux, based on libmodbus.
Allow me some C99 relaxation for compactness.
In the real world you should also properly handle signals like SIGTERM, etc...
There's also a modbus_rtu_set_serial_mode(RS232 vs RS485) function for Linux kernels 2.6.28 onwards. You may find other libraries that make working with RS485 easier on your platform.

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

Master snippet

主代码段

//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);

Slave snippet

从属片段

//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);