Repository navigation
start stop.pl
Start-stop to klasyczny pierwszy program w automatyce: przycisk start włącza silnik, przycisk stop go wyłącza, silnik pracuje dalej po zwolnieniu startu, a przy obu wciśniętych przyciskach pierwszeństwo ma stop. Porównajmy jego implementacje w językach ST, LAD (ladder logic) i ANSI C z wykorzystaniem bibliotek OpenCPLC, uwzględniając w C dwa style mapowania: na zmienne i na wskaźniki. Jeśli kod w języku C wydaje Ci się najbardziej przystępny i zrozumiały, to prawdopodobnie ta droga jest dla Ciebie.
| Sygnał | ST i LAD | C |
|---|---|---|
| Przycisk start | %IX0.0 |
DI1 |
| Przycisk stop | %IX0.1 |
DI2 |
| Silnik | %QX0.0 |
RO1 |
PROGRAM main
VAR
start_button: BOOL := FALSE;
stop_button: BOOL := FALSE;
motor_running: BOOL := FALSE;
END_VAR
start_button := %IX0.0;
stop_button := %IX0.1;
IF stop_button THEN
motor_running := FALSE;
ELSIF start_button THEN
motor_running := TRUE;
END_IF;
%QX0.0 := motor_running;
END_PROGRAM
W każdym cyklu PLC cewka przyjmuje wynik swojego szczebla, więc bez dodatkowego styku cewka motor_running wyłączyłaby się po zwolnieniu startu.
Styk motor_running pod start_button to styk samopodtrzymujący: po włączeniu cewki zamyka on szczebel 3, dopóki stop_button go nie przerwie.
W ST i C ten styk jest zbędny, bo zmienna zachowuje wartość do następnego zapisu.
Cewka S (set) ustawia motor_running, a zmienna pozostaje ustawiona, dopóki nie skasuje jej cewka R (reset).
Przy obu wciśniętych przyciskach stop przerywa szczebel 3, a szczebel 4 kasuje motor_running, więc pierwszeństwo ma stop.
Program to wątek loop nowego projektu, utworzonego na przykład przez opencplc -n myapp -b Uno.
Każdy przebieg jego pętli while(1) to jeden cykl, jak w PLC: na początku wejścia są kopiowane do zmiennych, a na końcu zmienna jest kopiowana na wyjście, jak w dwóch pierwszych i ostatnim szczeblu drabinek.
let() kończy przebieg i oddaje procesor pozostałym wątkom.
bool start_button = false;
bool stop_button = false;
bool motor_running = false;
void loop(void)
{
while(1) {
start_button = DIN_State(&DI1);
stop_button = DIN_State(&DI2);
if(stop_button) {
motor_running = false;
}
else if(start_button) {
motor_running = true;
}
DOUT_Preset(&RO1, motor_running);
let();
}
}Wskaźniki nadają nazwy wejściom i wyjściu w jednym miejscu, a kod operuje bezpośrednio na nich: DOUT_Set i DOUT_Rst działają jak cewki S i R.
Stan obu przycisków jest odczytywany tak jak w drabinkach: przy odczycie zbocza przez DIN_Rise stop działałby tylko w chwili wciśnięcia, a przytrzymany nie blokowałby startu silnika.
DIN_t *start_button = &DI1;
DIN_t *stop_button = &DI2;
DOUT_t *motor_running = &RO1;
void loop(void)
{
while(1) {
if(DIN_State(stop_button)) {
DOUT_Rst(motor_running);
}
else if(DIN_State(start_button)) {
DOUT_Set(motor_running);
}
let();
}
}