Tag Archives: codesys 2.3

Подключение устройств по интерфейсу RS-485

При подключении нескольких устройств в сеть RS-485 необходимо учитывать, что приборы в данной сети должны подключаться последовательно один за другим. Например, если есть три прибора — X1, X2, X3, у каждого прибора есть клеммы A1, B1, A2, B2, A3, B3 соответственно. В таком случае провод идет с клеммы A1 на клемму A2 и затем с клеммы A2 на клемму A3. Аналогично с кабелем B. C клеммы B1 кабель идет на клемму B2 и потом с клеммы B2 на клемму B3. Схематично это изображено на Рисунке 1.

 

Рис.1. Подключение приборов по RS-485

Максимальная длина линии связи между крайними устройствами может составлять до 1200м (и более с использованием повторителей). При длине линии связи более 100м в максимально удаленных друг от друга точках сети рекомендуется устанавливать оконечные согласующие резисторы номиналом от 100 до 250 Ом, позволяющие компенсировать волновое сопротивление кабеля и минимизировать амплитуду отраженного сигнала.

Сеть RS-485 не поддерживает подключения звездой, то есть на клеммы прибора-мастера нельзя сразу подключать два или более устройств.

Для примера рассмотрим пример подключения панели оператора ИП-320, модуля дискретного ввода-вывода МДВВ и программируемого логического контроллера, который в данном случае выполняет роль Мастера сети. Пример правильного последовательного подключения приведен на Рисунке 2.

Рис. 2. Пример правильного подключения

На Рисунке 3 приведен пример неправильного подключения – топология звезда. При данном подключении работа в сети RS-485 будет вестись некорректно.

Рис. 3. Пример неправильного подключения

    Эмулятор ОВЕН ТРМ1

    ПЛК100 (Master) + ИП320 (Slave) + МВА8 (Slave)

    Эмулятор ТРМ1

     

     

    Задача:

    1)      Эмуляция работы ТРМ1

    2)      Опрос входа МВА (получение температуры)

    3)      Обработка в контроллере данных, полученных с МВА

    4)      Передача данных на панель для отображения температуры

    5)      Установка уставки, гистерезиса и режима работы с панели

    6)      Контроллер работает в качестве мастера

    Решение задачи

    1)     Сетевые параметры

    — Контроллер  — Мастер

    — Адрес Панели Оператора ИП320 – 1

    — Адрес Модуля Ввода  МВА8 – 16

     

    2)     Регистры для обмена данными в сети

     

    Имя переменной Адрес Регистра Назначение
    Параметры для обмена с МВА8
    T_MVA 1 Опрос температуры с МВА в целочисленном формате со сдвигом 2 знака
    Параметры для обмена с ИП320
    T_IP_TX 5 Передача в панель температуры в целочисленном формате со сдвигом 2 знака для отображении в численном виде
    T_IP_GR 6 Передача в панель температуры в целочисленном формате без сдвига для вывода на график
    Ust 7 Регистр для вывода уставки в панель в целочисленном формате, со сдвигом 2 знака
    Ust_inp 8 Регистр для получения нового значения уставки с панели в целочисленном формате, со сдвигом 2 знака
    Gist 9 Регистр для вывода гистерезиса в панель в целочисленном формате, со сдвигом 2 знака
    Gist_inp 10 Регистр для получения нового значения гистерезиса с панели в целочисленном формате, со сдвигом 2 знака
    Rejim 11 Регистр для вывода режима работы котроллера (нагреватель — холодильник)
    Rejim_inp 12 Регистр для получения нового режима работы котроллера (нагреватель — холодильник)
    Rele_b 13 Регистр для чтения статуса индикатора выходного реле
    screen 15 Регистр для получения текущего номера экрана панели
    Screen_in 16 Регистр для сметы текущего экрана панели
    auto 17 Регистр разрешения автоматического переключения экранов панели
    Параметры для обмена с ИП320 (для инициализации панели)
    U_ret 8 Запись в панель уставки из энергонезависимой памяти
    G_ret 10 Запись в панель гистерезиса из энергонезависимой памяти
    R_ret 12 Запись в панель режима работы из энергонезависимой памяти

     

    3)     Описание Экранов и назначения клавиш панели ИП320

    Основное назначение панели – это вывод температуры на экран и установка параметров работы эмулятора ТРМ1. В качестве примера была взята упрощенная модель работы ТРМ1. Модель предполагает, что ТРМ1 работает в двух режимах – прямой гистерезис и обратный. Для реализации этих двух режимов необходимо задавать уставку, гистерезис и сам режим работы ТРМ1.

    При подачи питания на контроллер, в контроллере ПЛК запускается алгоритм инициализации панели, данные для которой хранятся в энергонезависимой памяти контроллера.

    В панели ИП 320 реализованы 4 экрана:

    Базовый — для вывода основных параметров работы прибора

    Установка параметров — для задания уставки и гистерезиса

    Установка режима работы — для выбора режима работы ТРМ1

    График — для вывода температуры в виде графика

     

    Подробное описание экранов и работы с ними:

    Рис.1 Базовый экран

     

    Базовый:

     

    Данный экран предназначен для просмотра измеряемой температуры, вывода графика и вывода текущих значений уставки и гистерезиса. Также индикатор отображает состояние выходного реле. Данный экран не позволяет менять параметры.

    Все параметры читаются из регистров указанных на рисунке 1. Индикатор соответствует логическому состоянию регистра 13 бита 0 (соответствует биту 208). Динамический текст выводится в соответствии с содержимым регистра 13, в данном регистре используется только 0-й бит, который может находиться в 2-х состояниях TRUE и False – что будет соответствовать числам 1 и 0 в десятичной системе счисления (в зависимости от этого значения в панели задается выводимый текст).

    С помощью кнопки  8 можно перейти в режим автоматического переключения экранов панели. Экраны переключаются ПЛК циклически, в том случае если в регистре 17 бит 0 (соответствует буту 272) равен 1. Кнопка 8 работает в реверсивном режиме, то есть при каждом нажатии заданный бит меняется на противоположное состояние (0 либо 1).

    При нажатии на кнопку 9 происходит переход на экран дата-время, выход с этого экрана осуществляется нажатием кнопки ESC.

    Установка параметров:

     

     

    Рис. 2 Экран установки параметров

    Экран установки параметров предназначен для задания значений уставки и гистерезиса. На экране отображаются четыре числовых значения. Значения, которые находятся напротив “OLD” являются текущими, и отображают реальные значения уставки и гистерезиса. Значения, которые стоят напротив “NEW” предназначены для ввода новых значений уставки и гистерезиса. Редактируемые значения защищены паролем, и их редактирование запрещено.

    Для разрешения записи новых значений необходимо перейти на экран пароля и выбрать меню “Открыть доступ”. Далее откроется экран ввода пароля, в котором необходимо будет ввести пароль с помощью стрелок на панели (пароль 11).

    После открытия доступа кнопкой SET можно выбрать редактируемый параметр (из группы NEW) и ввести его новое значение, после чего нажать кнопку ENT, чтобы его записать. Через небольшой промежуток времени в группе NEW отобразится новое введенное значение.

    Запись новых значений реализуется путем записи нового значения из регистров Input  в регистры Output.

    После окончания редактирования параметров по необходимости можно перейти на экран пароля и закрыть доступ, для защиты параметров от их дальнейшего изменения.

    Как и в базовом экране, кнопка 8 включает, или выключает автопрокрутку экранов.

    Установка режима работы:

    Рис. 3 Экран установки режима работы

    Данный экран позволяет установить режим работы ТРМ1 нажатием кнопок 0 или 1 на панели оператора. Режим работы при нажатии на данные клавиши будет меняться в том случае, если на экране пароля был открыт доступ, в противном случае кнопки будут не функциональны. После Выбора режима путем нажатия соответствующей кнопки на экран будет выведен номер текущего режима.

    Переход на экран пароля осуществляется при помощи кнопки +/-.

    Кнопка 8 включает или отключает автопрокрутку экранов.

    Рис. 4 Экран график

    График:

    Экран графика представляет, выводит график температуры, но в более крупном масштабе, чем на экране 1 (Базовый).

    Кнопкой 8 включается автоматическая прокрутка экранов.

    Параметры настройки панели:

     

    Рис. 5 Настройки панели

    В настройках проекта конфигуратора ИП320 необходимо задать пароль для ввода его на экране пароля. Также указывается номер регистра для работы с экранами панели.

    При необходимости можно задать список тревог, в случае которых на экран будет выдаваться сообщение, до тех пор пока данная ситуация имеет место, либо по нажатии кнопки Esc. В данном примере реализована одна тревога – включение реле.

    Список тревог

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Рис. 6 Список тревог

     

    Температурный график с заданием от панели

    Пример формирования графика температуры отопления в зависимости от температуры наружнего воздуха с реализацией ночного режима работы.

    Функциональный блок экспортирован, для вставки в проект необходимо сделать импорт.

    FUNCTION_BLOCK Graph_Temp

    VAR_INPUT

    Temp_in:REAL;    (*Температура наружнего воздуха*)

    Temp_NV_A:WORD;         (*температура воздуха первой точки графика (с панели)*)

    Temp_NV_B:WORD;         (*температура воздуха второй точки графика (с панели)*)

    Temp_otopl_A:WORD;         (*температура отопления , первая точка графика (с панели)*)

    Temp_otopl_B:WORD;         (*температура отопления , вторая точка графика (с панели)*)

    tmp_N: WORD;  (*снижение температуры ночью на Х градусов (с панели)*)

    In_night_on: BOOL; (*разрешение включения ночного режима*)

    time_night_in: BOOL; (*время включения ночного режима настало*)

    END_VAR

    VAR_OUTPUT

    Zad: REAL;           (*вычисленное по графику задание температуры отопления*)

    END_VAR

    VAR

    koef1:REAL;          (*коэффициент уравнения прямой*)

    Temp_otopl_B_: REAL;

    Temp_otopl_A_: REAL;

    Temp_NV_A_: REAL;

    Temp_NV_B_: REAL;

    tmp_N_: REAL;

    zad_N: REAL; (*снижение задания на ночное время*)

    zad_G: REAL; (*задание по графику*)

    END_VAR

    Temp_otopl_B_:=WORD_TO_REAL(Temp_otopl_B)/10; (*преобразование форматов данных полученных с ИП320*)

    Temp_otopl_A_:=WORD_TO_REAL(Temp_otopl_A)/10;

    Temp_NV_A_:=WORD_TO_REAL(Temp_NV_A)/10;

    Temp_NV_B_:=WORD_TO_REAL(Temp_NV_B)/10;

    tmp_N_:=WORD_TO_REAL(tmp_N)/10;

    koef1 :=  (Temp_otopl_B_ — Temp_otopl_A_)/(Temp_NV_B — Temp_NV_A_)  ; (*коэфициенты уравнения*)

    (*формирование графика*)

    IF (Temp_in >= Temp_NV_A_) THEN

    zad_G := Temp_otopl_A_;

    END_IF

    IF ((Temp_in <Temp_NV_A_) AND (Temp_in >=Temp_NV_B)) THEN

    zad_G := Temp_otopl_A_ + koef1 * (Temp_in — Temp_NV_A_);

    END_IF

    IF (Temp_in <Temp_NV_B) THEN

    zad_G := Temp_otopl_B;

    END_IF
    (*формирование ночного графика*)

    IF (In_night_on=TRUE AND time_night_in=TRUE AND (zad_G- tmp_N_<= zad_G-zad_N) ) THEN

    zad_N:= zad_N +0.00001;

    END_IF

    (*снижение и увеличение температуры происходит со скоростью 0.2-0.3 градуса в минуту и зависит от цикла ПЛК, кому не нравиться переписывайте на внешнее время*)

    IF (In_night_on=TRUE AND time_night_in=FALSE AND zad<=zad_G  ) THEN

    zad_N:= zad_N -0.000001;

    END_IF
    (*общее формирование задания*)

    IF In_night_on=TRUE THEN

    zad:=zad_G-zad_N;

    ELSE

    zad:=zad_G;

    zad_N:=0;

    END_IF

    END_FUNCTION_BLOCK

    Управление 3 насосами

    Алгоритм предназначен для управления 3-мя насосами (или другими обьектами требующими чредование времени работы,например тремя водогрейными котлами),  каждый из которых снабжен своим датчиком   (или иным сигналом обратной связи). Одновременно работают два объекта из трех. По истечении  заданного времени  происходит переключение работающих  насосов.

    Листинг

    VAR_INPUT

    Run: BOOL; (*сигнал начала работы программы ротации*)

    Time_Rotat_in:WORD; (*время работы насосов, в часах*)

    Time_zad_on_in: WORD; (*время задержки перед началом работы алгоритма , в секундах*)

    Time_Nech_in: WORD; (*время, в течение которого при запуске двигателя насоса  не анализируются показания датчика давления, в секундах*)

    Time_Nech_on_work_in: WORD; (*время, в течение которого при работе двигателя насоса допускаются «провалы» показаний датчика давления, в секундах*)

    Time_Zad_in: WORD; (*время задержки между отключением одного насоса и включением другого, в секундах*)

    p1_on: BOOL; (*сигнал обратной связи (датчик давления, контакт пускателя итд.) насоса №1*)

    p2_on: BOOL; (*сигнал обратной связи (датчик давления, контакт пускателя итд.) насоса №2*)

    p3_on: BOOL; (*сигнал обратной связи (датчик давления, контакт пускателя итд.) насоса №3*)
    END_VAR

    VAR_OUTPUT

    p1_out: BOOL; (*сигнал включения насоса №1*)

    p2_out: BOOL; (*сигнал включения насоса №2*)

    p3_out: BOOL; (*сигнал включения насоса №3*)

    err_p1: BOOL; (*авария насоса №1*)

    err_p2: BOOL; (*авария насоса №2*)

    err_p3: BOOL; (*авария насоса №3*)

    END_VAR

    VAR

    i: WORD; (*переменная которая определяет запуск насосов*)

    Time_zad_on: TIME; (*время задержки перед началом работы алгоритма*)

    Time_Nech: TIME; (*время, в течение которого при запуске двигателя насоса  не анализируются показания датчика давления;*)

    Time_Nech_on_work: TIME; (*время, в течение которого при работе двигателя насоса допускаются «провалы» показаний датчика давления*)

    Time_Zad: TIME; (*время задержки между отключением одного насоса и включением другого*)

    Time_rotat: TIME;  (*время работы насосов*)

    Tim_off: BOOL;

    Trig1: R_TRIG;

    C_Tim: TON; (*таймер чредования насосов*)

    Time_Rotat_DW: DWORD;

    p1_out_: BOOL;

    p2_out_: BOOL;

    p3_out_: BOOL;

    TON_Zad_Pump1: TON;

    TON_Pump1_Nech: TON;

    Run_Pump: BOOL;

    Run_Trig: R_TRIG;

    Sbros_Trig: F_TRIG;

    TOF_Pump1_Nech: TOF;

    TON_Zad_Pump2: TON;

    TON_Pump2_Nech: TON;

    TOF_Pump2_Nech: TOF;

    TON_Zad_Pump3: TON;

    TON_Pump3_Nech: TON;

    TOF_Pump3_Nech: TOF;

    T_zad2: TIME; (*задержка включения второго насоса при холодном старте*)

    END_VAR

    (*преобразование переменных времени полученых с панели *)

    Time_Rotat_DW:=WORD_TO_DWORD(Time_Rotat_in);(*перевод в часы*)

    Time_rotat:=DWORD_TO_TIME((Time_Rotat_DW*3600000)/2);

    Time_zad_on:=WORD_TO_TIME(Time_zad_on_in*1000); (*перевод в секунды*)

    Time_Nech:=WORD_TO_TIME(Time_Nech_in*1000);

    Time_Nech_on_work:= WORD_TO_TIME(Time_Nech_on_work_in*1000);

    Time_Zad:=WORD_TO_TIME(Time_Zad_in*1000);(*инициализация и востановление начальных условий*)

    IF Run=TRUE THEN

    Run_Trig(CLK:=TRUE);

    Sbros_Trig(CLK:=TRUE) ;

    ELSE

    Run_Trig(CLK:=FALSE);

    Sbros_Trig(CLK:=FALSE);

    END_IF

    IF Run_Trig.Q=TRUE THEN

    Run_Pump:=TRUE;

    T_zad2:=T#5s;

    END_IF

    IF  Trig1.Q=TRUE THEN

    T_zad2:=T#0s ;

    END_IF

    IF Sbros_Trig.Q= TRUE THEN

    err_p1:=FALSE;

    err_p2:=FALSE;

    err_p3:=FALSE;

    END_IF

    (*запуск таймера ротации насосов*)

    IF Run_Pump=TRUE  THEN

    C_Tim(IN:=TRUE , PT:=T#1m );

    END_IF

    (*сброс таймера ротации насосов*)

    IF Run_Pump =FALSE THEN

    C_Tim(IN:=FALSE , PT:=T#0s );

    END_IF

    (*детектирование импульса перехода с насоса на насос*)

    Trig1(CLK:= C_Tim.Q );

    Tim_off:=Trig1.Q;

    (*востановление начальных установок, если идет холодный старт в автомате*)

    IF (Run_Pump=FALSE AND (p3_on= FALSE  AND p1_on=FALSE AND p2_on=FALSE)) THEN

    i:=0;

    END_IF

    IF Run=FALSE THEN

    p1_out_:= FALSE;

    p2_out_:=FALSE;

    p3_out_:=FALSE;

    Run_Pump:=FALSE;

    END_IF

    (*подхват насосов на «лету»*)

    IF (Run_Pump=FALSE AND (p1_on= TRUE AND p2_on=TRUE)) THEN

    i:=0;

    END_IF

    IF (Run_Pump=FALSE AND (p2_on= TRUE AND p3_on=TRUE)) THEN

    i:=2;

    END_IF

    IF (Run_Pump=FALSE AND (p3_on= TRUE AND p1_on=TRUE)) THEN

    i:=1;

    END_IF

    (*счетчик*)

    IF (Tim_off=TRUE AND Run_Pump=TRUE ) THEN

    i:=i+1;

    END_IF

    IF i>=3 THEN

    i:=0;

    END_IF

    (*включение насосов*)

    IF (Run_Pump=TRUE AND i=0) THEN

    p1_out_:= TRUE;

    p2_out_:=TRUE;

    p3_out_:=FALSE;

    END_IF

    IF (Run_Pump=TRUE AND i=1) THEN

    p1_out_:= TRUE;

    p2_out_:=FALSE;

    p3_out_:=TRUE;

    END_IF

    IF (Run_Pump=TRUE AND i=2) THEN

    p1_out_:= FALSE;

    p2_out_:=TRUE;

    p3_out_:=TRUE;

    END_IF

    (*перезапуск таймера*)

    IF (Run_Pump=TRUE AND Tim_off=TRUE) THEN

    C_Tim(IN:=FALSE , PT:=T#1m );

    END_IF

    (*управление насосами*)

    (*насос №1*)

    IF p1_out_=TRUE THEN

    TON_Zad_Pump1(IN:=TRUE , PT:=Time_Zad );

    ELSE

    TON_Zad_Pump1(IN:=FALSE , PT:=Time_Zad );

    END_IF

    IF (TON_Zad_Pump1.Q=TRUE AND err_p1=FALSE) THEN

    p1_out:=TRUE;

    END_IF (*формирование задержки включения и защиты от ошибочного включения*)

    IF (p1_out_=TRUE AND p1_out=TRUE) THEN

    TON_Pump1_Nech(IN:=TRUE , PT:=Time_Nech );

    ELSE

    TON_Pump1_Nech(IN:=FALSE , PT:=Time_Nech );

    END_IF

    (*задержка контроля обратной связи после пуска насоса*)

    IF  (p1_out=TRUE AND p1_on=FALSE) THEN

    TOF_Pump1_Nech(IN:=FALSE, PT:=Time_Nech_on_work);

    ELSE

    TOF_Pump1_Nech(IN:=TRUE, PT:=Time_Nech_on_work);

    END_IF

    (*задержка при пропадании сигнала обратной связи при работе насоса*)

    IF (Run=TRUE AND p1_out_=TRUE AND  TON_Pump1_Nech.Q=TRUE AND p1_on=FALSE AND TOF_Pump1_Nech.Q=FALSE) THEN

    err_p1:=TRUE ;

    Run_Pump:=FALSE ;

    p1_out:=FALSE;

    p2_out_:=TRUE;

    p3_out_:=TRUE;

    END_IF

    (*определение аварии насоса, производиться остановка ротации и принудительное включение оставшихся насосов*)

    IF p1_out_=FALSE THEN

    p1_out:=FALSE;

    END_IF

    (*остановка насоса по истесению времени или аварии*)

    (*насос №2*)

    IF p2_out_=TRUE THEN

    TON_Zad_Pump2(IN:=TRUE , PT:=Time_Zad+T_zad2 );

    ELSE

    TON_Zad_Pump2(IN:=FALSE , PT:=Time_Zad );

    END_IF

    (*здесь все тоже самое*)

    IF (TON_Zad_Pump2.Q=TRUE AND err_p2=FALSE) THEN

    p2_out:=TRUE;

    END_IF

    IF (p2_out_=TRUE AND p2_out=TRUE) THEN

    TON_Pump2_Nech(IN:=TRUE , PT:=Time_Nech );

    ELSE

    TON_Pump2_Nech(IN:=FALSE , PT:=Time_Nech );

    END_IF

    IF  (p2_out=TRUE AND p2_on=FALSE) THEN

    TOF_Pump2_Nech(IN:=FALSE, PT:=Time_Nech_on_work);

    ELSE

    TOF_Pump2_Nech(IN:=TRUE, PT:=Time_Nech_on_work);

    END_IF

    IF (Run=TRUE AND p2_out_=TRUE AND  TON_Pump2_Nech.Q=TRUE AND p2_on=FALSE AND TOF_Pump2_Nech.Q=FALSE) THEN

    err_p2:=TRUE ;

    Run_Pump:=FALSE ;

    p2_out:=FALSE;

    p1_out_:=TRUE;

    p3_out_:=TRUE;

    END_IF

    IF p2_out_=FALSE THEN

    p2_out:=FALSE;

    END_IF

    (*насос №3*)

    IF p3_out_=TRUE THEN

    TON_Zad_Pump3(IN:=TRUE , PT:=Time_Zad );

    ELSE

    TON_Zad_Pump3(IN:=FALSE , PT:=Time_Zad );

    END_IF

    IF (TON_Zad_Pump3.Q=TRUE AND err_p3=FALSE) THEN

    p3_out:=TRUE;

    END_IF

    IF (p3_out_=TRUE AND p3_out=TRUE) THEN

    TON_Pump3_Nech(IN:=TRUE , PT:=Time_Nech );

    ELSE

    TON_Pump3_Nech(IN:=FALSE , PT:=Time_Nech );

    END_IF

    IF  (p3_out=TRUE AND p3_on=FALSE) THEN

    TOF_Pump3_Nech(IN:=FALSE, PT:=Time_Nech_on_work);

    ELSE

    TOF_Pump3_Nech(IN:=TRUE, PT:=Time_Nech_on_work);

    END_IF

    IF (Run=TRUE AND p3_out_=TRUE AND  TON_Pump3_Nech.Q=TRUE AND p3_on=FALSE AND TOF_Pump3_Nech.Q=FALSE) THEN

    err_p3:=TRUE ;

    Run_Pump:=FALSE ;

    p3_out:=FALSE;

    p2_out_:=TRUE;

    p1_out_:=TRUE;

    END_IF

    IF p3_out_=FALSE THEN

    p3_out:=FALSE;

    END_IF

    END_PROGRAM

    Пожелания к работе программы и описание найденных ошибок можно направлять по адресу a_vit76@mail.ru Автор — Виктор Алексеев

    График с заданием точек элементами массива

    Пример: график уставки по пяти точкам. Каждая из координат задается массивом из 5 элементов, которые сначала сортируются по возрастанию, а затем по ним определяется уставка регулирования.

    При выходе за пределы линейной зависимости выходная переменная принимает значение  крайних точек зависимости.

    Листинг

    FUNCTION_BLOCK obr_gr (*сортировка элементов массивов по возрастанию*)

    VAR_INPUT

    x,y:ARRAY[1..5] OF REAL;

    END_VAR

    VAR_OUTPUT

    x1,y1:ARRAY[1..5] OF REAL;

    END_VAR

    VAR i: INT;

    xp,yp: REAL;

    END_VAR

    FOR i:=1 TO 4 DO

    IF x[i+1]<x[i] THEN

    xp:=x[i];

    x[i]:=x[i+1];

    x[i+1]:=xp;
    yp:=y[i];

    y[i]:=y[i+1];

    y[i+1]:=yp;
    END_IF;

    END_FOR;
    FOR i:=1 TO 5 DO

    x1[i]:=x[i];

    y1[i]:=y[i];

    END_FOR;

    FUNCTION_BLOCK opr_ust

    VAR_INPUT

    x,y:ARRAY[1..5] OF REAL; (*массивы входных значений*)

    vh_znach:REAL; (*сигнал с датчика*)

    END_VAR

    VAR_OUTPUT

    ust:REAL; (*требуемая уставка регулирования*)

    END_VAR

    VAR

    i: INT;

    k: REAL;

    END_VAR

    FOR i:=1 TO 4 DO;

    IF (x[i+1]>vh_znach) AND (x[i]<vh_znach) THEN

    k:=(y[i+1]-y[i])/(x[i+1]-x[i]);

    ust:=y[i]+k*(vh_znach-x[i]);

    END_IF;

    END_FOR;

    Простой график в CoDeSys

    Простейший пример: график уставки по двум точкам. При желании по аналогии можете сделать столько точек, сколько вам нужно.

    x1, y1 — координаты первой точки

    x2, y2 — координаты второй точки
    При выходе за пределы линейной зависимости выходная переменная принимает значение или y1, или y2.

    Листинг:

    FUNCTION_BLOCK graph

    VAR_INPUT

    par:REAL;            (*входной параметр*)

    x1, y1:REAL;         (*координаты первой точки*)

    x2, y2:REAL;         (*координаты второй точки*)

    END_VAR

    VAR_OUTPUT

    zad: REAL;           (*задание, определенное по графику*)

    END_VAR

    VAR

    koef1:REAL;          (*коэффициент уравнения прямой*)
    END_VAR

    koef1 := (y2 — y1) / (x2 — x1);
    IF (par <= x1) THEN

    zad := y1;

    END_IF;
    IF ((par > x1) AND (par < x2)) THEN

    zad := y1 + koef1 * (par — x1);

    END_IF;
    IF (par >= x2) THEN

    zad := y2;

    END_IF;

    Работа с таймерами на языке ST

    Пример работы с дискретными входами и выходами ПЛК, а также с таймерами ton и tof. Пример на языке ST.

    При замыкании первого входа замыкается первый выход.

    При замыкании первого и второго входа замыкается второй выход.

    Через 5 секунд после замыкания третьего входа замыкается третий выход.

    Через 10 секунд после размыкания четвертого входа размыкается четвертый выход.

    Листинг:

    PROGRAM PLC_PRG

    VAR

    tim1:TON;

    tim2:TOF;

    END_VAR

    (*plc100-24.K-L core 2-03 target 2-02-4*)

    out1:=in1;

    Out2:=in1 AND in2;

    (*задержка включения*)

    tim1(IN := in3, PT := T#5s);

    out3:=tim1.Q;

    (*задержка выключения*)

    tim2(IN := in4, PT := T#10s);

    out4:=tim2.Q;

    Сетевые переменные в CoDeSys.

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

    Необходимо помнить, что данная опция необходима, когда у нас на одном объекте как минимум 2 контроллера.

    Обмен переменными может вестись только по интерфейсу Ethernet. (На данном этапе).

    Пример создан на базе контроллера ПЛК150-220.И-L

    Target 2-02.3

    Переходим на вкладку Resources

    Выбираем папку «Target settings», вкладку «Network functionality»

    В строчке «Name of supported network interfaces» задаем в ручную – UDP

    Во вкладке Resources выбираем вкладку «Library Manager» и добавляем библиотеку (правой кнопкой мыши в поле библиотек) – Additional Library.

    Необходимо подключить следующие библиотеки:

    SysLibCallback.lib

    SysLibSockets.lib

    NetVarUdp_LIB_V23.lib

    Библиотеки вложены в архиве, либо на диске с ПЛК, либо на сайте ОВЕН.

    Рекомендуется перед подключением перенести библиотеки в директорию, созданную CoDeSys, по умолчанию: c:Program Files3S SoftwareCoDeSys V2.3Library

    Выбираем папку «Global variables»

    Выбираем команду Add Object

    Всплывает следующее окно.

    В строчке «Name of the global list» задаем имя, например PRIMER.

    !Важно:

    1. В обоих (нескольких) контроллерах имя данной папки должно быть идентичным.
    2. Регистр (большие или маленькие буквы) важен.

    Далее в этом окне нажимаем на кнопку «Add network» — окно видоизменяется следующим образом:

    Значение параметра «Network type» — необходимо выставить UDP. Вкладку Settings не редактируем.

    Значение параметра  «List identifier (COB-ID)» так же должно быть общим для всех контроллеров, участвующих в обмене. Значение выставляется произвольно. Для примера – 1.

    Далее ставим галочку у необходимого параметра.

    Для того, чтобы контроллер получал данные из сети необходимо поставить галочку у параметра Read. Для передачи данных с данного контроллера необходимо поставить галочку у параметра Write.

    Если выбраны Write – становятся доступными три последующие строчки, которые описывают по какому принципу необходимо передавать значение: «Циклически», «по изменению значения», «по команде».

    !Важно: Рекомендуется не ставить галочки чтение и запись для одной и той же группы «PRIMER» в одном контроллере. То есть только в одном контроллере переменные одной папки должны быть Write, в остальных контроллерах типа Read.

    Если необходимо, чтобы у каждого контроллера были переменные, которые и опрашиваются, и задаются – необходимо сделать несколько таких папок.

    После этого добавляем (объявляем) непосредственно во вновь созданной папке переменные, которые нам необходимы.

    И уже в программе работаем с ними, как со стандартными глобальными переменными.

    Сложные типы данных CoDeSys

    Массивы

    Элементарные типы данных могут образовывать одно-, двух-, и трехмерные массивы. Массивы  могут быть объявлены в разделе объявлений POU или в списке глобальных переменных. Путем вложения массивов можно получить многомерные массивы, но не более 9 мерных ( «ARRAY[0..2] OF ARRAY[0..3] OF …» ).

    Синтаксис:

    <Имя_массива>:ARRAY [<ll1>..<ul1>,<ll2>..<ul2>] OF <базовый тип>.

    где ll1, ll2, ll3 указывают нижний предел индексов; ul1, ul2 и ul3 указывают верхние пределы.

    Индексы должны быть целого типа. Нельзя использовать отрицательные индексы.

    Пример:

    Card_game: ARRAY [1..13, 1..4] OF INT;

    Пример инициализации простых массивов:

    arr1 : ARRAY [1..5] OF INT := 1,2,3,4,5;

    arr2 : ARRAY [1..2,3..4] OF INT := 1,3(7); (* сокращение для 1,7,7,7 *)

    arr3 : ARRAY [1..2,2..3,3..4] OF INT := 2(0),4(4),2,3;

    (* сокращение для 0,0,4,4,4,4,2,3 *)

    Пример инициализации массива структур:

    TYPE STRUCT1

    STRUCT

    p1:int;

    p2:int;

    p3:dword;

    END_STRUCT

    ARRAY[1..3] OF STRUCT1:= (p1:=1,p2:=10,p3:=4723),(p1:=2,p2:=0,p3:=299),
    (p1:=14,p2:=5,p3:=112);

    Пример инициализации части массива:

    arr1 : ARRAY [1..10] OF INT := 1,2;

    Не инициализированные явно элементы массива принимают значения по умолчанию. Так, в данном примере оставшиеся элементы примут значение 0.

    Доступ к элементам массива:

    Для доступа к элементам двухмерного массива используется следующий синтаксис:

    <Имя_массива>[Индекс1,Индекс2]

    Пример:

    Card_game [9,2]

    Функция CheckBounds

    Определив в проекте функцию с именем CheckBounds, вы сможете использовать её для контроля за соблюдением границ индексов массивов. Имя функции фиксировано, изменять его нельзя.

    Пример функции CheckBounds:

    FUNCTION CheckBounds : INT
    VAR_INPUT
    index, lower, upper: INT;
    END_VAR

    IF  index < lower THEN
    CheckBounds := lower;
    ELSIF  index > upper THEN
    CheckBounds := upper;
    ELSE  CheckBounds := index;
    END_IF

    В этом примере CheckBounds ограничивает индекс массива заданными границами. Если запрашивается элемент, отсутствующий в массиве, функция  CheckBounds возвращает ближайший элемент.

    Проверка работы функции CheckBounds:

    PROGRAM PLC_PRG
    VAR
    a: ARRAY[0..7] OF BOOL;
    b: INT:=10;
    END_VAR

    a[b]:=TRUE;

    Указатели

    Указатели позволяют работать с адресами переменных или функциональных блоков.

    Синтаксис:

    <Имя_указателя>: POINTER TO <Тип данных/Функциональный блок>;

    Указатели применимы для всех базовых типов данных или функциональных блоков, включая  определяемые пользователем.

    Адреса переменных и функциональных блоков можно получить во время исполнения программы при помощи оператора ADR. Для обращения через указатель необходимо добавить оператор «^»  (content) после его имени.

    Обратите внимание: Указатели инкрементируются побайтно! Для увеличения указателя, как это принято в C-компиляторах, используйте инструкцию p=p+SIZEOF(p^);.

    Пример:

    pt:POINTER TO INT;

    var_int1:INT := 5;

    var_int2:INT;

    pt := ADR(var_int1);

    var_int2:= pt^;  (* var_int2 теперь равна 5 *)

    Функция CheckPointer:

    Данная функция позволяет контролировать обращение к допустимой области памяти через указатели. Если определена функция CheckPointer, то она будет автоматически вызываться при любом обращении через указатель. Функция должна быть определена в проекте (непосредственно или в библиотеке). Ее имя (CheckPointer) изменять нельзя.  Функция имеет следующие параметры:

    Для систем с 32-х битными указателями:

    FUNCTION CheckPointer : DWORD

    VAR_INPUT

    dwAddress : DWORD;

    iSize : INT;

    bWrite: BOOL;

    END_VAR

    Для систем с 16-и битными указателями:

    FUNCTION CheckPointer : WORD

    VAR_INPUT

    dwAddress : WORD;

    iSize : INT;

    bWrite: BOOL;

    END_VAR

    Функция возвращает адрес, который будет использоваться как указатель. Если все хорошо то, это будет входной параметр — dwAddress.

    Перечисление

    Перечисление — это определяемый пользователем тип данных, задающий несколько строковых псевдонимов для числовых констант.

    Перечисление доступно в любой части проекта, даже при локальном его объявлении внутри POU. Поэтому наиболее разумно создавать все перечисления на вкладке Типы данных Организатора Объектов. Объявление должно начинаться с ключевого слова TYPE и заканчиваться строкой END_TYPE.

    Синтаксис:

    TYPE <Имя_перечисления>:(<Элемент_0> ,< Элемент _1>, …< Элемент _n>);END_TYPE

    Переменная типа  <Имя_перечисления> может принимать только перечисленные значения. При инициализации переменная получает первое из списка значение. Если числовые значения элементов перечисления не указаны явно, им присваиваются последовательно возрастающие числа, начиная с 0. Фактически элемент перечисления — это число типа INT и работать с ними можно точно так же. Можно напрямую присвоить число переменной типа перечисление.

    Пример:

    TYPE TRAFFIC_SIGNAL: (Red, Yellow, Green:=10); (*Каждому цвету

    соответствует свое значение, для red — это 0, для yellow — 1 и для green — 10 *)

    END_TYPE

    TRAFFIC_SIGNAL1 : TRAFFIC_SIGNAL;

    TRAFFIC_SIGNAL1:=0; (* Переменная получила значение red*)

    FOR i:= Red TO Green DO

    i := i + 1;

    END_FOR;

    Элемент, уже включенный в перечисление, нельзя повторно включать в другое перечисление.

    Пример:

    TRAFFIC_SIGNAL: (red, yellow, green);

    COLOR: (blue, white, red);

    Ошибка: попытка повторного использования элемента TRAFFIC_SIGNAL red  в COLOR.

    Структуры

    Структуры создаются на вкладке Типы данных Организатора Объектов. Объявление должно начинаться с ключевых слов TYPE и STRUCT и заканчиваться строками END_STRUCT и END_TYPE.

    Синтаксис:

    TYPE <Имя _структуры>:

    STRUCT

    <Объявление переменной 1>

    .

    .

    <Объявление переменной n>

    END_STRUCT

    END_TYPE

    <Имя _структуры> образует новый тип данных, который может быть использован в любой части проекта наряду с базовыми типами.

    Вложенные структуры допускаются. Единственное ограничение заключается в запрете размещения элементов структуры по прямым адресам (AT объявления недопустимы!).

    Пример объявления структуры по имени Polygonline:

    TYPE Polygonline:

    STRUCT

    Start:ARRAY [1..2] OF INT;

    Point1:ARRAY [1..2] OF INT;

    Point2:ARRAY [1..2] OF INT;

    Point3:ARRAY [1..2] OF INT;

    Point4:ARRAY [1..2] OF INT;

    End:ARRAY [1..2] OF INT;

    END_STRUCT

    END_TYPE

    Пример инициализации структуры:

    Poly_1:polygonline := ( Start:=3,3, Point1 =5,2, Point2:=7,3, Point3:=8,5, Point4:=5,7, End := 3,5);

    Для доступа к элементам структуры используется следующий синтаксис:

    <Имя_структуры>.<Имя_компонента>

    Например, структура «Week» содержит компонент «Monday», обращение к которому будет выглядеть так:

    Week.Monday

    Псевдонимы типов

    Псевдонимы типов нужны для создания альтернативных пользовательских наименований типов данных. Это удобно при работе с большим числом однотипных констант, переменных и функциональных блоков.

    Псевдонимы типов определены на вкладке Типы данных Организатора Объектов. Объявление должно начинаться с ключевого слова TYPE и заканчиваться строкой  END_TYPE.

    Синтаксис:

    TYPE <Имя псевдонима>: <Исходное имя>;
    END_TYPE

    Пример:

    TYPE message:STRING[50];

    END_TYPE;

    Ограничение диапазона значений

    Ограничение диапазона позволяет объявить переменную, значения которой ограничены в определенных пределах. Существует возможность создать в проекте новые типы данных с ограниченным диапазоном значений либо задать диапазон непосредственно при объявлении переменной.

    Создание нового типа выглядит так:

    TYPE < Имя > : < Целый тип > (<от>..<до>) END_TYPE;

    <Имя> любой допустимый МЭК идентификатор,
    <IЦелый тип> один из типов SINT, USINT, INT, UINT, DINT, UDINT, BYTE, WORD,DWORD (LINT, ULINT, LWORD).
    <от> константа, определяющая начало диапазона значений включительно
    <до> константа, определяющая конец диапазона значений включительно.

    Пример:

    TYPE

    SubInt : INT (-4095..4095);

    END_TYPE

    Ограничение диапазона при объявлении переменной:

    i : INT (-4095..4095);

    ui : UINT (0..10000);

    END_VAR

    При попытке присвоить переменной с ограниченным диапазоном константы, не попадающей в заданный диапазон (например i := 5000;) CoDeSys даст сообщение об ошибке.

    Для контроля значений «ограниченных» переменных в процессе исполнения, применяются функции CheckRangeSigned или CheckRangeUnsigned. Они позволяют обрабатывать ошибки произвольным образом. Например, ограничить присваиваемое значение или сформировать флаги ошибки. Первая функция работает для переменных со знаком, вторая для переменных без знака (unsigned). Изменять идентификаторы этих функций нельзя.

    Пример:

    Здесь применяется функция CheckRangeSigned, контролирующая переменные со знаком (как, например, объявленная выше i). Функция «обрезает» присваиваемые значения по границам диапазона.

    FUNCTION CheckRangeSigned : DINT

    VAR_INPUT

    value, lower, upper: DINT;

    END_VAR

    IF (value < lower) THEN

    CheckRangeSigned := lower;

    ELSIF(value > upper) THEN

    CheckRangeSigned := upper;

    ELSE

    CheckRangeSigned := value;

    END_IF

    Функция вызывается автоматически при соответствующих операциях присваивания. Она получает три параметра: присваиваемое значение (value) и обе границы диапазона (lower, upper). Фактически присваивается возвращаемое CheckRangeSigned значение.

    Например, при присваивании i:=10*y происходит неявный вызов:

    i := CheckRangeSigned(10*y, -4095, 4095);

    В результате, даже если y > 1000, i не получит значение более 4095.

    Аналогично объявляется и функция CheckRangeUnsigned:

    FUNCTION CheckRangeUnsigned : UDINT

    VAR_INPUT

    value, lower, upper: UDINT;

    END_VAR

    Важно: Если функции CheckRangeSigned или CheckRangeUnsigned не включены в проект, ограничение границ диапазонов во время исполнения работать не будет.

    Внимание: Функции CheckRange…, содержащащиеся в библиотеке Check.Lib представляют собой пример реализации. Прежде чем использовать эту библиотеку, убедитесь, что данные функции работает  так, как нужно в вашем случае, либо создайте собственные функции непосредственно в вашем проекте.

    Пример. Переменная ui не превысит 10000, и цикл FOR никогда не закончится:
    VAR
    ui : UINT (0..10000);
    END_VAR

    FOR ui:=0 TO 10000 DO

    END_FOR

    Элементарные типы данных CoDeSys

    Типы данных

    Тип данных определяет род информации и методы ее обработки и хранения, количество выделяемой памяти. Программист может непосредственно использовать элементарные (базовые) типы данных или создавать собственные (пользовательские) типы на их основе.

    Логический (BOOL)

    BOOL логический тип данных. Переменная может принимать 2 значения ИСТИНА (TRUE) или ЛОЖЬ (FALSE). Занимает 8 бит памяти, если не задан прямой битовый адрес.

    Целочисленные

    BYTE, WORD, DWORD, SINT, USINT, INT, UINT, DINT, и UDINT — все это целочисленные типы.

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

    Тип Нижний предел Верхний предел Размер памяти
    BYTE 0 255 8 Бит
    WORD 0 65535 16 Бит
    DWORD 0 4294967295 32 Бит
    SINT: -128 127 8 Бит
    USINT: 0 255 8 Бит
    INT: -32768 32767 16 Бит
    UINT: 0 65535 16 Бит
    DINT: -2147483648 2147483647 32 Бит
    UDINT: 0 4294967295 32 Бит

    Очевидно, присвоение данных большего типа переменной меньшего типа может приводить к потере информации.

    Рациональные

    REAL и LREAL данные в формате с плавающей запятой, используются для сохранения рациональных чисел. Для типа REAL необходимо 32 бита памяти и 64 для LREAL.

    Диапазон значений REAL от: 1.175494351e-38 до 3.402823466e+38

    Диапазон значений LREAL от: 2.2250738585072014e-308 до 1.7976931348623158e+308

    Строки

    Строковый тип STRING представляет строки символов. Максимальный размер строки определяет количество резервируемой памяти и указывается при объявлении переменной. Размер задается в круглых или квадратных скобках. Если размер не указан, принимается размер по умолчанию — 80 символов.

    Длина строки не ограничена в CoDeSys, но строковые функции способны обращаться со строками от  1 до 255 символов!

    Пример объявления строки размером до 35 символов:

    str:STRING(35):=’Просто строка»;

    Время и дата

    TIME представляет длительность интервалов времени в миллисекундах. Максимальное значение для типа TIME : 49d17h2m47s295ms (4194967295 ms).

    TIME, TIME_OF_DAY (сокр. TOD) содержит время суток, начиная с 0 часов (с точностью до миллисекунд). Диапазон значений TOD от: 00:00:00 до 23:59:59.999.

    DATE содержит календарную дату, начиная с 1 января 1970 года. Диапазон значений от: 1970-00-00 до 2106-02-06.

    DATE_AND_TIME (сокр. DT) содержит время в секундах, начиная с 0 часов 1 января 1970 года. Диапазон значений от: 1970-00-00-00:00:00 до 2106-02-06-06:28:15.

    Типы TIME, TOD, DATE и DATE_AND_TIME (сокр. DT) сохраняются физически как DWORD.

    Формат представления данных описан в разделе Константы: