engineering

SPS-Programmierung Best Practices

SPS-Programmierung Best Practices: Strukturierte Programmierung nach IEC 61131-3, Namenskonventionen, Fehlerbehandlung und wartbare Code-Strukturen für Siemens TIA Portal.

David Prybisch
15 Min. Lesezeit
SPS-Programmierung Best Practices

1.Einleitung

SPS-Programmierung ist mehr als nur Logikbausteine aneinanderreihen. In über 10 Jahren als Automatisierungsingenieur habe ich unzählige SPS-Projekte gesehen – viele davon mit typischen Problemen:

  • Unlesbare Variablennamen wie M0.0, DB1.DBX0.0 oder %MW100
  • Inkonsistente Programmiersprachenmischung – KOP, FUP, AWL und SCL wild durcheinander im selben Projekt
  • Fehlende Dokumentation – der Original-Programmierer hat das Unternehmen längst verlassen

In diesem Artikel teile ich die wichtigsten Best Practices für wartbare SPS-Programme mit Siemens TIA Portal.

2.Warum Best Practices in der SPS-Programmierung?

2.1.Das Problem: Legacy-Code

Typisches Szenario aus meiner Praxis:

Ein Maschinenbauer ruft an: "Unsere Anlage steht. Können Sie helfen?"

Vor Ort die Ernüchterung:

  • Variablennamen wie M0.0, DB1.DBX0.0, %MW100 – niemand weiß, was dahinter steckt
  • KOP, FUP, AWL und SCL wild durcheinander im selben Projekt
  • Keine Kommentare, keine Strukturierung
  • Original-Programmierer hat das Unternehmen vor Jahren verlassen

Die Fehlersuche dauert unnötig lange, weil sich niemand im Code zurechtfindet.

2.2.Die Lösung: Professionelle Programmierung

Strukturierte, wartbare SPS-Programme bringen klare Vorteile:

  • Schnellere Fehlersuche durch sprechende Variablennamen
  • Kürzere Einarbeitungszeit für neue Programmierer
  • Weniger Maschinenstillstände durch bessere Fehlerbehandlung

3.Best Practice 1: IEC 61131-3-Standards konsequent nutzen

IEC 61131-3 ist der internationale Standard für SPS-Programmierung und Pflicht für CE-zertifizierte Maschinen.

3.1.Die 5 Programmiersprachen im Überblick

SpracheVerwendungVorteileNachteile
SCL (Structured Control Language)Komplexe Algorithmen, BerechnungenÜbersichtlich, lesbar, typsicherNicht für harte Echtzeit geeignet
LAD (Ladder Diagram)Simple Logik, Elektriker-freundlichIntuitiv für ElektrikerUnübersichtlich bei > 50 Rungs
FBD (Function Block Diagram)Regelung, Datenfluss-LogikGraphisch verständlichSchwer wartbar bei großen Programmen
ST (Structured Text)Wie SCL, IEC 61131-3-StandardKompakt, schnellSteile Lernkurve
SFC (Sequential Function Chart)Ablaufsteuerungen (GRAFCET)State-Machines visualisiertOverhead für simple Logik

3.2.Strukturierte Programmierung: Die Pyramide

SPS-Programmstruktur: Hierarchische Bausteinarchitektur von OB1 über FC_SystemControl zu Funktionsbausteinen und Datenbausteinen

OB1 (Main)
  └── FC_SystemControl (Betriebsarten)
       ├── FB_PackMLStateMachine (Ablaufsteuerung)
       │    ├── FB_MotorControl (Anlagenteil)
       │    ├── FB_ValveControl (Anlagenteil)
       │    └── FB_ConveyorControl (Anlagenteil)
       └── FC_AlarmHandler (Utility)

Regel: Jede Ebene hat genau EINE klare Verantwortung.

4.Best Practice 2: Namenskonventionen etablieren

4.1.Das Problem: Variable-Namen-Chaos

Negativ-Beispiel (aus der Praxis):

// ❌ SCHLECHT
M0.0    // Was ist das?
DB1.DBX0.0   // Welcher Motor?
%MW100  // Temperatur? Druck?

Positiv-Beispiel:

// ✅ GUT
bMotorPumpMainRun : BOOL;  // Motor Hauptpumpe läuft
iTemperatureTank1 : INT;   // Temperatur Tank 1 in °C
rPressureSetpoint : REAL;  // Sollwert Druck in bar

4.2.Standardisierte Präfixe (Hungarian Notation)

PräfixDatentypBeispiel
bBOOLbMotorRun, bAlarmActive
iINTiCounter, iTemperature
rREALrSpeed, rPressure
sSTRINGsAlarmText, sRecipeName
dtDATE_TIMEdtStartTime, dtLastMaintenance
tTIMEtDelayStart, tCycleTime
udiUDINTudiPartCounter, udiTotalProduction

4.3.Ein/Ausgänge mit Prefix

// Eingänge: ix (Input X)
ixMotorFeedbackRun : BOOL AT %I0.0;  // "x" = Bool
iwTemperatureSensor : WORD AT %IW0;   // "w" = Word

// Ausgänge: qx (Output X)
qxMotorStart : BOOL AT %Q0.0;
qwValvePosition : WORD AT %QW0;

Konsistenz ist König: Entscheiden Sie sich im Team für EINE Konvention und dokumentieren Sie sie.

5.Best Practice 3: Funktionsbausteine vs. Funktionen richtig einsetzen

5.1.Funktionsbausteine (FB) - Zustandsbehaftet

Wann verwenden?

  • Anlagenteile mit Zustand (Motor, Ventil, Förderband)
  • Alarm-Handler
  • State-Machines

Beispiel: Motor-Steuerung

FUNCTION_BLOCK FB_MotorControl
VAR_INPUT
  bStart : BOOL;        // Startbefehl
  bStop : BOOL;         // Stoppbefehl
  bFeedback : BOOL;     // Rückmeldung Motor läuft
END_VAR

VAR_OUTPUT
  qxStart : BOOL;       // Ausgang Motorstart
  bRunning : BOOL;      // Status: Motor läuft
  bAlarm : BOOL;        // Störung aktiv
END_VAR

VAR
  tDelayStart : TON;    // Verzögerung beim Start
  tTimeoutFeedback : TON; // Timeout für Rückmeldung
  bAlarmLatched : BOOL; // Gespeicherte Störung
END_VAR

// Programmlogik hier...
END_FUNCTION_BLOCK

Aufruf:

// Im OB1 oder FC
dbMotorPumpMain(
  bStart := bSystemRun AND NOT bEmergencyStop,
  bStop := bSystemStop OR bEmergencyStop,
  bFeedback := ixMotorPumpMainFeedback
);
qxMotorPumpMainStart := dbMotorPumpMain.qxStart;

5.2.Funktionen (FC) - Zustandslos

Wann verwenden?

  • Berechnungen ohne Zustand
  • Skalierungen
  • Mathematische Operationen
  • Hilfsfunktionen

Beispiel: Temperatur-Skalierung

FUNCTION FC_ScaleTemperature : REAL
VAR_INPUT
  iwRawValue : INT;  // Rohwert von Sensor (0-27648)
  rMinTemp : REAL;   // Minimale Temperatur (z.B. -50°C)
  rMaxTemp : REAL;   // Maximale Temperatur (z.B. +150°C)
END_VAR

// Skalierung 0-27648 → rMinTemp bis rMaxTemp
FC_ScaleTemperature := rMinTemp +
  (REAL#iwRawValue / 27648.0) * (rMaxTemp - rMinTemp);
END_FUNCTION

Aufruf:

rTemperatureTank1 := FC_ScaleTemperature(
  iwRawValue := iwTempSensor1,
  rMinTemp := -50.0,
  rMaxTemp := 150.0
);

6.Best Practice 4: Fehlerbehandlung nach NAMUR NE 107

NAMUR NE 107 ist der Industriestandard für Selbstüberwachung und Diagnose in der Prozessindustrie. Im Maschinenbau hat er sich ebenfalls etabliert.

6.1.Die 4 Zustände

NAMUR NE 107 Diagnosezustände: Normal Operation, Maintenance Required, Function Check, Failure

6.2.Implementierung mit FB_AlarmHandler

FUNCTION_BLOCK FB_AlarmHandler
VAR_INPUT
  bTrigger : BOOL;          // Alarm-Auslöser
  eAlarmLevel : INT;        // 1=Info, 2=Warning, 3=Error, 4=Critical
  sAlarmText : STRING[80];  // Alarm-Text
END_VAR

VAR_OUTPUT
  bAlarmActive : BOOL;      // Alarm ist aktiv
  bAckRequired : BOOL;      // Quittierung erforderlich
END_VAR

VAR
  bAlarmLatched : BOOL;     // Gespeicherter Alarm
  dtTimestamp : DATE_TIME;  // Zeitstempel des Alarms
END_VAR

// Logik: Alarm speichern, Zeitstempel setzen, ggf. quittieren
IF bTrigger AND NOT bAlarmLatched THEN
  bAlarmLatched := TRUE;
  dtTimestamp := CURRENT_TIMESTAMP();
  bAlarmActive := TRUE;

  // Logging zu HMI/SCADA
  // ...
END_IF;

bAckRequired := bAlarmLatched AND eAlarmLevel >= 3;
END_FUNCTION_BLOCK

Best Practice: Ein zentraler Alarm-Manager sammelt alle Alarme und kommuniziert sie gebündelt zum HMI.

7.Best Practice 5: Versionierung mit Git

Ja, Git funktioniert auch für SPS-Code! Seit TIA Portal v18 ist die Integration deutlich einfacher geworden.

7.1.Setup: TIA Portal mit Git

1. Multiuser Engineering aktivieren

TIA Portal → Projekt → Eigenschaften → Multiuser Engineering → Aktivieren

2. Projekt in Git-freundlichem Format speichern

# .gitignore für TIA Portal
*.ap18
*.zap18
__OPNB*
*.bak

3. Git-Repository initialisieren

git init
git add .
git commit -m "Initial commit: TIA Portal project setup"

7.2.Branching-Strategie für SPS-Projekte

main (Produktiv-Code)
  ├── develop (Entwicklung)
  │    ├── feature/motor-control-update
  │    ├── feature/add-safety-logic
  │    └── bugfix/alarm-text-typo
  └── hotfix/critical-emergency-stop-bug

Workflow:

  1. Feature-Branch erstellen: git checkout -b feature/new-conveyor-logic
  2. Änderungen committen: git commit -m "Add conveyor start delay 2s"
  3. Pull Request erstellen (GitHub, GitLab)
  4. Code-Review durch zweiten Programmierer
  5. Merge in develop
  6. Testing auf Entwicklungs-SPS
  7. Release-Branch → main

8.Best Practice 6: Kommentare und Dokumentation

8.1.Code-Kommentare: Die 3-Zeilen-Regel

Schlecht:

// ❌ Offensichtlich, bringt nichts
bMotorRun := TRUE;  // Motor starten

Gut:

// ✅ Erklärt WARUM, nicht WAS
// Verzögerung 2s wegen Druckaufbau im Hydraulik-Kreislauf
// (Siehe Anforderung REQ-HYD-012)
tDelayStart(IN := bStartRequest, PT := T#2S);
qxMotorStart := tDelayStart.Q;

8.2.Dokumentations-Standards

Für jeden FB/FC:

(*
  Name: FB_MotorControl
  Version: 1.2.0
  Autor: David Prybisch
  Datum: 2025-11-22

  Beschreibung:
    Standardisierter Motorsteuerung mit Anlaufverzögerung,
    Rückmeldungsüberwachung und Störungsspeicherung.

  Änderungshistorie:
    v1.2.0 - 2025-11-22 - Timeout-Überwachung hinzugefügt
    v1.1.0 - 2025-10-15 - NAMUR-Alarm-Integration
    v1.0.0 - 2025-09-01 - Erste Version
*)
FUNCTION_BLOCK FB_MotorControl
// ...
END_FUNCTION_BLOCK

UML-Diagramme für Systemarchitektur:

Nutzen Sie Tools wie PlantUML oder Microsoft Visio, um die Gesamtarchitektur zu visualisieren.

9.Best Practice 7: Testing und Simulation

9.1.Simulation mit PLCSIM

Siemens PLCSIM Advanced ermöglicht das Testen von SPS-Programmen ohne physische Hardware:

Workflow:

  1. SPS-Programm im TIA Portal entwickeln
  2. PLCSIM Advanced starten und Projekt laden
  3. Variablen über Beobachtungstabelle setzen und prüfen
  4. Ablaufsteuerungen systematisch durchtesten

Vorteile:

  • Fehler früh erkennen – im Büro statt beim Kunden
  • Neue Programmierer können gefahrlos testen
  • Änderungen vor der Inbetriebnahme validieren

10.Best Practice 8: Performance-Optimierung

10.1.CPU-Auslastung im Blick behalten

Häufige Performance-Killer:

  1. Zu viele Timer/Counter → Nutzen Sie Arrays statt einzelner Variablen
  2. String-Operationen in Echtzeitzyklen → Lagern Sie in niederpriorisierte Tasks aus
  3. Komplexe Berechnungen in OB1 → Verwenden Sie zyklische Interrupts (OB35)

Beispiel: Array-basierte Timer-Verwaltung

// ❌ SCHLECHT: 100 einzelne Timer
VAR
  tMotor1 : TON;
  tMotor2 : TON;
  // ... 98 weitere Timer
END_VAR

// ✅ GUT: Array von Timern
VAR
  atMotorTimers : ARRAY[1..100] OF TON;
END_VAR

// Aufruf in Schleife
FOR i := 1 TO 100 DO
  atMotorTimers[i](IN := abMotorStart[i], PT := T#2S);
  aqxMotorStart[i] := atMotorTimers[i].Q;
END_FOR;

10.2.Speicher-Optimierung mit Multi-Instanzen

Problem: Jeder FB-Instanz verbraucht eigenen DB (Instanz-DB).

Lösung: Multi-Instanzen für wiederkehrende Bausteine.

// FB_ConveyorLine enthält 10x FB_MotorControl als Multi-Instanz
FUNCTION_BLOCK FB_ConveyorLine
VAR
  Motor1 : FB_MotorControl;  // Multi-Instanz
  Motor2 : FB_MotorControl;
  // ...
END_VAR

// Nur EINE Instanz von FB_ConveyorLine anlegen
dbConveyorLine : FB_ConveyorLine;  // Spart 90% Speicher vs. 10 separate FBs

11.Fazit: Professionelle SPS-Programmierung zahlt sich aus

Die Investition in strukturierte, wartbare SPS-Programme rentiert sich mehrfach:

  • Schnellere Fehlersuche durch sprechende Variablennamen und klare Struktur
  • Kürzere Einarbeitungszeit für neue Programmierer
  • Weniger Maschinenstillstände durch bessere Fehlerbehandlung
  • Einfachere Wartung über die gesamte Anlagenlebensdauer

11.1.Checkliste für Ihr nächstes SPS-Projekt

  • Namenskonventionen mit Team vereinbart und dokumentiert
  • Hierarchische Programmstruktur geplant (UML-Diagramm)
  • IEC 61131-3-Standards eingehalten
  • Alarm-Management nach NAMUR NE 107 implementiert
  • Git-Repository angelegt und .gitignore konfiguriert
  • Simulation mit PLCSIM vorbereitet
  • Code-Review-Prozess etabliert
  • Dokumentation (FB-Header, Systemarchitektur) erstellt

12.Infografik: SPS Best Practices auf einen Blick

SPS-Programmierung Best Practices Infografik: Checkliste für strukturierte, wartbare SPS-Programme

13.Weiterführende Ressourcen


Über den Autor: David Prybisch ist seit über 10 Jahren als SPS-Programmierer tätig. Er unterstützt Maschinenbauer bei strukturierter Programmierung mit Siemens TIA Portal, Code-Reviews und Inbetriebnahme.

Schlagwörter

SPS-ProgrammierungTIA PortalIEC 61131-3SiemensBest PracticesCode QualityNAMUR NE 107SCLAutomatisierung

Weitere Artikel