TIA Ein DB-Array mit Istwerten aus einem Eingang zyklich Füllen in SCL für S7-1200

Beiträge
37
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo liebe leute ,

ich hoffe ihr könnt mir weiterhelfen. Ich suche schon seit einer Woche eine möglichkeit Messwerte in ein DB zyklisch zu speichern. An sich klingt das ganze voll einfach, aber ich hab keine Ahnung von SCL.
Ich hab mir auch diesen Programmier Guide für S7-1200 durch gelesen und so eine Einführung in die Programmiersprache Strukturierter Text .
https://w3.siemens.com/mcms/sce/de/...1318674_Programming_guideline_DOKU_v13_de.pdf
http://www.ipsta.de/download/automationstechnik/Kap13_ST .pdf

Leider komme ich auch nicht wirklich weiter. Hier im Forum wurde ich auch nicht fündig. Langsam bin ich echt frustiert . :confused:

Ich hoffe hier kann mir einer weiter helfen.

Also ganz kurz zu meinem Problem.

Ich hab an meiner s7-1200 am Analogeingang ein Signal das sich ständig ändert. Und ich möchte z.b. alle 5 sekunden das signal in ein DB schreiben, dies soll er jedoch erst tun wenn ich ihm durch ein anderen Digitaleneingang E0.1 eine 1 anlege. Das ganze soll er solange tun bis der DB voll ist oder ich am E0.1 das signal wegnehme. Erstmal soll einfach der DB begrenzt fauf 50 Werte festgelegt sein.

Ich hab jetzt als Zyklischen Timer nichts gefunden bzw. keine andere idee als einen Taktmerker zu verwenden.

Anschließend habe ich mir gedacht, wenn ich ein Taktmerker benutze sagen wir mal M1.5 für eine Frequenz von 1 Hz und den E.0.1 baue ich das in eine For schleife ein.

also so ungefähr

For E0.1:=1 Do
if M1.5:=1 then
Füll mir im DB/Array die nächste Freie Position
end_if

Und genau da hört mein latein auf..:???:...Ich hoffe ihr habt Tipps oder könnt mir weiterhelfen

Schonmal ein ganz lieben Dank im Voraus
 
Im Grundsatz nicht schlecht, aber wenn du eine For-Schleife verwendest, wird diese in dem Bausteinaufruf jedes mal komplett abgearbeitet. D.h. der Eingangswert stünde 50 mal identisch in deinem DB (wenn man den Takt ignoriert).

grundsätzlich würde ich ein Array anlegen "Messwerte Array[0..49] of int" und das Ganze nicht in einer Forschleife machen lassen sonder eher wie folgt:

Code:
IF M1.5 AND E0.1 THEN
     #Messwerte[Zähler] := Input;
     #Zähler:= #Zähler + 1;
end if;

Dazu sollte man sagen: Den wenn ich deinen Anwendungsfall richtig verstehe möchtest du die Taktflanke haben, nicht die ganze Zeit des Taktes, korrekt?


Code:
#Flankenerkennung:=#"Takt alt" XOR #Taktflanke;
#"Takt alt":=Taktflanke;

(Syntax dürfe falsch sein, nur um das Prinzip zu erläutern.)

Hoffe das hilft etwas.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Was soll der Geiz :): anbei eine Quelle als Vorschlag:
Code:
FUNCTION_BLOCK "MW Speichern"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      "Analog in" : Int;   // Analogeingang Hier
      Enable : Bool;   // Dein Beispiel E0.1
      Takt : Bool;   // Taktmerker
   END_VAR

   VAR DB_SPECIFIC
      Messwerte : Array[0..49] of Int;
   END_VAR
   VAR 
      Zähler : Int;
      Taktmerker : Bool;
   END_VAR


BEGIN
    //Wird ausgeführt wenn eine Taktflanke erkannt wird, der Enable Eingang gesetzt ist und der Zähler kleiner als 50 ist
    IF #Enable AND (#Taktmerker XOR #Takt) AND (#Zähler<50) THEN
        #Messwerte[#Zähler] := #"Analog in";                     // Speichern des Signal im Array
        #Zähler := #Zähler + 1;                                  // Zähler erhöhen
    END_IF;
    
    
    #Taktmerker := #Takt; //Signal Speicher für Flankenerkennung
    
    //WICHTIG: Der Zähler wird nirgendwo wieder auf 0 gesetzt. Bezüglich Rücksetzen des Zählers gab es keine Vorgaben! Demnach funktioniert dies nur für 50 Takte.
        
END_FUNCTION_BLOCK
 
Hi Christmaspoo,

ich bedank mich mal ganz schnell bei dir^^... du bist ne riesen Hilfe. Sitz gerade am PC und kämpfe gerade bis ich gesehen habe das du geantwortet hast.

Ich versuch das mal umzusetzten, aber du hast vollkommen Recht ich hab das garnicht bedacht mit dem Zähler zurück setzten. D.h. der würde 50 istwerte speichern und dann wäre mein Zähler auf 50 und dann geht garnix mehr oder?

Hast du das in Step 7 V5.x geschrieben?
 
Bei indirektem Zugriff auf Arrays empfiehlt es sich immer, den variablen Index vor der Verwendung auf Zulässigkeit zu prüfen. Da kann man bei Ringpuffern auch gleich elegant den Wrap vom Array-Ende auf den Array-Anfang einbauen:
Code:
    IF #Enable AND (#Taktmerker XOR #Takt) THEN
        [COLOR="#0000CD"]#Zähler := #Zähler MOD 50 ;[/COLOR]
        #Messwerte[#Zähler] := #"Analog in";
        #Zähler := #Zähler + 1;
    END_IF;

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich hab das jetzt so übernommen wie Christmispoo es geschrieben hat und es sieht bei mir so aus.
Die Var_inputs habe ich auch übernommen, jedoch spinnt bei mir der Zähler. Beim Beobachten habe ich das gefühl das der wie verrückt springt.
Code:
    IF #Enable AND ("Clock_10Hz" XOR #Takt) AND ("Zähler" < 50) THEN
        "DB_SPECIFIC".Messwerte["Zähler"] := #"Analog in";                     // Speichern des Signal im Array
        "Zähler" := "Zähler" + 1;                                  // Zähler erhöhen
    END_IF;
    
    
    "Clock_1Hz" := #Takt;

#Taktmerker := #Takt; //Signal Speicher für Flankenerkennung
das ist etwas was mich verwirrt. Der Taktmerker wird doch von der CPU festgelegt und wie kann dann da eine zuweisung stattfinden wenn das die CPU garnicht mitmacht? :confused:


AChja und mein Taktmerker Spinnt, der kriegt immer nur ganz kurz ein True wenn der #Enable =1 ist, dann passiert nix mehr. Und wenn ich den Schalter immer wieder betätige passiert immer das selbe.
 
Zuletzt bearbeitet:
Hast Du den Code in einer FC programmiert? Und/oder "Zähler" in TEMP deklariert?
Bei Christmaspoo sind "Zähler" und "Taktmerker" im STAT eines FB.
Er hat auch keine Zuweisungen an die globalen CPU-Taktmerker drin, Dein " "Clock_1Hz" := #Takt; " ist falsch.

Harald
 
Hi Harald,

dir auch erstmal vielen Dank für deine Hilfe.

also ich hab Zähler in Temp deklariert. Dann hat er gemeckert, dass "Zähler" nicht zugewiesen ist. Anschließend habe ich sie in die Variablentabelle eingefügt.

Komischerweise funktioniert mein Taktmerker nicht obwohl ich ihn in der Hardwarekonfig eingeschaltet habe.

Ich hab mal Screenshots mit angehängt vlt. seht ihr den Fehler :S.

Ich hab mal den #Takt Eingang testweise dauerhaft auf 1 gesetzt. Der Zähler zählt nicht hoch, d.h. der beschreibt immer nur den ersten wert.
 

Anhänge

  • screenshot.2PNG.PNG
    screenshot.2PNG.PNG
    61,2 KB · Aufrufe: 67
  • screenshot3.PNG
    screenshot3.PNG
    50,1 KB · Aufrufe: 66
  • screenshot.jpg
    screenshot.jpg
    74,2 KB · Aufrufe: 67
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Die Variablen in TEMP können sich nichts merken. Deshalb müssen "Zähler" und "Taktmerker" in Static eines FB deklariert werden oder notfalls globale Variablen (Merker, Global-DB) sein, dann möglichst über InOut an den Baustein bringen. Am besten, Du programmierst den Code in einem FB wie es Christmaspoo gezeigt hat.

Wegen den nicht funktionierenden Taktmerkern: ist die Hardware-Konfiguration in die CPU geladen? Gibt es Unterschiede Online(CPU) <-> Offline(Projekt)?

Harald
 
Achh ich bin so doof ich hab das mit dem FB übersehen :ROFLMAO:...Sorry okay ich mach das jetzt schnell .

Ja hab die Hardware-Konfiguration geladen, kann auch gerade nicht sagen was da ist :S.

Noch ne Kurze Frage. Wenn ich das in eine FB schreibe erzeugt er doch ein DB. Speicher ich die istwerte in diesen DB der für den FB ist oder in einem separaten DB ?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn du die Daten im FB deklariert hast, dann speichert er sie auch im zugehörigen erzeugten DB. Du kannst alternativ auch Variablen in einem extra DB deklarieren und diese in deinem FB verwenden. Wenn du bestimmte Variablen und Daten nicht im Instanz-DB haben möchtest.


Mit Freundlichen Grüßen,

Gnaldariel
 
Zuletzt bearbeitet:
im gestellten Beispiel werden die Werte im Instanz DB gespeichert. Das kann auch ausgelagert werden. Wenn die Anwendung ein FC sein soll, müssen die in der Instanz gespeicherten Variablen in einen anderen Bereich geschoben werden. (siehe einige Antworten zuvor).
 
Ich würde gern von den Inhalten des Arrays den Durchschnitt bilden, aber nur von denen die nicht 0 sind um während der ersten Messungen keinen falschen Wert zu bekommen.
Ich habe nur 10 Werte in meinem Array.
Hat jemand dazu einen Ansatz?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Code:
FOR #Zähler:=0 TO 10 DO
       IF #Array[#Zähler]=0 THEN
              #Speicher_Var:=#Zähler-1;
              EXIT;
       ELSE IF #Zähler = 10 THEN
              #Speicher_Var:=10;
       END_IF;
END_FOR;

#Ergebnis:=0;

FOR #Zähler:=0 TO #Speicher_Var DO
       #Ergebnis:=#Ergebnis + #Array[#Zähler];
END_FOR;

Ergebnis:= Ergebnis / #Speicher_Var;

Sowas?
 
Hi leute,

ganz herzlichen dank an Christmisspoo und Harald. Eben habe ich das ganze nochmal runter geschrieben und siehe da es klappt. Obwohl ich absolut nicht weiß wo der unterschied zu gestern gewesen ist.

Und jetzt ist genau das was du angesprochen hast Christmisspoo: Den Zähler reseten.
Hab da noch ein Eingang #Reset hinzugefügt und die If bedingung dazu. ist das geschickt? (Frage an die erfahrenen User)
Code:
 IF #Reset=1  THEN
        #Zähler := 0;  
    END_IF;

IF #Enable AND (#Taktmerker XOR #Takt) AND (#Zähler<#Messwertanzahl)THEN
    "Temp_1".Messwert[#Zähler] := #"Analog in";
    #Zähler := #Zähler + 1;
    #Taktmerker:=#Takt;
   
    
END_IF;

#Taktmerker := #Takt;

Wäre es eine gute Idee den Zähler immer dann zu wenn ich die die Messung anstoße, also sprich mit meinem Beispiel E0.1 ?

Und Christmispoo du mit deinem Code nimmst du ja die Messwerte in dem DB für den FB auf stimmts?
Mit
Code:
VAR DB_SPECIFIC   Messwerte: Array [0..49] of int
. In Tia gibt es diesen Bereich VAR nicht. Ich würde am liebsten auch über einen Eingang am FB die länge des Arrays bestimmen, ist das möglich?

@ Harald kannst du mir sagen welchen unterschied dein Code zu dem von Christmisspo macht? Würde mich sehr interessieren du hast auch die Funktion MOD gebnutzt. Wofür ist das?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Die MOD Anweisung von Harald ist Quasi das Zurücksetzen des Zählers.

Was ich gepostet habe ist eine SCL Quelle aus Tia V13SP1 generiert. Anlegen müsstest du die Variablen bei "Static", da diese über den Zyklus hinaus gespeichert werden müssen.

Und ja, ich Speicher das Array in dem Instanz_DB. Kann natürlich auch extern erfolgen, aber so hat man die Möglichkeit Identischen Code mehrfach zu verwenden, ohne immer neue DBs anlegen zu müssen (ich hab ja keine Ahnung ob das nur 1 mal verwendet werden soll oder 50 mal).

EDIT: noch mal Kurz zur MOD-Funktion:
MOD gibt den Restwert einer Division. Dieser Restwert wird im Beispiel von Harald in der Ursprungsvariable gespeichert.
In diesem Fall siehts so aus (Ergebnise exemplarisch):

0 MOD 50 = 0 Rest 0
1 MOD 50 = 0 Rest 1
2 MOD 50 = 0 Rest 2
3 MOD 50 = 0 Rest 3
...
50 MOD 50 = 1 Rest 0 => Ergebnisvariable wird auf 0 zurückgesetzt.

War das verständlich?
 
Zuletzt bearbeitet:
@Credofire Code nochmal etwas optimiert/korrigiert:
Code:
#Ergebnis:=0;
FOR #Zähler:=0 TO 9 DO
       #Ergebnis := Ergebnis + Array[#Zähler];
       IF #Array[#Zähler]=0 THEN
            #Ergebnis := #Ergebnis / #Zähler;
            EXIT;
       ELSE IF #Zähler = 9 THEN
            #Ergebnis := #Ergebnis / #Zähler + 1;
       END_IF
END_FOR;

Spart eine zweite Zählschleife, und das Zwischenspeichern der Variablen ;-) (und Zykluszeit)

EDIT: Mal auf 10 Werte korrigiert, 0-10 sind 11 Werte
 
Zuletzt bearbeitet:
@ Christmispoo

Absolut verständlich^^. Also wie das Modolu in C++.

Genau so sieht es aus ich möchte das prinzipiel genau so wie du es gerade beschrieben hast. Einen Fertigen FB verwenden und ihn so oft wie möglich einsetzen.
Wie kann ich das machen dass mein FB einen Eingang hat mit dem ich die Länge des Arrays festlegen kann?

Also später will ich für jede Messwert eingang ein FB verwenden und in dem Instanz_DB soll dann die werte abgelegt werden so das ich nicht immer ein DB erstellen muss.

Das mit den zurücksetzen habe ich hinbekommen und funktioniert auch super. Danke sehr!!!!
Code:
IF #Reset = 1 THEN  //Zähler und Ausgang werden zurückgesetzt
    #Zähler := 0;
    "Temp_1 Fertig" := 0;
END_IF;

IF #Enable AND (#Taktmerker XOR #Takt) AND (#Zähler < #Messwertanzahl) THEN
    #Messwert[#Zähler] := #"Analog in";
    #Zähler := #Zähler + 1;
    #Taktmerker := #Takt;
END_IF;

IF (#Zähler = #Messwertanzahl) THEN
    #Out := 1; // Ausgang Out auf 1 wenn Zähler voll ist
    
END_IF;

#Taktmerker := #Takt;

hab das ganze jetzt bissi umgeändert.
Jetzt müsste nur noch der Array von aussen änderbar sein. Sowas wie
Code:
#Messwert[X];
und X ist der Wert der von aussen übergeben wird, das geht wohl nicht :S.
 
Zuletzt bearbeitet:
Zurück
Oben