Array mit REAL Daten füllen

Meutrich

Level-1
Beiträge
2
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,
bin noch recht unerfahren mit dem programmieren auf Codesys. Mein Problem, ich wollt ein Array erstellen und es mit Analogwerten füllen, diese sind in REAL. Das Auswerten der Analogwerte hab ich schon hinbekommen jetzt wollt ich diese Werte in ein Array reinschreiben. Die Werte sollen nicht zeitbasiert ins Arrayfeld reingeschrieben werden sondern nach einem bestimmten Ablauf, also nach einer bestimmten positiven Flanke. Wenns geht soll es nachdem ein Wert übertragen worden ist, der Index des Arrays automatisch einen höher gehen. Wenn dann wieder die positive Flanke TRUE gibt soll der neue Wert eingeschrieben werden. Ich bedanke mich schon mal für die Antworten;).
Hat da irgendwer eine Idee wie man das lösen könnte?

Gruß,
Meutrich
 
Hallo Meutrich,

eigentlich hast du ja schon geschrieben, wie man das macht.
Zu beachten ist dabei, dass das Array fest definiert ist und wenn dein Index am Ende angekommen ist, muss er wieder zurückgesetzt werden. Andernfalls schreibst du in Speicherbereiche, die anderen Daten zugeordnet sein können und das führt im Normalfall zu unerwünschten Auswirkungen. Im günstigsten Fall geht die SPS in Stop.

Code:
Var
a_Daten :Array[0..99] of Real;
Idx :Int :=0;
Trigger :R_Trig;
End_Var

Trigger(CLK := deinEreignis);

If Trigger.Q Then
  a_Daten[Idx] := deinAnalogwert;
  Idx := Idx +1;
 
  If Idx > 99 Then 
    Idx := 0;
  End_IF
End_IF
 
Modulo
Da hätt ich auch mal drauf kommen müssen. Ist echt elegant. :eek:

@Harald
das mit der Prüfung vorher hattest Du bei mir auch schonmal bemängelt. Damit ich es auch verstehe sei eine Frage erlaubt:

Die Prüfung findet nach dem Incrementieren und vor der nächsten Verwendung statt. Ist doch eher eine Frage der Disziplin, falls idx mehrfach verwendet würde - nicht oder?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
@Meutrich: Ab CoDeSys 3.5 kannst du für Methoden, Funktionen und Funktionsblöcke Arrays mit variabler Länge als VAR_IN_OUT deklarieren. "arr : array
[*] of int;" zum Beispiel. Falls du alte Daten nicht überschreiben willst...

(Ist "neu" seit der dritten Version der IEC 61131-3 die 2013 veröffentlicht wurde. http://www.plcopen.org/pages/whats_new/tc1/status.htm)
 
Zuletzt bearbeitet:
@Harald
das mit der Prüfung vorher hattest Du bei mir auch schonmal bemängelt. Damit ich es auch verstehe sei eine Frage erlaubt:

Die Prüfung findet nach dem Incrementieren und vor der nächsten Verwendung statt. Ist doch eher eine Frage der Disziplin, falls idx mehrfach verwendet würde - nicht oder?
Der Programmcode initialisiert Idx mit 0 und weißt bei irgendeinem Durchlauf mal Idx einen geprüften Wert zu. Da die Variable Idx aber auch von anderen Programmteilen oder über Kommunikation oder über Programm-Change oder durch Steuern von Programmierern änderbar ist, kann sich der Programmcode nicht darauf verlassen, daß bei einer Verwendung von Idx noch der Wert von einem früheren Zyklus oder überhaupt ein zulässiger Wert drinsteht.

Merke: "Weil SPS so schnell und so häufig den Programmcode wiederholen, wird alles was möglich ist auch irgendwann passieren."
Wir wollen auf jeden Fall stabile und robuste Programme für die Steuerung von oft exorbitant teuren Anlagen/Prozessen. Da kann man nicht vermitteln, daß die SPS mal eben in STOP gegangen ist nur weil der Programmierer keine Lust zum eintippen der paar Zeilen Prüfcode hatte.

Harald
 
Merke: "Weil SPS so schnell und so häufig den Programmcode wiederholen, wird alles was möglich ist auch irgendwann passieren."
Wir wollen auf jeden Fall stabile und robuste Programme für die Steuerung von oft exorbitant teuren Anlagen/Prozessen. Da kann man nicht vermitteln, daß die SPS mal eben in STOP gegangen ist nur weil der Programmierer keine Lust zum eintippen der paar Zeilen Prüfcode hatte.

Ich komm grad nicht ganz nach. Warum muss ich genau was mit der Variable machen? Kann ich mich nicht darauf verlassen, dass wenn ich einer Variable den Wert "5" zuweise und sie im nächsten durchlauf um 1 incrementiere, die Variable dann 6 ist? Oder geht es darum wenn ich mehrere Bausteine habe und diese Bausteine nutzen alle eine lokale Variable "a", dass der Wert von "a" des ersten Bausteins aus versehen auf die Variable "a" des zweiten Bausteins übertragen werden könnte, obwohl es unterschiedliche Bausteine mit unterschiedlichen Datenblöcken sind?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Warum muss ich genau was mit der Variable machen? Kann ich mich nicht darauf verlassen, dass wenn ich einer Variable den Wert "5" zuweise und sie im nächsten durchlauf um 1 incrementiere, die Variable dann 6 ist?
Genau so - das Programmstück kann sich nicht darauf verlassen, weil es nicht wissen kann, was außerhalb des Durchlaufs mit der Variable passiert ist. Deshalb ist VOR einer Verwendung zu überprüfen, ob die Variable (noch) einen zulässigen Wert enthält. Es gibt keine "private" Static-Variablen die gegen Schreibzugriffe von außen sicher geschützt sind.

Harald
 
Genau so - das Programmstück kann sich nicht darauf verlassen, weil es nicht wissen kann, was außerhalb des Durchlaufs mit der Variable passiert ist. Deshalb ist VOR einer Verwendung zu überprüfen, ob die Variable (noch) einen zulässigen Wert enthält. Es gibt keine "private" Static-Variablen die gegen Schreibzugriffe von außen sicher geschützt sind.

Aber wie prüfe ich dann, ob die Variable nun den Wert 6 enthält? Dazu bräuchte ich ja eine zweite variable, welche auch um 1 inkrementiert wird. Oder prüfe ich einfach, ob der Wert der Variable in einem gewissen Bereich ist? Und dann müsste ich ja JEDE Variable nochmals überprüfen, ob sie wirklich den neuen Wert angenommen hat...

Und warum höre ich das von dir zum ersten Mal? Man sollte doch meinen, dass irgendein Techniker (von Wago, die haben sich auch schon meine Programme angeschaut) oder ein Prüfungsexperte (als ich meinen Abschluss gemacht hatte und denen ein riesen Programm vorgestellt hatte) oder mein Lehrer (damals in der Ausbildung an der Berufsschule) mir das mal sagen würde...
 
Zuletzt bearbeitet:
Ich kann dem auch nicht so recht folgen.
Wenn ich mich auf den Wert einer Variablen von einem Zyklus zum nächsten nicht verlassen kann, ist weit mehr im Argen, als dass 2 Zeilen Code es auffangen könnten.
Wer im laufenden Betrieb Werte manipuliert, die nicht vom Bediener manipuliert werden sollten, macht das meist aus einem bestimmten Grund und sollte eigentlich wissen, was er tut.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Aber wie prüfe ich dann, ob die Variable nun den Wert 6 enthält?
Es soll nicht geprüft werden, ob der Wert noch 6 ist, sondern lediglich ob der Wert (noch) im zulässigen Bereich 0..99 ist.

Es geht nicht darum zu erkennen, ob der Wert verändert wurde, sondern darum Folgeschäden zu verhindern. Wenn z.B. ein Produktzähler verändert wird, dann ist das in der Regel nicht so tragisch, da ist halt der Wert falsch.
Wenn aber ein gemerkter Pointer oder Index für indirekte Adressierung sich verändert und das nicht bemerkt wird, dann schreibt das Programm unkontrolliert im Datenspeicher umher und verändert ungewollt irgendwelche Variablen mit unvorhersehbaren Folgen ...

Wenn man eine Straße überqueren will, dann muß man unmittelbar vorher nach links und rechts schauen, ob das Überqueren gefahrlos möglich ist. Da kann man nicht sagen "Ich habe gestern schon nach links geschaut und mir aufgeschrieben, daß die Straße frei war".


Und warum höre ich das von dir zum ersten Mal? Man sollte doch meinen, dass irgendein Techniker (von Wago, die haben sich auch schon meine Programme angeschaut) oder ein Prüfungsexperte (als ich meinen Abschluss gemacht hatte und denen ein riesen Programm vorgestellt hatte) oder mein Lehrer (damals in der Ausbildung an der Berufsschule) mir das mal sagen würde...

"Denn sie wissen nicht was sie tun."
Und "Du bist für Dein Programm verantworlich." und nicht irgendwelche Lektoren, die mit möglichst wenig Aufwand möglichst viel verdienen wollen, und Dir auch nicht in einer Woche 10 Jahre Erfahrung vermitteln können, wie man ein robustes Programm schreibt.

Seit es Hochsprachen wie ST oder SCL gibt, fühlen sich viele Leute in der Lage SPS-Programme zu schreiben, ohne genügend Wissen zu haben wie die SPS funktioniert, und ohne Ahnung welche Gefahren von stümperhaften "Vorführ"-Programmen ausgehen, die nur dann vielleicht richtig funktionieren, wenn nichts unvorhergesehenes passiert. Ein SPS-Programm muß aber auch bei unvorhergesehenen Bedingungen/Beeinträchtigungen richtig/sinnvoll funktionieren und die Anlagen/den Prozess steuern und schützen. Deshalb überträgt man ja Steuerungsaufgaben an SPS um Fehler (z.B. durch Menschen) zu verhindern. Wenn aber der Programmier-Mensch das Steuerungsprogramm fehlerhaft oder ungenau programmiert, dann wird auch die SPS nur fehlerhaft oder ungenau funktionieren.


Wenn ich mich auf den Wert einer Variablen von einem Zyklus zum nächsten nicht verlassen kann, ist weit mehr im Argen, als dass 2 Zeilen Code es auffangen könnten.
Wer im laufenden Betrieb Werte manipuliert, die nicht vom Bediener manipuliert werden sollten, macht das meist aus einem bestimmten Grund und sollte eigentlich wissen, was er tut.
Willst Du Dich rausreden "Mein Programm hat (leicht vermeidbare) Fehlfunktionen, weil die SPS nicht genug gegen Manipulationen und Dummheiten und Programmierfehler und andere Zufälle geschützt wird. Jemand anders ist schuld!"?
Heutzutage wo alle Steuerungen vernetzt sind kann sich das Programm nicht blind darauf verlassen, daß eine Variable noch den Wert von einer früheren Zuweisung hat. Selbst wenn der Programmierer ein perfekt fehlerfreies Programm programmiert hat. Die realen Einflußmöglichkeiten von außerhalb sind zu vielfältig.

Harald
 
Kannst du mir ein Programmbeispiel geben? Ich würde gerne sehen, wie du eine solche Prüfung realisierst und in dein Programm einbaust.

Vielen Dank schon Mal. Ich hab das Gefühl, das könnte später noch nützlich werden. Und ich seh mich ja als einigermassen fähigen Programmierer, aber ich lerne immer gerne was neues dazu. Da profitiere ich gerne von deiner Erfahrung. ;)
 
Wie wäre es denn mit:
Code:
Var
a_Daten :Array[0..99] of Real;
Idx :Int :=0;
Trigger :R_Trig;
End_Var

Trigger(CLK := deinEreignis);

If Trigger.Q and (Idx >= 0 and Idx < 100) Then
  a_Daten[Idx] := deinAnalogwert;
  Idx := Idx +1;
 
  If Idx > 99 Then 
    Idx := 0;
  End_IF
End_IF
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Index/Pointer prüfen vor Verwendung

Kannst du mir ein Programmbeispiel geben? Ich würde gerne sehen, wie du eine solche Prüfung realisierst und in dein Programm einbaust.
Man könnte den Wert zuerst prüfen und falls unzulässig dann die Verwendung abbrechen wie hier:
https://www.sps-forum.de/codesys-un...sung-nach-excel-exportieren-2.html#post671825

Ganz allgemein auf Wert innerhalb zulässiger Grenzen prüfen und notfalls einen Ersatz/Initialwert zuweisen:
Code:
IF Idx > 99 OR Idx < 1 THEN  [COLOR="#008000"]//prüfen[/COLOR]
  Idx := 1;                  [COLOR="#008000"]//ggf korrigieren[/COLOR]
END_IF

a_Daten[Idx] := irgendwas;   [COLOR="#008000"]//hier darf Idx nur 1..99 sein![/COLOR]

Idx := Idx + 1;              [COLOR="#008000"]//Idx auf nächsten Eintrag weiterstellen[/COLOR]
IF Idx > 99 THEN             [COLOR="#008000"]//prüfen[/COLOR]
  Idx := 1;                  [COLOR="#008000"]//und ggf korrigieren[/COLOR]
END_IF
Für das prüfen/korrigieren kann man evtl. auch eine LIMIT-Funktion verwenden.

Wenn der kleinste zulässige Wert 0 ist und nur sichergestellt werden muß, daß Idx (irgend-)einen zulässigen Wert hat dann bietet sich die MOD-Anweisung an (Idx muß ein unsigned-Datentyp sein):
Code:
Idx := Idx MOD 100;                 [COLOR="#008000"]//prüfen/korrigieren[/COLOR]

a_Daten[Idx] := irgendwas;          [COLOR="#008000"]//hier darf Idx nur 0..99 sein![/COLOR]

Idx := (Idx + 1) MOD 100;           [COLOR="#008000"]//Idx auf nächsten Eintrag weiterstellen[/COLOR]

[COLOR="#008000"]//--- oder -----------------------------------------------------------------[/COLOR]
a_Daten[Idx MOD 100] := irgendwas;  [COLOR="#008000"]//hier darf Idx nur 0..99 sein![/COLOR]

Idx := (Idx + 1) MOD 100;           [COLOR="#008000"]//Idx auf nächsten Eintrag weiterstellen[/COLOR]

Vielleicht kann man das Programm auch so umstellen, daß nur einmal geprüft werden muß, wie z.B. bei diesem Ringpuffer-Logbuch. Da wird zuerst der Index erhöht und geprüft/korrigiert und danach verwendet.
Code:
//Schreibzeiger auf nächsten Eintrag im Logbuch-Array stellen
      L     "Logbuch".LastIndex;     //Index des zuletzt geschriebenen Eintrags
      +     1;                       //nächster Eintrag
      L     100;                     //Anzahl Einträge im Logbuch-Array
      MOD   ;                        //Ringpuffer: Array-Ende mit Array-Anfang verbinden
      T     "Logbuch".LastIndex;     //neuer Wert des Schreibzeigers merken (0..99)

Wenn man ganz sicher gehen will, daß ein Wert nicht zwischen Prüfung/Korrektur und Verwendung durch andere Tasks (z.B. HMI) verändert wird, dann muß man den Wert auf einen von außen unzugänglichen Speicher umkopieren, z.B. in lokale/TEMP-Variablen im Stack (gibt es sowas in Codesys/Twincat?):
Code:
temp_Idx := Idx MOD 100;         [COLOR="#008000"]//umkopieren mit prüfen/korrigieren[/COLOR]

a_Daten[temp_Idx] := irgendwas;  [COLOR="#008000"]//hier darf temp_Idx nur 0..99 sein![/COLOR]

Idx := (temp_Idx + 1) MOD 100;   [COLOR="#008000"]//Idx auf nächsten Eintrag weiterstellen[/COLOR]

Harald
 
Ok, es geht immernoch auf den gesicherten Zugriff auf das Array.

Code:
Idx := Idx MOD 100;                 [COLOR=#008000]//prüfen/korrigieren[/COLOR]

a_Daten[Idx] := irgendwas;          [COLOR=#008000]//hier darf Idx nur 0..99 sein![/COLOR]

Idx := (Idx + 1) MOD 100;           [COLOR=#008000]//Idx auf nächsten Eintrag weiterstellen[/COLOR]

würde ich befürworten, wobei ich dann auch auf
Code:
Idx := Idx MOD 100;                 [COLOR=#008000]//prüfen/korrigieren[/COLOR]
a_Daten[Idx] := irgendwas;          [COLOR=#008000]//hier darf Idx nur 0..99 sein![/COLOR]
Idx := Idx + 1;                    [COLOR=#008000]//Idx auf nächsten Eintrag weiterstellen[/COLOR]
einkürzen würde da, Idx vor der nächsten Verwendung ohnehin wieder in den gültigen Bereich gezogen wird (ich habe von Steuerungen gehört, da sollte man Rechenoperationen sparen um Zykluszeiten klein zu halten :rolleyes: )
 
wobei ich dann auch auf
Code:
Idx := Idx MOD 100;                 [COLOR=#008000]//prüfen/korrigieren[/COLOR]
a_Daten[Idx] := irgendwas;          [COLOR=#008000]//hier darf Idx nur 0..99 sein![/COLOR]
Idx := Idx + 1;                    [COLOR=#008000]//Idx auf nächsten Eintrag weiterstellen[/COLOR]
einkürzen würde da, Idx vor der nächsten Verwendung ohnehin wieder in den gültigen Bereich gezogen wird
Das würde ich nicht machen, weil dann irgendwann der ungültige Wert 100 in die Variable geschrieben wird. (Wird die vielleicht noch woanders verwendet/angezeigt??) Das eine eingesparte "MOD 100" macht das Programm nicht wirklich schneller. Da verplempert der Programmierer woanders unüberlegt noch ganz viel mehr Rechenzeit und Programmspeicher. (am liebsten mit IF-Konstrukten ;))

ich habe von Steuerungen gehört, da sollte man Rechenoperationen sparen um Zykluszeiten klein zu halten :rolleyes: )
Und ich habe von ST-Programmierern gehört, die machen sich überhaupt keinen Kopf um die Geschwindigkeit und Effizienz ihrer Programme. Die wollen immer nur Arbeit beim eintippen des Codes sparen und am liebsten alles in Schleifen verpacken, egal ob das Programm dann dreimal so langsam wird ;)

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Und warum höre ich das von dir zum ersten Mal? Man sollte doch meinen, dass irgendein Techniker (von Wago, die haben sich auch schon meine Programme angeschaut) oder ein Prüfungsexperte (als ich meinen Abschluss gemacht hatte und denen ein riesen Programm vorgestellt hatte) oder mein Lehrer (damals in der Ausbildung an der Berufsschule) mir das mal sagen würde...
Ich will keinen Prüfungsexperten, keinen Berufschullehrer, keinen Ausbilder u.s.w. diskriminieren, aber selbst wenn sie mal ein Praktikum machen mussten und den Umgang mit Schraubstock und Feile von der PraxisSeite kennengelernt haben ... nun ja, ob auf äusserste Vorsicht gepolt oder nicht, sie haben schon Probleme, die Grundlagen in der zur Verfügung stehenden Zeit zu vermitteln ...
Zum Glück ist es nicht verboten, auch nach der Ausbildung noch das eine oder andere dazuzulernen ;o)

Ich habe auch schon erlebt, dass Kollegen überlegt haben (immerhin!) "der Fehler wird, wenn überhaupt, alle JubelJahre mal auftreten" und daraufhin beschlossen, nichts für den Fehlerfall vorzusehen.
In einem Fall habe ich gewarnt, dass der Fehler nicht die seltene Ausnahme, sondern der Regelfall sein wird, wurde aber erst ernst genommen, als sich meine Befürchtung in der Praxis bestätigte.
In anderen Fällen habe ich sogar die Umsetzung von "SuperIdeen" verweigert - aus guten Gründen, die ich auch angegeben habe. Da es - wie so oft - darum ging, Abläufe schneller zu gestalten, wurde die Aufgabe einem anderen Kollegen auf's Auge gedrückt und ... als es dann gerummst hat, liessen sich die HinterrücksVersuche nicht mehr verheimlichen.

Man kann gar nicht vorsichtig genug sein. Da gebe ich Harald vorbehaltlos Recht!
Fehlern aufzulauern, halte ich für enorm wichtig. Aber wie reagiert man auf einen Fehler, den man festgestellt hat?
Das ist zweifellos der schwierige Teil. Vermutlich wurde schon oft allein deshalb am Aufwand für die Feststellung von Fehlern gespart, weil die Entscheidung "wie reagiere ich darauf" eine Entscheidung zwischen Pest und Cholera war.
Wie im hier diskutierten Fall, einen Index, der auf ein Element jenseits eines Arrays zeigt, automatisch zurechtzubiegen, birgt aber auch eine Gefahr in sich: während man sich seines reinen Gewissens erfreut, treten Fehler auf, die aber niemand bemerkt, weil sie durch die eingebaute SelbstHeilung "entschärft" wurden.
Als MinimalLösung schlage ich deshalb vor, eine Protokollierung zu realisieren, die zumindest Auskunft darüber gibt, wie oft der Fall aufgetreten ist, der angeblich nie auftreten kann.
Gruss, Heinileini
 
Gibt es eine möglichkeit sich einen Thread zu "merken"? Ich glaube, diesen Thread werd ich noch n paar mal durchlesen müssen. :p
 
Zurück
Oben