Tools


«Сименс» в России

«Сименс» в России

Опрос различных устройств по Modbus RTU

Логические модули LOGO!, базовые контроллеры SIMATIC S7-1200

Модераторы: anna_razgoeva, gulenok_andrey

Alex_NN
Сообщения: 55
Зарегистрирован: 14 июн 2018, 12:28

Сообщение Alex_NN » 21 янв 2022, 14:01

Добрый день.
Задача такая - опросить по Modbus RTU два различных устройства с различной длиной и структурой данных.
Используется PLC 1214 и CB 1241.
Вопрос по использованию инструкции Modbus_Master.
1. Целесообразно ли использовать в данном случае одну инструкцию и подкладывать ей различные параметры опроса?
Если да, то переменную с каким типом данных нужно привязать к параметру DATA_PRT инструкции и как в эту переменную положить указатели на области данных?
2. Или проще все же использовать две инструкции Modbus_Master?
Понятно, что второй вариант проще, но можно ли сделать по первому варианту?

Potapov
Сообщения: 460
Зарегистрирован: 16 апр 2018, 16:32

Сообщение Potapov » 24 янв 2022, 19:27

может проще использовать Модбус_Клиента ? :)
Изображение
Для такого количества клиентов нет смысла "мультиплексировать" данные для разных устройств = нагляднее в поисках проблем с устройствами выделять каждой по функции = сразу видно на каком клиенте споткнулся.
http://s7detali.narod.ru/S7_1200/CM1241_2.html

Alex_NN
Сообщения: 55
Зарегистрирован: 14 июн 2018, 12:28

Сообщение Alex_NN » 25 янв 2022, 08:13

Potapov писал(а):
24 янв 2022, 19:27
Для такого количества клиентов нет смысла "мультиплексировать" данные для разных устройств = нагляднее в поисках проблем с устройствами выделять каждой по функции = сразу видно на каком клиенте споткнулся.
Согласен, что в данном случае это нагляднее.
Но вопрос остался. Возможно ли реализовать "мультиплексирование" для параметра DATA_PTR, если хочется сделать все на одной инструкции Modbus_Master?

MaksimNT
Сообщения: 17
Зарегистрирован: 18 май 2019, 08:51

Сообщение MaksimNT » 27 янв 2022, 15:44

Пример кода
// сброс флага выполнения шагов и обнуление шагов при недопустимых параметрах или по достижению максимального шага *)
IF "ConnPtP".iStep < 0 OR "ConnPtP".iStep > "ConnPtP".iStep_MAX THEN
"ConnPtP".iStep := 0;
"ConnPtP".bRun := FALSE;
"ConnPtP".bRead_CMD := FALSE;
END_IF;

// если шаг сконфигурирован
IF "ConnPtP".Par["Connect_PtP_1".iStep].bEn = 1 THEN
// и команда чтения, то
IF "ConnPtP".bRead_CMD = 1 THEN
// Присвоение параметров чтения текущего шага
"ConnPtP".iMB_ADDR := "ConnPtP".Par["Connect_PtP_1".iStep].iMB_ADDR;
"ConnPtP".iMODE := "ConnPtP".Par["Connect_PtP_1".iStep].iMODE;
"ConnPtP".dDATA_AD := "ConnPtP".Par["Connect_PtP_1".iStep].dDATA_AD;
"ConnPtP".iDATA_LEN := "ConnPtP".Par["Connect_PtP_1".iStep].iDATA_LEN;
CASE "ConnPtP".iStep OF
0:
"RAEL_Word_DB"(rIN:="DRV".RW[0].rSP1_08w,
wLWord=>"Connect_PtP_1".Rdata[1],
wHWord=>"Connect_PtP_1".Rdata[0]);
END_CASE;
END_IF;

ELSE
// если нет конфигурации шага, то сбрасываем команду чтения
"ConnPtP".bRead_CMD := FALSE;
END_IF;

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// вызов функционального блока Modbus_Master
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

// условия вызова запроса при флаге чтения, и команде чтения , и блок не занят, и порт иницализирован удачно
"ConnPtP".bREQ := "ConnPtP".bRun AND "ConnPtP".bRead_CMD AND NOT "ConnPtP".bBusy AND "ConnPtP".bCLDONE;

"Modbus_Master_PtP_1"(REQ := "ConnPtP".bREQ,
MB_ADDR := "ConnPtP".iMB_ADDR,
MODE := "ConnPtP".iMODE,
DATA_ADDR := "ConnPtP".dDATA_AD,
DATA_LEN := "ConnPtP".iDATA_LEN,
DONE => #bMB_DONE,
BUSY => "ConnPtP".bBusy,
ERROR => #bMB_Error,
STATUS => #wStatus,
DATA_PTR := "ConnPtP".Rdata);

// если вызов запроса выполнен на текущем шаге, то сбрасываем команду чтения
IF "ConnPtP".bREQ = 1 THEN
"ConnPtP".bRead_CMD := FALSE;
END_IF;

// если флаг аварии
IF #bMB_Error = 1 THEN
// то запоминаем ошибку обмена текущего шага
"ConnPtP".Par["Connect_PtP_1".iStep].bOK := FALSE;
"ConnPtP".Par["Connect_PtP_1".iStep].wStatus := #wStatus;
// счетчик ошибок увеличиваем
"ConnPtP".dCount_R_Err := "ConnPtP".dCount_R_Err + 1;
// переходим к следующему шагу
"ConnPtP".iStep := "ConnPtP".iStep + 1;
// обнуляем область чтения
FOR #iN_01 := 0 TO 15 DO
"ConnPtP".Rdata[#iN_01] := 0;
END_FOR;
"ConnPtP".bRead_CMD := TRUE;

// если флаг качественного чтения
ELSIF #bMB_DONE = 1 THEN
// то запоминаем качественный обмен текущего шага
"ConnPtP".Par["Connect_PtP_1".iStep].bOK := TRUE;
"ConnPtP".Par["Connect_PtP_1".iStep].wStatus := 16#00;
"ConnPtP".dCount_R := "ConnPtP".dCount_R + 1;
CASE "ConnPtP".iStep OF
2:
"DRV".RW[0].w2 := "ConnPtP".Rdata[0];
"DRV".RW[0].w3 := "ConnPtP".Rdata[1];

"Word_RAEL_DB"(wLWord:="Connect_PtP_1".Rdata[3],
wHWord:="Connect_PtP_1".Rdata[2],
OUT=>"DRV".RW[0].rX2_02);

"Control_PtP".iHeat_RWF55 := "Control_PtP".iHeat_RWF55 + 1;

3:
...

4:
....

END_CASE;

// если освободилась функция Modbus_Master и флаге чтения
ELSIF "ConnPtP".bBusy = 0 AND "ConnPtP".bRun = 1 THEN
// переходим к следующему шагу
"ConnPtP".iStep := "ConnPtP".iStep + 1;
// обнуляем область чтения
FOR #iN_01 := 0 TO 15 DO
"ConnPtP".Rdata[#iN_01] := 0;
END_FOR;
"ConnPtP".bRead_CMD := TRUE;
END_IF;

cron