Попробуйте сами пока что перенести проект на другой ПК и проверить. Или закрыть и открыть CODESYS заново.
Я думаю, у вас на ПК информация о соединении просто прокэшировалась.
Вид для печати
Прошу помощи по рефакторингу. Задача есть мотор асинхронный кнопка ПУСК без фиксации кнопка СТОП с фиксацией и контроль за АВАРИЯМИ по току и температуре.
Код://интерфейс аварий
INTERFACE IAlarm
// Метод выключения Аварии
METHOD AlarmOff : BOOL
VAR_INPUT
END_VAR
// Метод включения Аварии
METHOD AlarmOn : BOOL
VAR_INPUT
END_VAR
// Интерфей Моторов
INTERFACE IMotor
// выключить мотор
METHOD MotorOff : BOOL
VAR_INPUT
END_VAR
// включить Мотор
METHOD MotorOn : BOOL
VAR_INPUT
END_VAR
---------------------------------------------
// класс мотор с отслеживанием аварии
FUNCTION_BLOCK classMotor IMPLEMENTS IMotor, IAlarm
VAR_INPUT
onMotor: BOOL;// запуск мотора
offMotor: BOOL;// выключение мотора
alarmKz: BOOL; //авария короткого замыкания
alarmTemp: BOOL;//авария по температуре
END_VAR
VAR_OUTPUT
motorOut: BOOL;//выход мотора
motorAlarmOut: BOOL;// выход аварии мотора
END_VAR
VAR
// Логика работы
motorTrigRs: Standard.RS;
statusMotor: BOOL;
statusAlarm: BOOL;
END_VAR
// запуск мотора
motorTrigRs(SET:= onMotor, RESET1:= offMotor OR motorAlarmOut);
IF motorTrigRs.Q1 THEN
MotorOn();
ELSE
MotorOff();
END_IF
motorOut:= statusMotor;
// отследить аварию мотора
IF alarmKz OR alarmTemp THEN
AlarmOn();
ELSE
AlarmOff();
END_IF
motorAlarmOut:= statusAlarm;
(* Метод выключения Аварии*)
METHOD AlarmOff : BOOL
statusAlarm:= FALSE;
(* Метод включения Аварии*)
METHOD AlarmOn : BOOL
statusAlarm:= TRUE;
(* выключить мотор*)
METHOD MotorOff : BOOL
statusMotor:= FALSE;
(* включить Мотор*)
METHOD MotorOn : BOOL
statusMotor:= TRUE;
--------------------------------------------
PROGRAM PLC_PRG
VAR
// блок моторов
// входы
InStartMotor_2:BOOL;// пуск мотора
InStopMotor_2: BOOL;// стоп мотора
// авария мотора
InAlarmKz_2,InAlarmTemp_2: BOOL;
// выходы мотора
Q_2Motor: BOOL;
Q_2Alarm: BOOL;
// объект мотор
objMotor_2: classMotor;
END_VAR
objMotor_2(onMotor:= InStartMotor_2,offMotor:= InStopMotor_2,// включить мотор
alarmKz:= InAlarmKz_2,alarmTemp:= InAlarmTemp_2,// отслеживаем аварию
motorOut=> Q_2Motor,motorAlarmOut=> Q_2Alarm);// визуализация выходов мотора и аварии
Здравствуйте коллеги, подскажите пожалуйста, как подключиться к симплскаде от ПЛК210? говорят, что можно как то через символьные переменные и по ОПС серверу(arOPC). Что нужно включить или настроить у ПЛК 210. чтоб подключиться?Вложение 72537
Добрый день.
Посмотрите примеры в этом документе:
https://ftp.owen.ru/CoDeSys3/11_Docu...5_OPC_v3.0.pdf
Как мне считать эти цифры? Вложение 72539
Вложение 72540 это я уже делал
Используйте вместо Modbus Poll другое ПО, в котором есть логи - например, Modbus Universal MasterOPC
https://masteropc.ru/download
Добрый вечер.
Подскажите пожалуйста, как правильно организовать задержку в цикле.
Поскольку из-за того что в string можно затолкать всего 255 символов, курл со всеми токенами и ботАйДи занимает 164 символа UTF-8 оставляя на сообщение около 45 символов UTF16
Оттого появилась задача - отправлять сообщения в телеграм с задержкой в 2 секунды в связи с ограничением API не более 30 сообщений в минуту и не более 1 в секунд.
Хотел затолкать TON прямо в начало цикла, типа wait. но не понимаю как его правильно прикрутить.
Код:IF eStatus <> Mx210Assistant.ANALOG_SENSOR_ERRORS.NO_ERROR
THEN xSensorError := TRUE;
wsErrorMessage := ANALOG_SENSOR_ERROR_TO_WSTRING(eStatus);
wsMessage := WCONCAT(wsSensorName,wsErrorMessage);
sCommand := OSU.ReplaceAllSubstrings(c_sCommand, '#TOKEN#', sToken);
sCommand := OSU.ReplaceAllSubstrings(sCommand, '#CHAT_ID#', sChatId);
sCommand := OSU.ReplaceAllSubstrings(sCommand, '#PARSE_MODE#', sParseMode);
STU.ConvertUTF16toUTF8(ADR(wsMessage), ADR(sUtf8Message), SIZEOF(sUtf8Message), FALSE);
sCommand := OSU.ReplaceAllSubstrings(sCommand, '#TEXT#', sUtf8Message);
ELSIF rValue > rHiSpDeviationLevel OR rValue < rLowSpDeviationLevel
THEN
rValueRound := OSCAT_BASIC.ROUND(rValue,2);
wsValueText := TO_WSTRING(rValueRound);
wsSetPointText := TO_WSTRING(rSetPoint);
wsMaxDevPerc := TO_WSTRING(iMaxDeviationPercent);
awsMessage[1] := wsSensorName;
awsMessage[2] := OSU.WCONCAT8("Отклонился от уставки", wsSetPointText, " более чем на ", wsMaxDevPerc, "%");
awsMessage[3] := OSU.WCONCAT4("Текущее значение датчика", wsValueText, wsUnitsName, "");
FOR i := 1 TO 3 DO
sCommand := OSU.ReplaceAllSubstrings(c_sCommand, '#TOKEN#', sToken);
sCommand := OSU.ReplaceAllSubstrings(sCommand, '#CHAT_ID#', sChatId);
sCommand := OSU.ReplaceAllSubstrings(sCommand, '#PARSE_MODE#', sParseMode);
STU.ConvertUTF16toUTF8(ADR(awsMessage[i]), ADR(sUtf8Message), SIZEOF(sUtf8Message), FALSE);
sCommand := OSU.ReplaceAllSubstrings(sCommand, '#TEXT#', sUtf8Message);
END_FOR
ELSE
xSensorOK := TRUE;
END_IF
не получается
Вложение 72542
beatitas Я делал на СМСках от обратного: брал таймер BLNIK и раз в NN секунд просматривал очередь сообщений.
Если там что-то было - отправлял.
Благодарю.
Буду пробовать, но это усложняет задачу на написание буфера для очереди сообщений. Пока вообще не понимаю с какой стороны к нему подходить и на чём основывать. SQL базу прикручивать, как это делается в вебе? Но он точно нужен, на случай массового отвала датчиков)
Если все страдания из-за гипотезы о том, что "в string можно затолкать всего 255 символов" - то она неверна.
https://owen.ru/forum/showthread.php...l=1#post289762
https://owen.ru/forum/showthread.php...l=1#post361101
Я делал примерно так:
1. Структура - описание элемента очереди. У неё была строка сообщения, номер адресата (для СМСок) и флаг "активно" (Active).
Этот флаг был нужен алгоритму перебора очереди, чтобы понимать что этот элемент ещё не отправлен.
2. Массив этих структур - сама очередь. Выбрал его жёсткие границы и сделал их в виде константы с названием типа MAX_QUEUE_SIZE для того, чтобы во всех циклах и проверках её использовать, и не было жёстко заданных магических чисел из-за которых циклы выйдут за границы массива.
Это объявляется примерно так:
VAR CONSTANT
MAX_QUEUE_SIZE : WORD := 64;
END_VAR
VAR
arrQueue : ARRAY [1..MAX_QUEUE_SIZE] OF SMSItem;
END_VAR
3. Функция "Добавить в очередь". Она в цикле перебирает весь этот массив и ищет элемент, в котором Active = FALSE, заполняет его нужными данными и ставит Active = TRUE.
Это простой цикл с условием: как только нашли Active = FALSE, делаем нужное действие и по EXIT; выходим из цикла.
4. Функция "Обработка очереди". Там тоже цикл. Но он ищет первый элемент с Active = TRUE и закидывает данные из него в модем, а сам элемент помечает как Active = FALSE. Выход - тоже по EXIT;.
Её мы и вызываем по таймеру не чаще, чем нужно.
Во! =)
Вы зачем-то этому параметру 100 задали.
Задайте 0 - и все станет нормально.
Вложение 72556
beatitas Пожалуйста!
Благодарю. Нашёл в OSCAT.basic FIFO12/32. Завтра попробую переделать для wstring. Но всё равно пока не понимаю с какой стороны к нему задержку прикручивать. Если я правильно понимаю - то BLINK на RD. Но как тогда писать - сенсоры же опрашиваются внутри одного цикла ПЛК. Или можно его несколько раз триггерить за цикл? Надо эксперементировать))
Записывать нужно всё сколько событий придет, а читать через заданное время, на чем не принципиально, блинк это или таймер или в отдельной задаче с нужным временем цикла
нужно мнение спеца по ООП хочу сделать библиотеку что бы каждый раз не писать кучу кода.
Здравствуйте коллеги, пытаюсь со скады достучаться до ПЛК210(символьные переменные включил Вложение 72614 ) по CoDeSys.OPC.DA при этом появляется сообщение с ошибкой Вложение 72615 . Подскажите, как то можно достучаться со скады до ПЛК по OPC.DA?
Здравствуйте . к плк 210 две недели без проблем мог подключаться по веб интрефейсу. решил так же как обычно подключиться и сегодня и вот такой результат:
/usr/lib/lua/5.1/luci/dispatcher.lua:507: bad argument #1 to 'pairs' (table expected, got nil)
stack traceback:
[C]: in function 'pairs'
/usr/lib/lua/5.1/luci/dispatcher.lua:507: in function 'createtree'
/usr/lib/lua/5.1/luci/dispatcher.lua:220: in function 'dispatch'
/usr/lib/lua/5.1/luci/dispatcher.lua:112: in function </usr/lib/lua/5.1/luci/dispatcher.lua:111>
это как считается нормально? без причин
если часто такие будут проблемы
/usr/lib/lua/5.1/luci/dispatcher.lua:507: bad argument #1 to 'pairs' (table expected, got nil)
stack traceback:
[C]: in function 'pairs'
/usr/lib/lua/5.1/luci/dispatcher.lua:507: in function 'createtree'
/usr/lib/lua/5.1/luci/dispatcher.lua:220: in function 'dispatch'
/usr/lib/lua/5.1/luci/dispatcher.lua:112: in function </usr/lib/lua/5.1/luci/dispatcher.lua:111>
и если мне понадобится менять настройки в контроллере, то есть ли альтернативные варианты, обойтись без веб интерфейса??????????????????
Здравия, Всем!
Прошёл обучение на СПК на CFC, понятия поверхностные имею, сильно не бейте.
Хочу "подружить" по Modbus "левое" устройство.
Вопрос:
1. На вкладке "Канал Modbus" в Codesys двигал их (каналы) кнопками "Выше/Ниже", в результате на вкладке "Соотнесение каналов" появились дубли. Уже был ответ, что перебивать заново. Зачем тогда этот функционал "Выше/Ниже", если это приводит к необратимым последствиям? Как правильно пользоваться этими кнопками (двигать каналы)? И можно ли? Можно-ли переименовать канал без последствий? И как?
2. Код функции требуется 0x10. Нашёл на форуме, что через библиотеку OwenCommunication. А как по конкретнее? Через блок OCL.COM_Control, а также следом через OCL.MB_SerialRequest?
3. Сколько каналов можно организовать в Codesys, из опыта работы, чтоб особо не тормозило?
Добрый день.
1. Эту ошибку исправили в версии плагина Modbus 4.3.0.0.
2. Запрос с кодом функции 0x10 можно отправить как через OwenCommunication (и в этом случае ваше описание верно; подробнее см. в документе CODESYS V3.5. Modbus), так и через канал в дереве проекта (о которых вы спрашиваете в предыдущем вопросе).
3. Если речь о RS-485 - то сколько угодно, потому что в каждый момент времени обрабатывается только один канал.
Естественно, чем больше каналов, тем больше будет полный период опроса всех каналов в пределах данной шины.
Евгений Кислов! Вы гениальный человек! - Сообщений 11 657.
Благодарю за оперативный ответ!
... пошёл "курить" плагин Modbus. Вопросов стало не меньше.
Обновил Modbus до - 4.3.0.0.package (27-Jul-2023 13:02, 14M).
Пофиксены ошибки:
MODBUS-59 Bug: Old channels are not deleted after moving and reconfiguration (Старые каналы не удаляются после перемещения и реконфигурации);
MODBUS-146 ModbusEditorBug: number of channels is limited to 10 (Редактор Modbus: количество каналов ограничено 10)
... и много других.
Буду тестировать. Код функции 0x10 не увидел, вероятно, я ещё чего-то не догоняю "в дереве проекта".
Вопрос: есть ли некие такие правила неписанные или писанные, что и какие каналы создавать в начале, а какие в конце?
Например, сначала все Input`ы (запись в выходы), а потом "Читать" все входы или наоборот. Что для контроллера приоритетней в первую очередь и менее нагрузочно?
Читать 100 каналов (параметров) это нормально? Или перебор? Или такое "чтение" сделать - по событию, раз в минуту, допустим?
Вложение 72642Цитата:
Буду тестировать. Код функции 0x10 не увидел, вероятно, я ещё чего-то не догоняю "в дереве проекта".
16 - это 0x10
Для контроллера это не имеет значения.Цитата:
Вопрос: есть ли некие такие правила неписанные или писанные, что и какие каналы создавать в начале, а какие в конце?
Например, сначала все Input`ы (запись в выходы), а потом "Читать" все входы или наоборот. Что для контроллера приоритетней в первую очередь и менее нагрузочно?
Критерии "нормальности" для конкретной системы определяете вы (или автор ТЗ), равно как и настройки опроса (циклический или событийный, периоды и т. д.).Цитата:
Читать 100 каналов (параметров) это нормально? Или перебор? Или такое "чтение" сделать - по событию, раз в минуту, допустим?