Я бы не спешил давать какие либо советы, пока не выясниться что имеется ввиду, это дискретный сигнал, а не аналоговый, у него нет понятия потери связи, обрыв это ноль, замкнуто это единица
Вид для печати
Modbus RTU по RS485
Проблема решена, если нужна информация о том как разобраться, напишу сюда. Ибо на форуме сам ничего не нашел. Спасибо за подсказки по поводу битовой маски. Просто в OwenCloud нужно было чуть-чуть покопаться.
Ну хоть кто-то понял что работаем не через ПЛК. И на том спасибо.
Странный набор для раздела форума "ПЛК и Кодесис".Цитата:
у него только модуль, шлюз и облако
Добрый день. Есть ПЛК154 и ПЧ Электротекс ТТПТ-28-380-50-04. Требуется обеспечить управление по RS-485 (включение, выключение, считывание параметров и т.д.). Можно ли это сделать и как?
Теоретически можно. ПЧ имеет RS485, ПЛК тоже. Подробная документация на ПЧ доступна на офсайте производителя, там расписаны все регистры.
Не вижу особой проблемы.
Да, но в конфигураторе ПЛК Codesys у модбас мастера нет модбас-функции №5 (0x05) для записи значения одного флага (Force Single Coil). Поэтому отправить команду "ПУСК" в COILS 00001 не представляется возможным. Значит включить нельзя или это можно сделать другим способом... Но каким?
В принципе только старт\стоп передаются битами, остальное в регистрах. Если использовать управление стар\стоп от DO контроллера, а остальное читать\писать по цифре, то может получиться. Либо внимательно ковырять тему с "Функциональный блок FD01".
Есть предположение, что данный ПЧ очень похож на Данфосс.
нее, включать и выключать надо именно по 485 порту
Приветствую всех гуру Кодесис!
В проекте надо считать время достаточно точно. Желательная погрешность счёта времени +/ - 1 секунда за 10 часов. Изначально в проекте использовал задатчик секунд на R-триггере и разных таймерах , пробовал на блинке ( там погрешность достигает 15-20 сек. за 10 мин.) Потом перешёл по советам с сайта к счёту по функции T(), например
https://owen.ru/forum/showthread.php?t=10555&page=294
тут на странице 2 примера. Даже в эмуляторе, разница между двумя ФБ, за 30 мин работы, составляет 11 секунд. 11 секунд за 30 мин!!! В реальном железе (СП310 и ПЛК 154) за 1 час погрешность доходит от 10-12 сек. . Это просто жесть!!!
На данный момент нашёл выход в коррекции времени каждую 59 секунду. На обычном R-триггере и таймере TON. Добился точности хода 2 сек за 3 часа. Но это всё равно плохо. За 10 час набежит до 7 сек.
Есть ли у кого какие то наработки или мысли по этому поводу?
Первую функцию сегодня проверял в железе, перед этим проверяю программу в эмуляторе, что непонятно? По результатам проверки 1 функции написал выше, сейчас готовлю 2, завтра проверю в железе.
Сравнил точность хода в эмуляторе, даже тут дикая погрешноть, что ещё надо выложить?
Советую использовать системное время контроллера библиотекой CurTimeEx
Цитата:
GetTime: CurTimeEx;
TimeAndDate: SystemTimeDate;
Sys_Time: SysTime64;
Millisecond:UDINT;
Second,Second_old: UINT;(**)
TimeAndDate.Day :=0;
TimeAndDate.DayOfWeek :=0;
TimeAndDate.dwHighMsec :=0;
Millisecond:=TimeAndDate.dwLowMSecs;
TimeAndDate.dwLowMSecs :=0;
TimeAndDate.Milliseconds :=0;
TimeAndDate.Minute :=0;
Second:=TimeAndDate.Second;
TimeAndDate.Second :=0;
TimeAndDate.Hour :=0;
TimeAndDate.Year :=0;
TimeAndDate.Month :=0;
Sys_time.ulHigh :=0;
Sys_time.ulLow :=0;
GetTime (SystemTime:=Sys_Time , TimeDate:= TimeAndDate);
YEAR_S:=UINT_TO_STRING(TimeAndDate.Year);
MONTH_S:=UINT_TO_STRING(TimeAndDate.Month);
DAY_S:=UINT_TO_STRING(TimeAndDate.Day);
HOUR_S:=UINT_TO_STRING(TimeAndDate.Hour);
MIN_S:=UINT_TO_STRING(TimeAndDate.Minute);
SEC_S:=UINT_TO_STRING(TimeAndDate.Second);
cur_datetime_str:=concat(':',sec_s);
cur_datetime_str:=concat(MIN_S,cur_datetime_str);
cur_datetime_str:=concat(':',cur_datetime_str);
cur_datetime_str:=concat(hour_s,cur_datetime_str);
cur_datetime_str:=concat('-',cur_datetime_str);
cur_datetime_str:=concat(day_s,cur_datetime_str);
cur_datetime_str:=concat('-',cur_datetime_str);
cur_datetime_str:=concat(month_s,cur_datetime_str) ;
cur_datetime_str:=concat('-',cur_datetime_str);
cur_datetime_str:=concat(year_s,cur_datetime_str);
cur_datetime_str:=concat('dt#',cur_datetime_str);
Чего там делаете не видно. У меня ругаецца что файл поврежден
1.Пришлите в ПЛК из ноута счетчик миллисекунд из винды.
2.В момент получения в ПЛК запомните разницу между этим значением и TIME()
3.Через через час-два пришлите в ПЛК еще раз это счетчик.
4.Покажите разницу между второй посылкой и TIME() за вычетом разницы из п.2. Это и есть расхождение.
Здравствуйте! Вопрос по modbus.lib
Код:
Данный код без проблем записывает значения в дискретные выходы. (1-8)Цитата:
var
...
set_modbus:MB_WR_COILS;
end_var
set_modbus(
Enable:= TRUE,
Mode:= MB_RTU,
DevAddr:= Dev_adr,
firstaddr := 0,
quantity:=8,
buffer := buf,
ComHandle:= ,
TimeOut:= ,
Complete=> ,
Exception=> );
При этом
var
...
set_modbus:MB_RD_INPUTS; (*MB_RD_COILS тоже*)
end_var
set_modbus(
Enable:= TRUE,
Mode:= MB_RTU,
DevAddr:= Dev_adr,
firstaddr := 0,
quantity:=8,
buffer := buf,
ComHandle:= ,
TimeOut:= ,
Complete=> ,
Exception=> );[/QUOTE]
не считывает данные из дискретных входов (10001 - 10008)
Что я делаю неправильно?
Вложение 46978
OPC-сервер без проблем читает.
Странно, скачал файл на работе, у меня всё открылось, у меня Кодесис 2.3.9.41 (rus ).
Сегодня всё проверил по новой, на работе на компе, в эмуляции разброса между ФБ нет, считают одинаково, а вот расхождение с реальным временем на компе
составило 1 сек. за 1 час, файл прилагаю, там справа выведены часы реальные. Начало проверки в 13ч- 15м - 00с , конец 14-15-01, с каждого ФБ по 2 выхода, с первого булевый и DWORD без миллисекунд, со второго DWORD с миллисекундами и TIME и 4 рассчёта времени.
Далее ещё раз проверил оба ФБ в железе, оба показывают +11 сек. за час, то есть получается ко времени каждый раз добавляется время цикла.
Не нашел ответ в описании.
Скажите гуру, как в окне PLC_PRG(PRG- ST) искать начало IF или его окончание END_IF. Проект только начал, количество строк растет. Например в СИ редакторах скобка "{" и ее пара "}" всегда выделялись при наведении на них. Тут не как это не могу, как выделить пару- IF и её END_IF.
Никак, IDE слишком старое.
Только структурированными отступами.
спасибо. я так и думал. Но надеялся...
Всем привет! Подскажите, пожалуйста, а как можно внутри ST блока сбросить переменную с типом какой-нибудь структуры в её исходное состояние?
Например, у меня есть переменна, которая определена так:
Сам тип определён так:Цитата:
VAR
QUERY: typModbusExtendedQuery;
END_VAR
Цитата:
TYPE typModbusExtendedQuery :
STRUCT
SlaveAddress : BYTE;
FunctionCode : BYTE;
Read_StartAddress : UINT;
Read_Quantity : UINT;
Write_StartAddress : UINT;
Write_Quantity : UINT;
Write_Data : ARRAY[0..124] OF WORD;
END_STRUCT
END_TYPE
В начальный момент работы POU значения атрибутов этой переменной равны нулям. Далее, по ходу выполнения кода, значения этих атрибутов меняются, и в какой-то момент появляется необходимость получить эту переменную в определённом состоянии: иметь явно заданные SlaveAddress, FunctionCode, Read_StartAddress и Read_Quantity, но при этом иметь гарантированно сброшенные в ноль остальные атрибуты, в т.ч. обнулить массив Write_Data.
Вопрос: есть ли способ как-то переинициализировать эту переменную, чтобы затем задать только нужные атрибуты?
Я пробовал делать так:
и такЦитата:
QUERY := typModbusExtendedQuery;
и даже такЦитата:
QUERY := typModbusExtendedQuery();
но ни одна из этих конструкций не сработала, а гугл молчит как партизан. В качестве костыльного решения мне в голову приходит написание отдельной функции, которая будет затирать эту переменную, но может это всё-таки я дурак и есть проще способы? Просто мне в нескольких местах в коде нужно быть уверенным, что я получаю переменную только с явно заданными мною атрибутами, и что в других атрибутах не осталось мусора из других кусков кода.Цитата:
QUERY := typModbusExtendedQuery(SlaveAddress=1);
Буду признателен за помощь!
P.S. Только не предлагайте забить на ненулевые значения атрибутов, которые в данном конкретном случае можно оставить в "грязном виде", это всего лишь одна из множества ситуаций и хочется выработать универсальное решение.
Я так понял, задачу обнуления напрямую такой подход не решает, но позволяет внутри блока реализовать "самоочистку" при дёргании определённого входа. Подход интересный, пожалуй воспользуюсь им там, где возможно. Но метод не универсален, в частности - мне нужно обнулять переменную, которая является именно структурой, т.к. используется она в готовой библиотеке для которой недоступны исходные коды. Т.е. вопрос по прежнему актуален.
Добавлено: не сразу заметил, что экран ещё вниз скроллится, но о сути догадался :)
Придумал ещё два возможных способа обхода:
1) сделать функцию, которая будет возвращать созданный внутри неё пустой инстанс нужного типа;
2) сделать функцию, которая будет возвращать созданный внутри неё инстанс нужного типа, наполненный исходя из параметров, переданных функции. Проверил такой вариант на практике - нужно в явном виде тогда все параметры в функцию передавать. Или использовать вместо функции функциональный блок. Оба варианта мне как-то не особо нравятся.
Но вообще меня не покидает ощущение того, что это должно делаться как-то проще.
С самого начала я писал про 2 примера, создал по ним два ФБ, их и сравнивал, на данный момент остановился на втором ФБ, его удобней останавливать, сбрасывать и запускать.
Выложил файл для проверки в pro, но это не то что я проверяю в железе. Там вставляю второй ФБ (Vremia_iz_PLC_2) в свой проект и уже всё вместе проверяю.
У меня ПЛК 154АМ, в работе он нагревается до 45 град С, уже + к погрешности. У вас возможно 110 или 160.
вы проверяете только 1 ФБ, я целый проект со вставленным ФБ,
у меня в проекте около 12 REAL, постоянно отслеживается + возможно проект написан далеко не оптимально. Проект хотел вам отправить, но в личку нельзя, а выкладывать сюда не могу, по некоторым соображениям. Если только на мыло.
Из этого в сумме наверно и набегает 11 секунд.
Где вы берёте виндовый счетчик мсек, я так и не понял, но на второй картинке видно, что разница между часами винды и мсек в программе не 1 с, а 262 мсек. Поэтому про эмуляцию давайте забудем.
Ну тут как могу, чтобы быстрее, на ST это займёт у меня на данный момент раз в 100 больше времени.
какие функции, просто в окне обяъвлений создаете VAR CONSTANT, там вставляете QUERY_CONST: typModbusExtendedQuery;
(со всеми нужными значениями)
и в коде, в нужный момент времени QUERY := QUERY_CONST
так как раз Валенок практиковал и предлагал ранее здесь на форуме
ЗЫ ну он собственно про это уже написал
Во, то, что нужно! Хотя после более продвинутых языков программирования и выглядит это костыльно, но хотя бы внешние функции создавать не нужно.
2 Валенок:
Готовой либе я не могу подсунуть на вход ФБ, если она хочет структуру. А переписывать библиотеки производителя без исходников - можно, но есть проще способы получить желаемое.
Счёт присылайте, организую сбор роялти с каждого инстанса запущенного мною кода (но это не точно) :D
Ну и всем спасибо за подсказки )
Добрый день! Имеется 3 удалённых объекта, ПЛК110+ПМ01 по RS-485 и 1 диспетчерский пункт ПЛК110+ПМ01 по RS-485. Опрашивается статус (в сети,недоступен) и сигнал аварии с ПЛК. Возможно ли одновременный опрос 3 объектов по GPRS? Или хотя бы поочерёдный по CSD. Спасибо!
Все возможно если одну Sim сделать со статикой. Ну или CSD по очереди.
Добрый день.
В CDS 3.5 при использовании шаблонов модулей Мх110 для контроля их исправности периодически опрашивали переменную канала «Флаг ошибки».
Как проверять исправность модулей Мх110 в CDS 2.3?
У вас будет Modbus (master), там есть регистры Last address (DWORD) и Last error (WORD). Это регистры монитора связи. Например, если опрашиваемый модуль один, то можно опрашивать только Last error, при проблемах со связью значении в нем будет отличное от нуля. Если модулей больше, то оба регистра надо опрашивать синхронно.
Понял, спасибо. Буду тестировать.
Сегодня обнаружил, что в конфигурации задач у меня стоит циклический вызов PLC_PRG каждые t#200ms, видимо в начале при создании проекта случайно поставил. Ну думаю, вот откуда погрешность идёт, почти +12 сек за час (за 1 час насчитывало 1 ч. 12 с.). Удаление , очистка, компиляция, заливаю в ПЛК свою программу с изменениями. Сейчас правильно будет!
Барабанная дробь!!!
Меняется время цикла ПЛК, с (0,7-1)мс до 2 мс (стоит в настройках 5 мс) и время начинает считать медленнее реального, теперь примерно - 6 сек .
( за 1 час - 59 мин. 54 с.) Точнее ещё проверю, я просто в шоке.
Через браузер GetTime проверил время, за несколько месяцев время ушло на несколько секунд, то-есть сам ПЛК считает точно.
Обязательно перезаливать проект в плк что бы пошёл обмен данных на другом пк сервере scada
Почему на работает данный код?
Вместо этого приходится изменять переменную, а таймер вызывать безусловно в коде. Мне кажется, это больше нагружает контроллер, нежели этот код, если бы он работал.Код:PROGRAM PLC_PRG
VAR
TP1:TP;
END_VAR
IF TP1.ET = T#0ms AND NOT TP1.Q THEN (*таймер не запущен*)
TP1(IN:=TRUE, PT:=WORD_TO_TIME(1000*60)); (*запустили таймер на минуту*)
END_IF
IF NOT TP1.Q AND TP1.ET > T#0ms THEN (*таймер закончил отсчет*)
TP1(IN:=FALSE); (*сбрасываем таймер*)
END_IF