Używamy plików cookies (tzw. ciasteczka) by spersonalizować treść i ogłoszenia oraz by analizować ruch na stronie.  W sposób automatyczny dzielimy się informacjami o Twoim użyciu tego portalu z dostawcami ogłoszeń, którzy mogą połączyć te informacje z informacjami, które im udzieliłaś/łeś lub, które sami zebrali. Korzystanie z witryny bez zmiany ustawień dotyczących cookies oznacza, że będą one zamieszczane w Państwa urządzeniu końcowym.  Możecie Państwo dokonać w każdym czasie zmiany ustawień dotyczących cookies zmieniając opcje przeglądarki.

3. Bloki funkcyjne

W tej części opowiem jak wykorzystywać proste bloki funkcyjne, które usprawniają programowanie upraszczają kod i umożliwiają realizację złożonych zadań.

Niejszy artykuł bazuje na pojęciach i plikach omawianych w poprzednich częściach - zachęcam więc, by czytać całość od samego początku

Zmodyfikujmy nieco nasz program z poprzedniego artykułu. Niech wyjście OUT1 zależy od wejścia IN1 w następujący sposób:

OUT1 := IN1;

1

Co się wtedy stanie?

Po sprawdzeniu projektu (Project -> Build), wgraniu go (Online -> Login) i uruchomieniu (Online -> Run) przetestujmy działanie programu. Podając napięcie 24V+ na wejście IN1, która jest pierwszą dziurką pierwszego modułu wejść, powinniśmy włączać wyjście OUT1, które jest pierwszą dziurką pierwszego modułu wyjść, czyli trzeciego modułu w naszej konfiguracji. Gdyby wyjście OUT1 podłączone było do przekaźnika, a przekaźnik zwierał obwód, w który wpięta jest żarówka podłączona do 230V, zobaczylibyśmy, jak światło zapala się i gaśnie. Warto to przetestować :)

No dobrze, ale w automatyce stosujemy łączniki ścienne zwierne, które zwierają wejścia na czas przyciśnięcia, a nie przełączają się na stałe. Jak sterować w takiej sytuacji oświetleniem?

Osoby przyzwyczajone do innych języków programowania mogą chcieć zaproponować następujący kod:

IF IN1 = TRUE THEN (* lub w skrócie IF IN1 THEN *)
  OUT1 := NOT OUT1;
END_IF;

Co na ludzki język chciało by się przetłumaczyć następująco: jeśli IN1 jest prawdziwe (tzn, pojawiło się napięcie w pierwszej dziurce), wtedy odwróć stan OUT1.

To niestety nie zadziała. Program w PLC wykonywany jest kilkadziesiąt razy na sekundę i nie wie, czy napięcie się właśnie ‘pojawiło’, czy już jakiś czas jest. Tak długo jak długo przyciśnięty jest przycisk, każdy cykl programu zmieniać będzie stan OUT1!

To ważne. Zatrzymajmy się i przeczytajmy powyższe kilka razy. Program:

IF IN1 THEN
  OUT1 := NOT OUT1;
END_IF;

wykonywany jest raz za razem. W trakcie pół sekundowego przyciśnięcia przycisku (podania prądu do IN1), stan OUT1 zostanie odwrócony kilkadziesiąt razy. Na czym stanie? Nie wiadomo. Sprawa przypadku.

W trakcie całego programowania PLC należy o tym pamiętać i myśleć nie o stanach prawda/fałsz ale o wykrywaniu zbocza wznoszącego i opadającego danej zmiennej, czyli momenu, w którym zmienna lub wejście zmienia stan. Program nasz powinien brzmieć: jeśli IN1 zmieni stan z FALSE na TRUE, zmień raz stan OUT1.

CoDeSys oferuje bloki funkcyjne, które zajmują się takim ‘wykrywaniem zbocza”. Przetestujmy jeden z nich.  W definicjach:

PROGRAM PLC_PRG

VAR
  IN1_TRIG: R_TRIG;
END_VAR

W programie:

IN1_TRIG(CLK := IN1);
IF IN1_TRIG.Q THEN
  OUT1 := NOT OUT1;
END_IF;

2

R_TRIG jest blokiem funkcyjnym wykrywającym wznoszące zbocze impulsu (stąd „Rising Trigger” => R_TRIG).

3

Blok funkcyjny to taka czarna skrzynka, która przyjmuje coś na wejściu i oddaje coś na wyjściu. Linia IN1_TRIG (CLK := IN1) informuje, że do wejścia CLK bloku IN1_TRIG należy podłączyć stan fizycznego wejście IN1.

IN1_TRIG będzie się odtąd ‘kręcić’ w programie, ilekroć ten będzie wykonany (czyli kilkadziesiąt razy na sekundę). Gdy tylko IN1 zmieni się z FALSE na TRUE (podamy napięcie na IN1), blok IN1_TRIG na wyjściu Q poda wartość TRUE, ale zrobi to tylko 1 raz! W konsekwencji warunek IF IN1_TRIG.Q THEN…. zostanie spełniony tylko raz i tylko raz odwrócona zostanie wartość OUT1.

Przetestujmy!

Jeszcze jedna rzecz – utraciliśmy możliwość sterowania przez wizualizację. Trzeba to naprawić! W definicjach dodajemy deklarację zmiennej VIS_light i bloku funkcyjnego wykrywającego ‘wznoszące zbocze’ tej zmiennej.

VAR
  IN1_TRIG: R_TRIG;
  VIS_light : BOOL;
  VIS_light_TRIG : R_TIRG;
END_VAR

A w programie mamy teraz:

IN1_TRIG(CLK := IN1);
VIS_light_TRIG(CLK := VIS_light);
IF IN1_TRIG.Q OR VIS_light_TRIG.Q THEN
  OUT1 := NOT OUT1;
END_IF;

Zmieńmy też konfigurację przycisku na wizualizacji by jego przyciśnięcie zmieniało stan zmiennej VIS_light na czas przyciśnięcia: Klikamy 2x na przycisk “Click!”, wybieramy Input, czyścimy checkbox przy „Toggle variable”, zaznaczamy pole przy „Tap variable” i wpisujemy „PLC_PRG.VIS_light”:

4

Powinno działać :)

Oto plik z ostateczną wersją programu.