Создайте простой клиент / сервер с помощью Modbus на C

В настоящее время я работаю над проектом, который позволит различным автоматам общаться. Для этого я хотел бы создать клиента и сервер, которые будут общаться по протоколу Modbus. Я не уверен, хочу ли я сейчас использовать ModBus / TCP, ModBus / RTU или ModBus / ASCII.

Я искал примеры клиент / сервер на C, и я мог найти библиотеки, но не простой пример общения. Я хотел бы начать с нуля, поэтому библиотеки - это не то, что мне нужно.

Я прошу, чтобы кто-нибудь мог дать мне простой код, написанный на C, для клиента и / или сервера, которые обмениваются данными с использованием Modbus, поскольку я не уверен, что я буду использовать любой тип Modbus, было бы большим подспорьем. (RTU / TCP / ASCII).

Чем проще, тем лучше. Я бы хотел, чтобы код продемонстрировал, например: инициализацию на сервере, запрос, ответ, закрытие соединения.

Большое спасибо за уделенное время.


person PiggyGenius    schedule 13.04.2015    source источник
comment
Если я правильно понял, ModbusTCP - это просто обычное TCP-соединение, в котором данные структурированы как Modbus. Я уже создал TCP-сервер / клиент, так что все должно быть в порядке. Таким образом, меня больше интересует последовательная реализация, такая как RTU, в которой я полностью потерялся.   -  person PiggyGenius    schedule 13.04.2015
comment
Один способ - редактирование с обновлением прогресса, другой - вознаграждение, но вы должны подождать как минимум два дня. Впрочем, следите за обновлениями, я что-то пишу :)   -  person matpop    schedule 14.04.2015


Ответы (1)


Три вещи:

  1. Поскольку вы разрабатываете свои собственные клиентские и серверные компоненты, я предлагаю вам использовать Modbus только в том случае, если это строго необходимо или удобно с учетом открытости (т. Е. Другие производители должны иметь возможность связываться с вашими клиентскими или серверными компонентами посредством стандартизованного протокола. - и Modbus подходит).
  2. Имейте в виду, что Modbus TCP - это не просто Modbus RTU (/ ASCII) поверх TCP / IP (что, конечно, все еще разрешено, также будет разрешено UDP). Следует учитывать несколько важных отличий.
  3. Я понимаю, что вам нужно понимать Modbus на более глубоком уровне. В этот момент, когда у вас есть открытый последовательный канал или (прослушивающий) TCP-сокет внутри вашей программы C, вы можете просто начать с простых запросов / ответов Modbus.

Взгляните на это краткое, но довольно полное описание, а также на документацию этого постоянно обновляемая библиотека.


Вот супер-упрощенный пример RTU для Linux, основанный на libmodbus.
Позвольте мне немного смягчить C99 для компактности. < br> В реальном мире вы также должны правильно обрабатывать такие сигналы, как SIGTERM и т. д ...
Также есть функция modbus_rtu_set_serial_mode (RS232 vs RS485) для ядер Linux 2.6.28 и новее. Вы можете найти другие библиотеки, которые упрощают работу с 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);
person matpop    schedule 14.04.2015
comment
Большое спасибо за ваш ответ, я терял надежду. Я вынужден использовать Modbus, и даже если бы я не был в той ситуации, над которой я работаю, использование Modbus является логическим решением. Да, я понял, что Modbus TCp - это не RTU или ASCII поверх TCP, я имел в виду, что Modbus TCP похож на любое TCP-соединение, единственная разница - это структура данных (верно?). Спасибо за ссылки, у меня уже есть библиотека modbus, но мне очень нужен пример на C, который не использует какую-либо библиотеку. - person PiggyGenius; 15.04.2015
comment
Да, это то, что я говорил в своем третьем пункте. Думаю, это неплохо объяснили здесь. - person matpop; 15.04.2015
comment
Что ж, они объясняют, как это сделать, но я хотел бы, чтобы письменный пример (в лучшем случае на C, но другой язык был бы в порядке), чтобы убедиться, что я правильно понимаю, прежде чем я начну реализовывать этот протокол связи. Кажется, вы немного знаете о Modbus, может быть, вы могли бы написать короткий код, показывающий взаимодействие Modbus RTU или ASCII (я понимаю Modbus TCP) между клиентом и сервером? Я буду любить тебя за это! - person PiggyGenius; 15.04.2015
comment
Просто обновляю, что я все еще придерживался последовательной связи Modbus, будь то RTU или ASCII. - person PiggyGenius; 16.04.2015
comment
Учитывая все, что вы сказали, в конце концов, я действительно думаю, что в вашем случае было бы очень неразумно начинать с нуля. Хотя очень важно, чтобы вы понимали детали вариантов протокола Modbus, я рекомендую вам не изобретать велосипед и использовать существующую библиотеку C, которая подходит для вашей платформы. Я собираюсь опубликовать упрощенный пример RTU (в настоящее время ASCII фактически унаследован), основанный на libmodbus, как только у меня будет время. В таких программах вы просто указываете имя устройства ОС (например, / dev / ttyS0, COM6); Вам решать, чтобы это устройство работало как последовательное соединение rs232 / rs485. - person matpop; 16.04.2015
comment
Хорошо, это не пример с нуля, но все же очень, очень, очень полезный. Большое спасибо, что нашли время помочь совершенно незнакомому человеку, вы то, что хорошо на этой планете !! (Если вы можете прокомментировать код, будет еще лучше). - person PiggyGenius; 16.04.2015
comment
Я, конечно, прокомментирую, но вам придется подождать максимум пару дней, а? :) - person matpop; 16.04.2015
comment
Да, конечно, чем раньше, тем лучше, но я могу подождать. - person PiggyGenius; 16.04.2015
comment
Большое спасибо за код, я постараюсь реализовать его, как только смогу, я поражен временем, которое вы потратили на то, чтобы мне помочь, и большое вам спасибо. - person PiggyGenius; 20.04.2015
comment
@matpop Ваш код избавил меня от страданий. Я хотел реализовать раб, но не нашел примеров. Я могу просматривать регистры хранения в моем симуляторе Modbus, но как мне отобразить значение входного регистра 1 в моем коде c, если я установил его из своего симулятора. Заранее спасибо. - person S.I.J; 29.01.2016