In der Welt der industriellen Automatisierung und SPS-Programmierung ist die Datenintegrität von größter Bedeutung. Eine gängige Methode zur Gewährleistung dieser Integrität ist die Verwendung von CRC-Berechnungen (Cyclic Redundancy Check). Diese Algorithmen generieren einen Prüfwert basierend auf den Daten, der dann mit den Daten gespeichert oder übertragen wird. Der Empfänger kann dann denselben Algorithmus verwenden, um den Prüfwert neu zu berechnen und ihn mit dem empfangenen Prüfwert zu vergleichen. Stimmen die Prüfwerte überein, ist die Wahrscheinlichkeit hoch, dass die Daten nicht beschädigt wurden.
Oftmals werden CRC-Algorithmen in höheren Programmiersprachen wie C# entwickelt und getestet, bevor sie in die raueren Umgebungen von SPS-Systemen implementiert werden. Der Grund dafür ist, dass C# leistungsstarke Debugging-Tools und eine breitere Palette an Bibliotheken zur Verfügung stellt, was die Entwicklung und das Testen deutlich vereinfacht. Die Übertragung eines CRC-Algorithmus von C# auf ST (Structured Text), die primäre Programmiersprache für viele SPS-Systeme, kann jedoch eine Herausforderung darstellen. Dieser Artikel führt Sie Schritt für Schritt durch diesen Prozess.
Warum CRC in SPS-Systemen?
Bevor wir uns mit der eigentlichen Portierung befassen, wollen wir kurz beleuchten, warum CRC-Prüfungen in SPS-Anwendungen so wichtig sind:
- Datenintegrität bei der Kommunikation: In industriellen Umgebungen kommunizieren SPS-Systeme oft mit anderen Geräten über verschiedene Kommunikationsprotokolle wie Modbus, Profibus oder Ethernet/IP. Diese Protokolle können anfällig für Rauschen und Störungen sein, die zu Datenbeschädigungen führen können. CRC-Prüfungen helfen dabei, diese Fehler zu erkennen und zu beheben.
- Speicherintegrität: Daten, die in SPS-Speichern abgelegt sind, können durch Hardwarefehler oder Softwarefehler beschädigt werden. CRC-Prüfungen können verwendet werden, um die Integrität gespeicherter Daten regelmäßig zu überprüfen.
- Sicherheit: Obwohl CRC kein robustes kryptografisches Verfahren ist, kann es helfen, versehentliche oder unbeabsichtigte Datenmanipulationen zu erkennen.
Schritt 1: Verstehen des C#-CRC-Algorithmus
Der erste Schritt besteht darin, den C#-Code des CRC-Algorithmus vollständig zu verstehen. Dies beinhaltet das Verständnis der verwendeten CRC-Variante (z. B. CRC-16, CRC-32), des verwendeten Polynoms und des Initialwerts. Ein typischer C#-CRC-Algorithmus könnte so aussehen:
„`csharp
public class CRC
{
private static readonly uint[] CrcTable = GenerateCrcTable(0xEDB88320); // CRC-32 Polynomial
private static uint[] GenerateCrcTable(uint polynomial)
{
uint[] table = new uint[256];
for (uint i = 0; i < 256; i++)
{
uint temp = i;
for (int j = 0; j < 8; j++)
{
if ((temp & 1) == 1)
{
temp = (temp >> 1) ^ polynomial;
}
else
{
temp >>= 1;
}
}
table[i] = temp;
}
return table;
}
public static uint CalculateCRC(byte[] data)
{
uint crc = 0xFFFFFFFF; // Initial value
foreach (byte b in data)
{
crc = (crc >> 8) ^ CrcTable[(crc & 0xFF) ^ b];
}
return ~crc; // Final XOR value
}
}
„`
In diesem Beispiel wird der CRC-32-Algorithmus verwendet. Der Algorithmus basiert auf einer Lookup-Tabelle, die vorab berechnet wird, um die Berechnung zu beschleunigen. Das Polynom ist 0xEDB88320 und der Initialwert ist 0xFFFFFFFF.
Schritt 2: Identifizieren von Unterschieden zwischen C# und ST
C# und ST unterscheiden sich in Bezug auf Datentypen, Operatoren und die Art und Weise, wie Speicher verwaltet wird. Einige wichtige Unterschiede, die bei der Portierung berücksichtigt werden müssen, sind:
- Datentypen: C# bietet eine breitere Palette an Datentypen als ST. Beispielsweise gibt es in ST möglicherweise keinen direkten Entsprechungsdatentyp für ‘uint’. Sie müssen möglicherweise den am besten geeigneten Datentyp auswählen, z. B. UDINT oder DWORD.
- Arrays: ST-Arrays sind in der Regel statisch dimensioniert, während C#-Arrays dynamisch sein können. Stellen Sie sicher, dass die ST-Arrays groß genug sind, um alle Daten aufzunehmen.
- Bitweise Operationen: ST unterstützt zwar bitweise Operationen wie AND, OR, XOR und NOT, aber die Syntax kann sich von C# unterscheiden.
- Funktionen und Funktionsbausteine: In ST sollten Sie den CRC-Algorithmus in einem Funktionsbaustein (FB) oder einer Funktion kapseln, um die Wiederverwendbarkeit zu gewährleisten.
Schritt 3: Portierung des Codes von C# auf ST
Nachdem Sie die Unterschiede zwischen C# und ST verstanden haben, können Sie mit der eigentlichen Portierung beginnen. Hier ist ein Beispiel, wie der obige C#-CRC-Algorithmus in ST übersetzt werden könnte:
„`st
FUNCTION_BLOCK FB_CRC32
VAR_INPUT
pData : POINTER TO BYTE; // Pointer to the data
uiDataLength : UINT; // Length of the data
END_VAR
VAR_OUTPUT
udiCRC : UDINT; // Calculated CRC value
END_VAR
VAR
udiCrcTable : ARRAY[0..255] OF UDINT;
uiIndex : UINT;
uiByteIndex : UINT;
udiTemp : UDINT;
bByte : BYTE;
bInitialized : BOOL := FALSE;
END_VAR
// Generate CRC Table (only once)
IF NOT bInitialized THEN
FOR uiIndex := 0 TO 255 DO
udiTemp := uiIndex;
FOR uiByteIndex := 0 TO 7 DO
IF (udiTemp AND 16#00000001) <> 0 THEN
udiTemp := SHR(udiTemp, 1) XOR 16#EDB88320;
ELSE
udiTemp := SHR(udiTemp, 1);
END_IF
END_FOR
udiCrcTable[uiIndex] := udiTemp;
END_FOR
bInitialized := TRUE;
END_IF
// Calculate CRC
udiCRC := 16#FFFFFFFF; // Initial value
FOR uiIndex := 0 TO uiDataLength – 1 DO
bByte := pData[uiIndex];
udiCRC := SHR(udiCRC, 8) XOR udiCrcTable[(udiCRC AND 16#000000FF) XOR BYTE_TO_UDINT(bByte)];
END_FOR
udiCRC := NOT udiCRC; // Final XOR value
END_FUNCTION_BLOCK
„`
Einige wichtige Punkte sind hier zu beachten:
- Der CRC-Algorithmus ist in einem Funktionsbaustein (FB_CRC32) gekapselt.
- Die Daten werden über einen Pointer (pData) und eine Länge (uiDataLength) übergeben. Dies ist eine übliche Methode, um mit Speicher in ST umzugehen.
- Die CRC-Lookup-Tabelle wird beim ersten Aufruf des Funktionsbausteins generiert und in der Variablen `udiCrcTable` gespeichert. Die Variable `bInitialized` sorgt dafür, dass die Tabelle nur einmal generiert wird.
- Die bitweisen Operationen SHR (Shift Right) und XOR werden verwendet, um die CRC-Berechnung durchzuführen.
- Der Initialwert und der Final XOR-Wert werden wie im C#-Code angewendet.
Schritt 4: Testen und Debuggen des ST-Codes
Nach der Portierung ist es wichtig, den ST-Code gründlich zu testen und zu debuggen. Verwenden Sie die Debugging-Tools Ihrer SPS-Entwicklungsumgebung, um den Code Schritt für Schritt auszuführen und die Werte der Variablen zu überwachen. Vergleichen Sie die Ergebnisse des ST-Codes mit den Ergebnissen des C#-Codes für verschiedene Datensätze, um sicherzustellen, dass die Berechnungen korrekt sind.
Berücksichtigen Sie bei der Fehlersuche die folgenden Punkte:
- Datentypen: Stellen Sie sicher, dass die verwendeten Datentypen in ST die gleiche Größe und Darstellung wie die entsprechenden Datentypen in C# haben.
- Array-Indizes: ST-Arrays sind nullbasiert. Stellen Sie sicher, dass die Array-Indizes innerhalb der Grenzen liegen.
- Bitweise Operationen: Überprüfen Sie die korrekte Verwendung von bitweisen Operatoren.
- Initialwerte: Stellen Sie sicher, dass die Initialwerte korrekt gesetzt sind.
Schritt 5: Optimierung (optional)
Nachdem der ST-Code korrekt funktioniert, können Sie ihn optional optimieren, um die Leistung zu verbessern. Einige Optimierungstechniken sind:
- Manuelle Optimierung: Anstatt die CRC Tabelle immer wieder neu zu berechnen kann diese auch als Konstante deklariert werden. Damit spart man Rechenzeit und Zykluszeit.
- Verwendung von optimierten Bibliotheken: Einige SPS-Hersteller bieten optimierte Bibliotheken für CRC-Berechnungen an. Diese Bibliotheken können eine bessere Leistung bieten als selbst geschriebener Code.
- Code-Profiler: Verwenden Sie einen Code-Profiler, um Leistungsengpässe zu identifizieren und den Code entsprechend zu optimieren.
Fazit
Die Portierung eines CRC-Algorithmus von C# auf ST erfordert ein Verständnis der Unterschiede zwischen den beiden Sprachen und eine sorgfältige Übersetzung des Codes. Durch Befolgen der in diesem Artikel beschriebenen Schritte können Sie einen korrekten und effizienten CRC-Algorithmus für Ihre SPS-Anwendung erstellen. Denken Sie daran, den Code gründlich zu testen und zu debuggen, bevor Sie ihn in einer Produktionsumgebung einsetzen.