logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Programowanie obiektowe w CAREL STone dla c.pCO PLC - Kompletny przewodnik

lunakk 08 Kwi 2026 20:30 384 0

TL;DR

  • Kompletny przewodnik po programowaniu obiektowym w CAREL STone i Structured Text dla c.pCO PLC, oparty na bibliotece sterowania przemysłową pompownią.
  • Opisuje architekturę biblioteki: osobne pliki .st, namespace z wersją, {IF DEF} dla wariantów sprzętowych, regiony, interfejsy oraz klasy abstrakcyjne i finalne.
  • Pokazuje konkretne mechanizmy, m.in. Libs.PumpStation_Lib_v2_0_0, FEATURE_MODBUS_DRIVE, FEATURE_ADVANCED_MOTOR oraz typy USINT, UINT i DINT.
  • Promuje Template Method, fail-fast z RETURN, REF_TO dla dużych struktur, VAR_IN_OUT CONSTANT, jawne TO_xxx i dokumentację (**...*) dla publicznych elementów.
Wygenerowane przez model językowy.
📢 Słuchaj (AI):
  • Programowanie obiektowe w CAREL STone dla c.pCO PLC - Kompletny przewodnik



    Programowanie obiektowe w CAREL STone Kompletny przewodnik

    Cytat:
    Niniejszy artykuł to zbiór zasad i konwencji programowania obiektowego w języku Structured Text (ST) w środowisku CAREL STone dla sterowników c.pCO nowej generacji. Wszystkie opisane wzorce i praktyki bazują na moim wieloletnim doświadczeniu z produkcyjnymi bibliotekami przemysłowymi. Jako przykład przewodni wybrałem bibliotekę sterowania pompownią przemysłową — system zarządzający różnymi typami pomp (VFD, DOL, soft-start) z regulacją ciśnienia, przepływu i poziomu cieczy. Zasady mają jednak zastosowanie uniwersalne.





    1. Struktura projektu CAREL STone

    1.1. Plik projektu/biblioteki ".stprj"

    Każdy projekt/biblioteka CAREL STone posiada plik XML .stprj, który definiuje metadane i strukturę kompilacji.

    Kod: text
    Zaloguj się, aby zobaczyć kod


    1.2. Organizacja katalogów

    Dobrą praktyką jest podział kodu na katalogi odzwierciedlające elementy OOP:

    KatalogZawartośćPrzykłady plików
    Classes/Klasy (abstrakcyjne i finalne)BasePump.st, VFD_Pump.st, DOL_Pump.st
    Interfaces/Interfejsy (kontrakty)IPump.st, IVariableSpeedPump.st
    Functions/Funkcje globalneValidateModbusResults.st, CheckControllerID.st
    Libs/Zależności zewnętrzne (.stlib)PumpCore_v.2.0.3.0.stlib


    Konwencja: każda klasa/interfejs = osobny plik .st o nazwie identycznej z nazwą klasy/interfejsu.

    1.3. Wersjonowanie bibliotek — "LibVer.g.st"

    CAREL STone stosuje mechanizm preprocesora do zarządzania wersjami i namespace'ami:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kluczowe zasady:

    • Wersja jest częścią namespace'a (Libs.PumpStation_Lib_v2_0_0) — pozwala na współistnienie wielu wersji biblioteki
    • Include guard (__LIBRARYNAMESPACEANDVERSION__) zapobiega wielokrotnemu definiowaniu
    • Każdy plik .st zaczyna się od {INCLUDE '../LibVer.g.st'}
    • Makro LibraryNamespaceAndVersion jest używane jako nazwa NAMESPACE w każdym pliku




    2. Namespace i dyrektywy preprocesora

    2.1. Namespace

    Każdy plik w bibliotece jest opakowany w NAMESPACE z makrem wersyjnym:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Konwencje:

    USING importuje inne namespace'y — zawsze na początku, po otwarciu NAMESPACE
    • Zależne biblioteki importowane przez pełną ścieżkę z wersją: Libs.PumpCore_v2_0_3_0
    • Typy systemowe przez System.IO, System.Math

    2.2. Kompilacja warunkowa "{IF DEF ...}"

    CAREL STone wspiera dyrektywy preprocesora do kompilacji warunkowej. W praktyce intensywnie je wykorzystuję do obsługi wariantów sprzętowych:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kod: text
    Zaloguj się, aby zobaczyć kod


    Praktyczne zastosowania:

    DefineEfekt
    FEATURE_MODBUS_DRIVESWłącza sterowanie VFD przez Modbus — wymaga rozszerzonego API komunikacyjnego
    FEATURE_ADVANCED_MOTORSWłącza pompy soft-start i DOL z rozszerzonym monitoringiem


    Cytat:
    Dzięki temu jeden codebase obsługuje wiele wariantów sprzętowych. Klasy mogą mieć dwie niezależne implementacje w tym samym pliku, przełączane w compile-time.


    2.3. Regiony "{REGION ... ENDREGION}"

    Regiony porządkują sekcje kodu wizualnie w IDE:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Zalecana konwencja regionów:

    RegionZawartość
    SettersMetody ustawiające parametry
    GettersMetody zwracające wartości
    Public / ProtectedPodregiony wewnątrz Setters/Getters grupujące po widoczności
    Default paramsStałe domyślne
    NAMED VALUESTypy wyliczeniowe z przypisanymi wartościami numerycznymi
    ENUMERATORSStandardowe enumeratory
    CONFIGURATIONStruktury konfiguracyjne
    INFORMATIONStruktury informacyjne/statusowe
    Conditional API callsBloki wywołań warunkowanych na feature-flags sprzętu





    3. Typy danych

    3.1. Named Values (enumeratory z wartościami)

    CAREL STone pozwala na definiowanie enumeratorów z jawnie przypisanymi wartościami numerycznymi. Składnia:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Przykład — wybór pompy:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Przykład — stany maszyny sterującej:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kluczowe cechy:

    • Typ bazowy (USINT, UINT, DINT) determinuje rozmiar w pamięci — optymalizacja zasobów PLC
    • Wartości nie muszą być ciągłe (np. PUMP_STATE ma luki: 12→18, 21→100)
    • Modyfikator INTERNAL ogranicza widoczność: TYPE INTERNAL — typ niedostępny spoza biblioteki
    • Dostęp przez kwalifikator: PUMP_STATE#Regulation, PUMP_SEL#Pump1

    3.2. Enumeratory standardowe

    Bez jawnych wartości — kompilator przypisuje je automatycznie od 0:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Cytat:
    Zwróć uwagę na przecinek przed DOL_Pump wewnątrz {IF DEF} — jest to konieczne, aby zachować poprawną składnię niezależnie od stanu kompilacji warunkowej.


    3.3. Struktury ("STRUCT")

    Struktury grupują powiązane dane. W praktyce stosuję intensywne zagnieżdżanie struktur:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Konwencje struktur:

    • Każde pole ma wartość domyślną (:= ...)
    • Zakresy definiowane wprost: UINT(0..100), UINT(0..18000)
    • Zagnieżdżanie jako forma kompozycji — hierarchia danych

    3.4. Tablice typowane

    Kod: text
    Zaloguj się, aby zobaczyć kod


    3.5. Atrybuty i metadane pól

    CAREL STone wspiera atrybuty przypisywane do pól i metod:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    AtrybutZnaczenie
    {ATTRIBUTE UOM ...}Jednostka miary (CELSIUS, BAR, PERCENT, AMPERE, OHM, RPM, SECOND, MINUTE, HERTZ, CUBICMETERPERHOUR)
    {METADATA MIN_VAL ...}Minimalna wartość parametru
    {METADATA MAX_VAL ...}Maksymalna wartość parametru


    Te atrybuty mogą być odczytywane przez narzędzia IDE (IntelliSense) i systemy supervisory.

    3.6. Stałe globalne "VAR_GLOBAL CONSTANT"

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Konwencje:

    INTERNAL — stałe widoczne tylko wewnątrz biblioteki
    • Nazwy: UPPER_SNAKE_CASE z prefiksem tematycznym (np. DEFAULT_)
    • Wartości domyślne są źródłem prawdy dla parametrów fabrycznych




    4. Interfejsy ("INTERFACE")

    4.1. Definicja interfejsu

    Interfejs definiuje kontrakt — zestaw metod, które klasa musi zaimplementować:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    4.2. Dziedziczenie interfejsów ("EXTENDS")

    Interfejsy mogą rozszerzać inne interfejsy:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Konwencje interfejsów:

    RegułaPrzykład
    Prefix I w nazwieIPump, IVariableSpeedPump
    Brak ciał metodTylko sygnatury
    Grupowanie w regiony{REGION Setters}, {REGION Getters}
    Atrybuty na metodach{ATTRIBUTE UOM BAR} przed METHOD
    VAR_IN_OUT CONSTANT dla strukturPrzekazanie przez referencję bez kopii, read-only


    4.3. Wzorzec "VAR_IN_OUT CONSTANT"

    Kluczowy wzorzec optymalizacji pamięci PLC:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    VAR_IN_OUT — przekazanie przez referencję (brak kopiowania dużych struktur)
    CONSTANT — zabezpieczenie przed modyfikacją wewnątrz metody
    • Idealny do przekazywania dużych struktur konfiguracyjnych do setterów




    5. Klasy ("CLASS")

    5.1. Hierarchia klas

    Kod: text
    Zaloguj się, aby zobaczyć kod


    5.2. Klasa abstrakcyjna — "BasePump"

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kluczowe wzorce:

    ABSTRACT — nie można tworzyć instancji bezpośrednio
    INTERNAL — klasa widoczna tylko wewnątrz biblioteki
    IMPLEMENTS IPump — implementacja kontraktu interfejsu
    METHOD ABSTRACT PROTECTED OnRun — metoda abstrakcyjna, punkt rozszerzenia (Template Method Pattern)
    THIS. — jawne odwołanie do członków instancji

    5.3. Modyfikatory widoczności zmiennych

    Kod: text
    Zaloguj się, aby zobaczyć kod


    ModyfikatorZakres widoczności
    PRIVATETylko w danej klasie
    PROTECTEDW klasie i jej podklasach
    PUBLICWszędzie (domyślny dla metod interfejsu)
    INTERNALWewnątrz biblioteki


    Konwencja: zmienne instancji FB i referencje → PRIVATE; struktury współdzielone z podklasami → PROTECTED.

    5.4. Klasa pośrednia — "BaseVariableSpeedPump"

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Wzorce:

    EXTENDS BasePump IMPLEMENTS IVariableSpeedPump — dziedziczenie po jednej klasie + implementacja interfejsu
    OVERRIDE — nadpisanie metody klasy bazowej
    SUPER.Reset() — wywołanie implementacji rodzica

    5.5. Klasa finalna — "VFD_Pump"

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kluczowe cechy klas finalnych:

    FINAL — klasa nie może być dalej dziedziczona
    PUBLIC — widoczna dla użytkowników biblioteki
    • Implementuje OnRun() — konkretna logika sterowania
    OVERRIDE PROTECTED ApplyConfiguration — rozszerza bazową konfigurację, zawsze wywołuje SUPER.ApplyConfiguration()




    6. Wzorce projektowe (Design Patterns)

    6.1. Template Method Pattern

    Najważniejszy wzorzec, który stosuję w bibliotekach sterowania. Klasa bazowa BasePump.Run() definiuje szkielet algorytmu, a klasy pochodne dostarczają implementację OnRun():

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Każda klasa finalna implementuje OnRun() inaczej:

    KlasaLogika [b]OnRun()[/b]
    VFD_PumpWriteMotorData → Driver(analog out) → ReadMotorData → CanGo
    SoftStartPumpWriteMotorData → Driver(soft-start) → ReadMotorData → CanGo
    VFD_PumpModbusWriteMotorData → Modbus calls (WriteSpeed, ReadFeedback...) → ReadMotorData → Error check
    ExternalControllerSynchronizacja ze standalone-inverterem przez REF_TO T_MOTOR_DATA
    DOL_PumpWriteMotorData → ReadMotorData → CanGo (direct on/off, no speed regulation)


    6.2. Wzorzec detekcji zmiany konfiguracji

    Każda klasa z konfiguracją implementuje wzorzec wykrywania zmian:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Logika: flaga IsConfigChanged jest akumulowana (OR) — raz ustawiona, nie zostanie zresetowana aż do Reset(). Sprawdzana w Run() → jeśli TRUE, wykonuje Reset() i RETURN.

    6.3. Wzorzec domyślnej konfiguracji przez zmienną lokalną

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Zmienna lokalna CfgDefault jest inicjalizowana wartościami domyślnymi ze struktury CFG_VFD_MOTOR. Nie trzeba ich ustawiać ręcznie — wystarczy przypisać świeżą instancję.

    6.4. Wzorzec referencji dla dużych struktur

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Zasada: duże struktury konfiguracyjne są przechowywane jako REF_TO — dane pozostają w jednym miejscu, klasa trzyma tylko wskaźnik. Walidacja NULL przed użyciem:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    6.5. Wzorzec Getter/Setter

    Konsekwentny wzorzec Get/Set:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kluczowe: wartość zwracana przez przypisanie do nazwy metody: GetXxx := wartość;

    6.6. Przeciążanie metod (Method Overloading)

    CAREL STone wspiera przeciążanie — ta sama nazwa metody, różne sygnatury:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Oraz przeciążanie z różnymi typami parametrów (na przykładzie obsługi błędów):

    Kod: text
    Zaloguj się, aby zobaczyć kod





    7. Modyfikatory klas i metod

    7.1. Modyfikatory klas

    ModyfikatorZnaczeniePrzykład
    ABSTRACTNie można instancjonować; wymaga podklasBasePump, BaseVariableSpeedPump
    FINALNie można dziedziczyćVFD_Pump, SoftStartPump, DOL_Pump
    INTERNALWidoczna tylko wewnątrz bibliotekiBasePump, BaseVariableSpeedPump
    PUBLICWidoczna dla użytkowników bibliotekiVFD_Pump, ExternalController


    Stosowane kombinacje:

    DeklaracjaRola
    CLASS ABSTRACT INTERNALKlasa bazowa, ukryta przed użytkownikiem
    CLASS FINAL PUBLICKlasa końcowa, API publiczne


    7.2. Modyfikatory metod

    ModyfikatorZnaczenie
    ABSTRACTBrak ciała — musi być zaimplementowana w podklasie
    OVERRIDENadpisuje metodę klasy bazowej
    PUBLICDostępna z zewnątrz
    PROTECTEDDostępna w klasie i podklasach
    PRIVATEDostępna tylko w danej klasie


    Przykład łańcucha override:

    Kod: text
    Zaloguj się, aby zobaczyć kod





    8. Funkcje ("FUNCTION")

    Funkcje są samodzielne, bezstanowe i operują na danych wejściowych:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Cechy:

    ARRAY [*] — tablica o dynamicznym rozmiarze (variable-length array)
    LOWER_BOUND() / UPPER_BOUND() — intrinsics do granic tablicy
    • Wartość zwracana przez przypisanie do nazwy funkcji: ValidateModbusResults.ID := ...
    • Dostęp do pól zwracanej struktury przez . na nazwie funkcji
    RETURN jako early exit

    Kolejny przykład — sprawdzanie kompatybilności sprzętowej:

    Kod: text
    Zaloguj się, aby zobaczyć kod






    9. Komentarze i dokumentacja

    9.1. Typy komentarzy

    SkładniaCelWidoczność
    (*komentarz*)Komentarz blokowy standardowyKod
    (**komentarz*)Komentarz dokumentacyjny (IntelliSense)IDE + podpowiedzi
    //komentarzKomentarz liniowyKod


    9.2. Komentarze dokumentacyjne "(**...*)"

    Każdy publiczny element powinien mieć komentarz (**...*) bezpośrednio przed deklaracją:

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kod: text
    Zaloguj się, aby zobaczyć kod


    Kod: text
    Zaloguj się, aby zobaczyć kod


    Konwencje dokumentacji:

    • Klasy: opis roli i odpowiedzialności (multi-line, z * na początku kontynuacji)
    • Metody: jeden wiersz opisujący akcję (zaczyna się od czasownika: Returns, Sets, Executes, Resets)
    • Zmienne: krótki opis przeznaczenia
    • Parametry VAR_INPUT / VAR_IN_OUT: opis każdego parametru

    9.3. Komentarze operacyjne "(*...*)"

    Wewnątrz ciał metod — wyjaśniają logikę:

    Kod: text
    Zaloguj się, aby zobaczyć kod





    10. Konwencje nazewnictwa

    10.1. Podsumowanie

    ElementKonwencjaPrzykłady
    InterfejsI + PascalCaseIPump, IVariableSpeedPump
    Klasa bazowaBase + PascalCaseBasePump, BaseVariableSpeedPump
    Klasa finalnaPascalCase (bez prefixu)VFD_Pump, SoftStartPump, ExternalController
    Metoda publicznaGet/Set + PascalCaseGetMotorSpeed, SetRegParams
    Metoda chronionaPascalCaseOnRun, ApplyConfiguration, UpdateAlarmStatus
    Metoda prywatnaPascalCaseDriver, CoreProcessingPhase
    Zmienna lokalnaPascalCaseCfgDefault, InternalMotorType, ErrCode
    Zmienna instancjiPascalCasePumpSel, IsConfigChanged, ReadyToCmd
    Stała globalnaUPPER_SNAKE_CASEDEFAULT_MAX_SPEED, TARGET_CONTROLLER_ID
    Typ (struct)UPPER_SNAKE_CASEREG_PARAMS, CFG_VFD_MOTOR, PRESSURE_PROTECTION
    EnumeratorUPPER_SNAKE_CASEMOTOR_TYPE, REG_TYPE, MOTOR_CFG_VARIANT
    Wartość enumeratoraPascalCaseVFD, ExternalController, Factory
    Named valuePascalCasePump1, EmergencyStop, Regulation
    Prefiks BoolIs/En/AlIsConfigChanged, En_Backup, Al_Present
    ReferencjaRef + nazwaRefRegParams, RefAdvRegParams


    10.2. Separatory w nazwach

    W środowisku CAREL STone stosuję podkreślnik _ jako separator w złożonych nazwach technicznych:

    PumpSel — Pump Selection
    PID_Params — PID Parameters
    HighPress_Ti — High Pressure Integral Time
    AlarmStatus — Alarm Status
    IsConfigChanged — z prefixem Is




    11. Wzorce konwersji typów

    CAREL STone wymaga jawnych konwersji typów za pomocą funkcji TO_xxx:

    Kod: text
    Zaloguj się, aby zobaczyć kod





    12. Obsługa błędów

    12.1. Wzorzec sprawdzania wyników komunikacji

    Kod: text
    Zaloguj się, aby zobaczyć kod


    12.2. Wzorzec kaskadowej walidacji

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Wzorzec: seria kroków z RETURN po każdym potencjalnym błędzie — fail-fast bez zagnieżdżonych IF-ów.

    12.3. Warunkowe wywołania API

    Kod: text
    Zaloguj się, aby zobaczyć kod


    Zasada: sprawdzaj feature-flags drivera/falownika przed wywołaniem opcjonalnych poleceń — dzięki temu kod działa z różnymi modelami i wersjami firmware.




    13. Podsumowanie najlepszych praktyk

    Architektura

    1. Jeden plik = jeden element (klasa, interfejs, funkcja)
    2. Interfejsy jako kontrakty — definiuj INTERFACE przed implementacją
    3. Hierarchia: abstrakcyjna baza → klasy finalne — użytkownik widzi tylko FINAL PUBLIC
    4. Ukrywaj implementację — klasy bazowe jako INTERNAL
    5. Template Method PatternMETHOD ABSTRACT PROTECTED OnRun jako metoda abstrakcyjna i punkt rozszerzenia

    Pamięć i wydajność

    6. VAR_IN_OUT CONSTANT dla dużych struktur przekazywanych do metod
    7. REF_TO do przechowywania referencji — unikaj kopiowania
    8. Najmniejszy typ bazowyUSINT zamiast UINT gdy wystarczy zakres 0-255
    9. Zakresy typówUINT(0..100) zamiast gołego UINT

    Konwencje

    10. Prefiksy: I (interfejs), Base (klasa abstrakcyjna), Get/Set (metody), Is/En (bool)
    11. Komentarze (**...*) (IntelliSense) na każdym publicznym elemencie
    12. {REGION} do organizacji kodu w IDE
    13. Kompilacja warunkowa {IF DEF} do obsługi wariantów sprzętowych
    14. Jawne konwersje typówTO_BYTE(), TO_REAL(), TO_USINT()

    Bezpieczeństwo

    15. Walidacja NULL przed dereferencją REF_TO
    16. Fail-fast z RETURN zamiast głębokiego zagnieżdżania
    17. Detekcja zmiany konfiguracji — flaga IsConfigChanged + Reset()
    18. Dzielenie przez zero — sprawdzenie <> 0 przed dzieleniem




    Cytat:
    Autor: Hubert Lepiarczyk a.k.a lunakk | Artykuł oparty na doświadczeniu z produkcyjnymi bibliotekami w środowisku CAREL STone.
    Artykuł pochodzi z bazy wiedzy IceLAB: https://icelab.pl/pl/portal/stone-oop-conventions/

    Fajne? Ranking DIY
    O autorze
    lunakk
    Poziom 14  
    Offline 
    Projektowanie automatyki chłodniczej
    Tworzenie autorskich programów sterujących
    Wdrażanie systemów zdalnego nadzoru maszyn i urządzeń chłodniczych
    Analiza i optymalizacja pracy urządzeń
    Specjalizuje się w: automatyka hvac & bms
    lunakk napisał 104 postów o ocenie 57, pomógł 6 razy. Mieszka w mieście Kraków. Jest z nami od 2007 roku.
📢 Słuchaj (AI):
REKLAMA