Hier mal Beispielcode, wie ich die Impulsübertragung über Bus mache.
Der eigentliche Haupt-Zähler (32 Bit oder mehr) ist in der Master-SPS, die Impulseingänge sind an einer Slave-SPS, die die Impulse in einen Vorzähler (8 Bit bzw. 7 Bit bei Profibus) zählt. Der Master liest über Bus den Zählerstand des Vorzählers und vergleicht, um wieviel der Vorzähler seit der letzten Lesung weitergezählt hat und addiert den Differenzbetrag zum Hauptzähler. Von Impulsverlängerung halte ich nicht viel, weil auch verlängerte Impulse bei Busproblemen verloren gehen oder sogar mehrfach gezählt werden können. Außerdem kann man bei entsprechender Zählfrequenz die Impulse nicht beliebig verlängern.
Ich habe öfter Wasser-Verbrauchszähler mit sehr kurzen Zählimpulsen (3ms ... 10ms), wo ich als preiswerte Zählereingänge S7-200 benutze und per MPI an die Master-SPS kopple (Lesen von der S7-200 mit SFC67 "X_GET"). Die Zykluszeit der S7-200 wird als 1ms angezeigt. Wenn die Zählimpulse sehr kurz sind, dann kann man an der S7-200 auch noch den Impulsabgriff aktivieren. Theoretisch kann die S7-200 so bis knapp 500Hz zählen.
Mit meiner Vorzähler-Variante habe ich noch nie Probleme gehabt. Wenn jede Sekunde ein Impuls kommt, dann kann die Busverbindung über 4 Minuten ausfallen oder die Master-SPS in Stop stehen, ohne daß ein Zählimpuls verloren geht. Bei Übertragung über Profibus-DP muß noch beachtet werden, daß bei Unterbrechung der Profibus-Verbindung die Slave-Eingangsdaten vom DP-Master auf 0 gesetzt werden. Dies darf den Master-Zähler nicht beeinflussen. In meiner Variante wird der Master-Zähler bei Profibus-Ausfall nicht 0, sondern bleibt einfach nur stehen. Wenn der Profibus-Ausfall nur kurzzeitig ist, dann werden die zwischenzeitlichen Zählimpulse später dazuaddiert.
Da meistens mehrere Zähler zu verarbeiten sind, bietet es sich an, für die Zählfunktionen Multiinstanz-FB zu benutzen. Wenn aber an den SPS öfters Programmänderungen gemacht werden sollen, sollten die Zähler-Variablen nicht in der FB-Instanz liegen, sondern per IN_OUT in einem globalen extra-DB abgelegt sein, der möglichst nur die Zählerwerte und ein paar Reserven enthält. Dann können auch die Zählerprogrammteile ohne Verlust der Zählerstände geändert werden.
Hier der Vorzähler in der Slave-SPS (als FC mit ausgelagerter Zähler-Variable):
Code:
FUNCTION "Slave_Vorzaehler_Byte" : VOID
TITLE =Vorzähler 7 Bit im DP-Slave
VERSION : 0.1
VAR_INPUT
IN_xZaehleingang : BOOL ;
END_VAR
VAR_IN_OUT
IO_xFlankenmerker : BOOL ;
IO_bZaehler : BYTE ;
END_VAR
BEGIN
NETWORK
TITLE =Impulszähler mit Bit .7 immer 1
//Zählt 128 ... 255 -> 128 ... 255 ...
L #IO_bZaehler;
U #IN_xZaehleingang;
FP #IO_xFlankenmerker;
SPBN EZ;
+ 1;
EZ: OW W#16#80; // Bit .7
T #IO_bZaehler; // immer setzen
END_FUNCTION
Hier der Hauptzähler in der Master-SPS (als FB mit Zähler-Variable in der Instanz):
Code:
FUNCTION_BLOCK FB 31
TITLE =Zähler mit 7-Bit-Vorzähler über Bus
//Das Vorzähler-Bit .7 ist immer 1 gesetzt um Profibusausfall zu erkennen.
VERSION : 0.1
VAR_INPUT
IN_bRECV_VZ : BYTE ; //jetzt empfangener Vorzähler-Stand
END_VAR
VAR
STAT_bVZ_old : BYTE ; //zuletzt empfangener Vorzähler-Stand
STAT_dZaehler : DINT ; //Zählerstand 0 bis 999.999.999
END_VAR
BEGIN
NETWORK
TITLE =Differenz zum vorherigen Vorzähler-Stand zum Zähler addieren
//Der Slave-Vorzähler zählt 128...255 mit Wrap zu 128, Bit .7 ist immer 1
//Der Master-Hauptzähler zählt von 0...999.999.999 und macht dann Wrap
//über Profibus empfangenen Slave-Vorzähler-Stand prüfen,
//falls Profibus ausgefallen, dann ist Bit .7 (und alle anderen) = 0
L 128;
L #IN_bRECV_VZ;
>I ;
SPBN DVZ; //OK, #IN_bRECV_VZ = 128..255
L 0; //.7=0! -> 0 addieren
SPA ADZ;
//Differenz zum zuletzt empfangenen Vorzähler-Stand (wird meist 0 sein)
//hier Akku1: #IN_bRECV_VZ mit .7=1
DVZ: L #STAT_bVZ_old;
-I ; //#IN_bRECV_VZ - #STAT_bVZ_old
UW W#16#7F; //falls Wrap -> positive Differenz
L #IN_bRECV_VZ;
T #STAT_bVZ_old; //#IN_bRECV_VZ merken
POP ; //Differenz zurück in Akku1
//positive Differenz Vorzähler zum Hauptzähler addieren
//hier Akku1: positive Differenz oder 0 bei Profibus-Ausfall
ADZ: L #STAT_dZaehler;
+D ;
L L#1000000000;
MOD ; //Wrap bei > 999.999.999
T #STAT_dZaehler;
END_FUNCTION_BLOCK
Wem als Puffer 127 Impulse Vorzähler nicht reichen, im Anhang sind auch Baustein-Versionen für 32767 Impulse (INT).
Harald