CLSID=16#21xx
Описані в загальному описі функціональних вимог.
Версія Codesys - 3.5.
Версія Machine Expert - 1.2.
Немає особливих рекомендацій. Описані в загальних рекомендаціях.
Реалізований як функціональний блок. Посилання на файл експорту тут
Static екземпляру функціонального блоку, де зберігається:
TMBITS_PREVMEM_RTВ Codesys біту відслідковування першого скану немає, а використання біту в Machine Expert залежить від типу контролера і не працює в симуляції.
Static екземпляру функціонального блоку, де зберігається:
FirstScanNextScanВ Codesys бітових міандрів немає, а використання бітів в Machine Expert залежить від типу контролера і не працює в симуляції. Для їх реалізації використовується функціональний блок BLINK , який генерує імпульси вказаної тривалості, та викликається всередині функції PLCFN.
Для коректрої роботи бітових міандрів необхідно виставити тип задачі, де буде опитуватись дана функція Freewheeling
Static екземпляру функціонального блоку, які формують відповідні бітові міандри:
Clock_10HzClock_5HzClock_2HzClock_1HzДля зчитування системного часу необідно додатково підключити бібліотуку SysTimeRTC.
Для відображення локального часу додано зміщення LocalTime_ofset. по замовченню налаштовано на +2 години.
Для зчитування часу циклу необідно підключити бібліотуку CmpIecTask.
FUNCTION_BLOCK PLCFN
VAR_IN_OUT
PLC : PLC_CFG;
END_VAR
VAR_STAT
TMBITS_PREV : Int; // попереднє значення таймерних меандрів
MEM_RT : LREAL; // память для вимірювання часу циклу
FirstScan : BOOL ;
NextScan : BOOL;
Clock_10Hz: BOOL;
Clock_5Hz: BOOL;
Clock_2Hz: BOOL;
Clock_1Hz: BOOL;
Clock_0_5Hz: BOOL;
BLINK_10Hz: BLINK;
BLINK_5Hz: BLINK;
BLINK_2Hz: BLINK;
BLINK_1Hz: BLINK;
BLINK_0_5Hz: BLINK;
iecResult : RTS_IEC_RESULT;
pIecInfo : POINTER TO CmpIecTask.Task_Info2;
LocalTime_ofset:INT:=2;
nowDT:dword;
END_VAR
VAR_TEMP
TMBITS_CUR : Int;
i : INT;
NOW: SYSTIMEDATE;
END_VAR
Посилання щодо особливості реалізації деяких частин під блоком коду:
IF PLC.STA.CMDACK THEN
PLC.CMD := 0;
END_IF;
PLC.STA.CMDACK := (PLC.CMD <> 0 AND NOT PLC.STA.CMDACK);
(*--------------------------------- Визначення біту першого скану*)
IF NOT FirstScan AND NOT NextScan THEN
FirstScan := TRUE;
NextScan:=TRUE;
ELSE
FirstScan := FALSE;
END_IF
PLC.STA.SCN1 := FirstScan;
IF PLC.STA.SCN1 THEN (*при першому скані*)
PLC.ID := 1; (*Ідентифікатор завжди 1*)
PLC.CLSID := 16#2100; (*Клас завжди 162100*)
PLC.TQ := 0;
TMBITS_CUR := 0;
TMBITS_PREV := 0;
PLC.TQMS := 0;
END_IF;
PLC.STA_PERM.0 := PLC.STA.CON2ERR;
PLC.STA_PERM.1 := PLC.STA.PLC2STOP;
PLC.STA_PERM.2 := PLC.STA.BLK;
PLC.STA_PERM.3 := PLC.STA.ALDIS;
PLC.STA_PERM.4 := PLC.STA.DIOON;
PLC.STA_PERM.5 := PLC.STA.DIOERR;
PLC.STA_PERM.6 := PLC.STA.b6;
PLC.STA_PERM.7 := PLC.STA.FRC;
PLC.STA_PERM.8 := PLC.STA.SMLALL;
PLC.STA_PERM.9 := PLC.STA.DISP;
PLC.STA_PERM.10 := PLC.STA.FRC2;
PLC.STA_PERM.11 := PLC.STA.FRC1;
PLC.STA_PERM.12 := PLC.STA.SCN1;
PLC.STA_PERM.13 := PLC.STA.FRC0;
PLC.STA_PERM.14 := PLC.STA.SML;
PLC.STA_PERM.15 := PLC.STA.CMDACK;
PLC.ALM1_PERM.0 := PLC.ALM1.ALM;
PLC.ALM1_PERM.1 := PLC.ALM1.NWALM;
PLC.ALM1_PERM.2 := PLC.ALM1.ALMNACK;
PLC.ALM1_PERM.3 := PLC.ALM1.WRN;
PLC.ALM1_PERM.4 := PLC.ALM1.NWWRN;
PLC.ALM1_PERM.5 := PLC.ALM1.WRNNACK;
PLC.ALM1_PERM.6 := PLC.ALM1.BAD;
PLC.ALM1_PERM.7 := PLC.ALM1.NWBAD;
PLC.ALM1_PERM.8 := PLC.ALM1.BADNACK;
PLC.ALM1_PERM.9 := PLC.ALM1.EMCYSTP;
PLC.ALM1_PERM.10 := PLC.ALM1.STP2RUN;
PLC.ALM1_PERM.11 := PLC.ALM1.CON2ERR;
PLC.ALM1_PERM.12 := PLC.ALM1.PLC2STOP;
PLC.ALM1_PERM.13 := PLC.ALM1.DIOERR;
PLC.ALM1_PERM.14 := PLC.ALM1.PLCERR;
PLC.ALM1_PERM.15 := PLC.ALM1.CONHIERR;
(*--------------------------------- таймерні біти та лічильники*)
BLINK_10Hz(enable:=TRUE, timelow:=T#50MS, timehigh:=T#50MS, out=>Clock_10Hz);
BLINK_5Hz(enable:=TRUE, timelow:=T#100MS, timehigh:=T#100MS, out=>Clock_5Hz);
BLINK_2Hz(enable:=TRUE, timelow:=T#250MS, timehigh:=T#250MS, out=>Clock_2Hz);
BLINK_1Hz(enable:=TRUE, timelow:=T#500MS, timehigh:=T#500MS, out=>Clock_1Hz);
BLINK_0_5Hz(enable:=TRUE, timelow:=T#1000MS, timehigh:=T#1000MS, out=>Clock_0_5Hz);
(*плинні значення*)
TMBITS_CUR.0 := Clock_10Hz; // 100MS
TMBITS_CUR.1 := Clock_5Hz; // 200MS
TMBITS_CUR.2 := Clock_2Hz; // 500MS
TMBITS_CUR.3 := Clock_1Hz; // 1S
TMBITS_CUR.7 := PLC.NOW[0] > 16#29; //min
(*відловлювання імпульсів необхідних часових періодів*)
PLC.PLS.P100MS := TMBITS_CUR.0 AND NOT TMBITS_PREV.0; (*100 мс *)
PLC.PLS.P200MS := TMBITS_CUR.1 AND NOT TMBITS_PREV.1; (*200 мс*)
PLC.PLS.P500MS := TMBITS_CUR.2 AND NOT TMBITS_PREV.2; (*500 мс*)
PLC.PLS.P1S := TMBITS_CUR.3 AND NOT TMBITS_PREV.3; (*1 с*)
PLC.PLS.P60S := TMBITS_CUR.7 AND NOT TMBITS_PREV.7; (*1 хв*)
(*підрахунок кількості секунд і хвилин*)
IF PLC.PLS.P1S THEN
PLC.TQ := PLC.TQ + 1;
END_IF; (*загальний час з початку 1-го циклу контролера (в секундах)*)
IF PLC.TQ > 16#7FFF_FFFF THEN
PLC.TQ := 16#7FFF_FFFF;
END_IF;
IF PLC.PLS.P60S AND NOT PLC.STA.SCN1 THEN
PLC.TQM := PLC.TQM + 1;
END_IF; (*загальний час роботи ПЛК з моменту пуску (в хвилинах)*)
IF PLC.TQM > 16#7FFF_FFFF THEN
PLC.TQM := 16#7FFF_FFFF;
END_IF;
(*розрахунок інших часових періодів*)
PLC.PLS.P2S := (PLC.TQ MOD 2) = 0 AND PLC.PLS.P1S;(*2 с*)
PLC.PLS.P5S := (PLC.TQ MOD 5) = 0 AND PLC.PLS.P1S;(*5 с*)
PLC.PLS.P10S := (PLC.TQ MOD 10) = 0 AND PLC.PLS.P1S;(*10 с*)
(* меандри *)
PLC.PLS.M1S := Clock_1Hz; (*меандр з періодом 1 с (0.5 с + 0.5 с)*)
PLC.PLS.M2S := Clock_0_5Hz;(*меандр з періодом 2 с (1 с + 1 с) *)
(* астрономічний час *)
SysTimeRtcConvertUtcToDate(dwTimestampUtc:= GetRTC()+LocalTime_ofset*3600, pDate:=NOW );
PLC.NOW[0] := INT_TO_BCD(NOW.wSECOND); //NOW[0] seconds,-- (16ss,--)
PLC.NOW[1] := SHL(INT_TO_BCD(NOW.wHOUR), 8) OR INT_TO_BCD(NOW.wMINUTE);//16hhmm
PLC.NOW[2] := SHL(INT_TO_BCD(NOW.wMONTH), 8) OR INT_TO_BCD(NOW.wDAY); //16mmdd
PLC.NOW[3] := SHL(INT_TO_BCD(NOW.wYEAR / 100), 8) OR INT_TO_BCD(NOW.wYEAR MOD 100);; //16yyyy
PLC.NOWns := INT_TO_BCD(now.wMilliseconds)*1000000;
(* початок години *)
PLC.PLS.NEWHR := (PLC.NOW[1] AND 16#00FF) = 0 (*хвилини*)AND PLC.PLS.P60S (*один раз за хвилину*);
(* початок доби*)
PLC.PLS.NEWDAY := PLC.NOW[1] = 0 (*години_хвилини*)AND PLC.PLS.P60S (*один раз за хвилину*);
(*початок зміни*)
IF PLC.SHIFTPARA[0] < 1 OR PLC.SHIFTPARA[0] > 3 THEN
PLC.SHIFTPARA[0] := 2;
END_IF;(*коректність кількості змін*)
PLC.PLS.NEWSHIFT := FALSE; (*скидуємо біт початку зміни*)
FOR i := 1 TO PLC.SHIFTPARA[0] DO
(*хоча б одна з устоавок змін спрацювала*)
PLC.PLS.NEWSHIFT := PLC.PLS.NEWSHIFT OR (PLC.SHIFTPARA[i] = PLC.NOW[1] (*години хвилин*)AND PLC.PLS.P60S (*один раз за хвилину*));
END_FOR;
TMBITS_PREV := TMBITS_CUR;(*збереження попередніх значень*)
(*----------- визначеня зміни*)
IF PLC.SHIFTPARA[0] > 3 OR PLC.SHIFTPARA[0] < 2 THEN
PLC.SHIFTPARA[0] := 3;
END_IF;(*якщо кількість змін >3 або <1 - робимо 3*)
IF PLC.NOW[1] >= PLC.SHIFTPARA[1] AND (PLC.NOW[1] < PLC.SHIFTPARA[2] OR PLC.SHIFTPARA[2] = 160000) THEN (*1-ша зміна*)
PLC.SHIFTNMB := 1;
ELSE (*2-га або 3-тя*)
IF PLC.SHIFTPARA[0] = 2 THEN (*якщо в 2 зміни*)
PLC.SHIFTNMB := 2;
ELSE (*якщо 3 зміни*)
IF PLC.NOW[1] >= PLC.SHIFTPARA[2] AND (PLC.NOW[1] < PLC.SHIFTPARA[3] OR PLC.SHIFTPARA[3] = 160000) THEN
PLC.SHIFTNMB := 2;
ELSE
PLC.SHIFTNMB := 3;
END_IF;
END_IF;
END_IF;
(*----------- *)
(*цикли*)
pIecInfo := IecTaskGetInfo3(hIecTask := IecTaskGetCurrent(pResult := ADR(iecResult)), pResult := ADR(iecResult));
PLC.TSK_LTIME := DWORD_TO_UINT(pIecInfo^.dwCycleTime / 1000);
IF NOT FirstScan THEN
//обмеження
IF PLC.TSK_MAXTIME > 3000 THEN
PLC.TSK_MAXTIME := 0;
END_IF;
IF PLC.TSK_MAXTIME < PLC.TSK_LTIME THEN
PLC.TSK_MAXTIME := PLC.TSK_LTIME;
END_IF;
ELSE
PLC.TSK_MAXTIME := 0;
END_IF;
PLC.TQMS := PLC.TQMS + PLC.TSK_LTIME;//лічильник в мс
(*скидання статусів і тривог*)
PLC.STA.BLK := false;
PLC.STA.ALDIS := false;
PLC.STA.FRC := false;
PLC.STA.SMLALL := false;
PLC.STA.DISP := false;
PLC.STA.FRC2 := false;
PLC.STA.FRC1 := false;
PLC.STA.FRC0 := false;
PLC.STA.SML := false;
PLC.ALM1.ALM := 0;
PLC.ALM1.NWALM := 0;
PLC.ALM1.ALMNACK := 0;
PLC.ALM1.WRN := 0;
PLC.ALM1.NWWRN := 0;
PLC.ALM1.WRNNACK := 0;
PLC.ALM1.BAD := 0;
PLC.ALM1.NWBAD := 0;
PLC.ALM1.BADNACK := 0;
PLC.ALM1.EMCYSTP := 0;
PLC.ALM1.STP2RUN := 0;
PLC.ALM1.CON2ERR := 0;
PLC.ALM1.PLC2STOP := 0;
PLC.ALM1.DIOERR := 0;
PLC.ALM1.PLCERR := 0;
PLC.ALM1.CONHIERR := 0;
(*запамятовування лічильників*)
PLC.CNTALM_PERM := PLC.CNTALM;
PLC.CNTWRN_PERM := PLC.CNTWRN;
PLC.CNTBAD_PERM := PLC.CNTBAD;
PLC.CNTFRC_PERM := PLC.CNTFRC;
PLC.CNTMAN_PERM := PLC.CNTMAN;
(*скидання лічильників*)
PLC.CNTALM := 0;
PLC.CNTWRN := 0;
PLC.CNTBAD := 0;
PLC.CNTFRC := 0;
PLC.CNTMAN := 0;
Main:CmpApp, CmpIecTask,Standart=Standart,SysTimeCore,SysTimeRtc,SysTypes2 Interfaces,UtilPLC_STA, PLS і PLC_ALM1 представлені для зручності через структури з відплвідною назвоюPLC_CFG є частиною GVL SYSПерелік тестів та загальний опис їх проведення наведений в розділі тестування PLCFN.
усі змінні, що використовуються в тесті записані в TEST
усі тести реалізовані у фукції TS_PLCFN
| Номер | Назва | Коли перевірявся | Результати тестування |
|---|---|---|---|
| 1 | перший скан | 11.02.2021 | працює при перезаливці, при втраті живлення |
| 2 | астрономічний час | 11.02.2021 | працює |
| 3 | лічильники роботи ПЛК: загальний і зі старту | 11.02.2021 | працює при перезаливці, при втраті живлення |
| 4 | бітові імпульси | 11.02.2021 | працює |
| 5 | бітові меандри | 11.02.2021 | працює |
| 6 | імпульси початку години, доби | 11.02.2021 | працює |
| 7 | скидування бітів статусів та лічильників тривог, статусів та збереження їх в змінних _PERM |
||
| 8 | зміни: номер активної зміни, початок зміни | ||
| 9 | відображення мінімального та максимального часу циклу | 11.02.2021 | працює |
| 10 | Обнулення команд через один цикл | 11.02.2021 | працює |
Загальний опис тесту наведений в розділі тестування PLCFN
TEST.TST_CCLS := TEST.TST_CCLS + 1;
IF SYS.PLC.STA.SCN1 THEN
TEST.TST_SCN1CLC := TEST.TST_SCN1CLC + 1;
TEST.TST_NBCLC := TEST.TST_CCLS;
END_IF;
Загальний опис тесту наведений в розділі тестування PLCFN
Загальний опис тесту наведений в розділі тестування PLCFN
Загальний опис тесту наведений в розділі тестування PLCFN
IF TEST.TST_PLSON THEN
IF SYS.PLC.PLS.P100MS THEN
TEST.TST_P100MS := TEST.TST_P100MS + 1;
END_IF;
IF SYS.PLC.PLS.P200MS THEN
TEST.TST_P200MS := TEST.TST_P200MS + 1;
END_IF;
IF SYS.PLC.PLS.P500MS THEN
TEST.TST_P500MS := TEST.TST_P500MS + 1;
END_IF;
IF SYS.PLC.PLS.P1S THEN
TEST.TST_P1S := TEST.TST_P1S + 1;
END_IF;
IF SYS.PLC.PLS.P2S THEN
TEST.TST_P2S := TEST.TST_P2S + 1;
END_IF;
IF SYS.PLC.PLS.P5S THEN
TEST.TST_P5S := TEST.TST_P5S + 1;
END_IF;
IF SYS.PLC.PLS.P10S THEN
TEST.TST_P10S := TEST.TST_P10S + 1;
END_IF;
IF SYS.PLC.PLS.P60S THEN
TEST.TST_P60S := TEST.TST_P60S + 1;
END_IF;
IF SYS.PLC.TQ - TEST.TEST_TQPREV >= 121 THEN
TEST.TST_PLSON := false;
END_IF;
ELSE
TEST.TEST_TQPREV := SYS.PLC.TQ;
END_IF;
Загальний опис тесту наведений в розділі тестування PLCFN
Загальний опис тесту наведений в розділі тестування PLCFN
IF SYS.PLC.PLS.NEWHR THEN
TEST.TST_CHHRCNT := TEST.TST_CHHRCNT + 1;
END_IF;
IF SYS.PLC.PLS.NEWDAY THEN
TEST.TST_CHDAYCNT := TEST.TST_CHDAYCNT + 1;
END_IF;
Загальний опис тесту наведений в розділі тестування PLCFN
Загальний опис тесту наведений в розділі тестування PLCFN
Тест наразі не проводився.
Загальний опис тесту наведений в розділі тестування PLCFN
Перевірити проходження команд принаймні протягом одного циклу. Це потрібно для відловлення широкомовних команд.
//Обнулення команд через один цикл
IF SYS.PLC.CMD <> 0 THEN
TEST.TST_CMDCNT := TEST.TST_CMDCNT + 1;
END_IF;