Hallo,
ich muss mit einem Messgerät 2 "Quellen" messen. Dazu schaltet LabVIEW alle 5 Minuten ein Relais um die Quellen abwechselnd durchschalten.
In einem anderen Programm nehme ich die Messwerte auf - da sie vom selben Kanal kommen würden sie zwangsweise in einem Messfile gespeichert werden.
Ich hab mir nun folgende Lösung erarbeitet: Ich definier im Relaisprogramm globale Variablen die je nach Schaltungszustand den Wert true oder false bekommen. Diese globalen Variablen sollen im Messfileprogramm gelesen werden und über die Logik dann die Messscheiber enablen oder disablen.
Von der Theorie her meine ich, dass das klappen müsste jetzt kommt aber das Problem: Lese ich die Variablen im Messfileprogramm aus, kann es sein dass Sie beide true, oder beide fals sind. Was eigentlich nicht sein darf. Zumindest finde ich das.
Hat von euch vielleicht jemand ähnliche Probleme mit gloablen Variablen gehabt?
Zum besseren Verständnis gibts Bilder
[
attachment=21203]
[
attachment=21204]
[
attachment=21205]
' schrieb:Von der Theorie her meine ich, dass das klappen müsste jetzt kommt aber das Problem: Lese ich die Variablen im Messfileprogramm aus, kann es sein dass Sie beide true, oder beide fals sind. Was eigentlich nicht sein darf. Zumindest finde ich das.
Gerade die Theorie sagt hier genau das voraus, was du festgestellt hast!
Du hast hier zwei While-Schleifen, also zwei Prozessor-Thraeds. Du musst nun wissen, dass beide Thraeds unabhängig laufen. Aber: Sie laufen tatsächlich nicht gleichzeitig, sondern nur hintereinander respektive verschachtelt (Timesharing) (das mit dem Dualcore lass ich jetzt mal außen vor). Der eine Thread kann den anderen Thread jederzeit unterbrechen - und zwar an beliebigen Stellen. Und jetzt stell dir mal vor, die Unterbrechung findet genau zu dem Zeitpunkt statt, zu dem die eine Variable mit true beschrieben wird. Dann sind beide Variablen plötzlich true.
Zitat:Hat von euch vielleicht jemand ähnliche Probleme mit gloablen Variablen gehabt?
Das ist also kein Problem, sondern eher ein Feature (RaceCondition).
Du kannst folgendes machen. Verwende keine zwei Boolschen Variablen, sondern eine einzige Zahl. Bit 0 der Zahl entspricht dann der ersten Boolschen Variablen, B1 der zweiten.
top, ich weiß zwar nich ganz was du mit bit 1 und zwei machst aber je nachdem ob ich der var im jeweiligen timshift die zahl 0 oder 1 zuweise und in meinem messfile ein vergleich mache - ja dann funktioniert das ganz wunderbar! cool!
Danke
zu früh gefreut er baut mir doch wieder fehler ein - kannst du mir vielleicht genauer erklären was du mit bit 0 und bit 1 der zahl meinst?
Viele Grüße
Chris
' schrieb:er baut mir doch wieder fehler ein
Was für Fehler? Es msus ja nicht zwangsläufig der gleiche sein.
Zitat:kannst du mir vielleicht genauer erklären was du mit bit 0 und bit 1 der zahl meinst?
Der Wert von B0 (= erstes Bit. Dass du weißt was ein Bit ist und wieviele Bits ein I32 hat, setzte ich mal voraus) entstricht der Globalen Variablen "glob1". Der Wert von B1 entspricht dann "glob2". Ausrechnen kann man das wie folgt: Glob1 = ((Zahl and 1)<>0); Glob2 = ((Zahl and 2)<>0);
[*grübel*]
Viel, viel besser gefiehle mir allerdings ein Enumerator! Guckst du in der Hilfe. Ein Enumerator ist zwar eine Zahl, die kann man aber als lesbaren Text darstellen. Da vergibst du einfach die Werte "Tue Glob1" und "Tue Glob2" - und schon muss du dich um keine Bits mehr kümmern. - Dann kannst du sogar ganz einfach auf "Tue Glob3" und "Tue Glob1+Glob2" erweitern.
' schrieb:Von der Theorie her meine ich, dass das klappen müsste jetzt kommt aber das Problem: Lese ich die Variablen im Messfileprogramm aus, kann es sein dass Sie beide true, oder beide fals sind. Was eigentlich nicht sein darf. Zumindest finde ich das.
Da ist mir doch übers Wochenende eingefallen, dass dein Code ja noch viel kritischer ist, als ich bei meinem ersten Posting hier hab durchblicken lassen.
Du musst das Prinzip des Datenflusses beachten. "Datenfluß" ist, wenn die einzelnen Operationen hintereinander, d.h sequenziell, abgearbeiten werden. Normalerweise wird ein "Datenfluß" erzeugt durch z.B. den Errorcluster oder durch andere Datenleitungen, die von VI zu VI gehen. Eine weitere Möglichkeit ist, die Sequenzierung durch den sog. Sequenzrahmen zu erzeugen.
Was das jetzt mit deinem Code zu tun hat? Die drei Operationen "30.000 Sekunden warten", "Glob1 setzen", "Glob2 setzen" sind nicht sequenziert, d.h. man weiß nicht, in welcher Reihenfolge die einzelnen Befehle abgearbeitet werden. Du denkst vielleicht, die hier aufgeführet Reihenfolge wird gemacht. Das stimmt aber nicht. Es kann auch sein, dass die Reihenfolge "Glob1 setzen", "Warten", "Glob2 setzen" gemacht wird. Dann hat - guckst du deinen Code - für die Dauer von "Warten" Glob1 den selben Wert wie Glob2.
' schrieb:Was das jetzt mit deinem Code zu tun hat? Die drei Operationen "30.000 Sekunden warten", "Glob1 setzen", "Glob2 setzen" sind nicht sequenziert, d.h. man weiß nicht, in welcher Reihenfolge die einzelnen Befehle abgearbeitet werden. Du denkst vielleicht, die hier aufgeführet Reihenfolge wird gemacht. Das stimmt aber nicht. Es kann auch sein, dass die Reihenfolge "Glob1 setzen", "Warten", "Glob2 setzen" gemacht wird. Dann hat - guckst du deinen Code - für die Dauer von "Warten" Glob1 den selben Wert wie Glob2.
Kann man z.B. so lösen:
[
attachment=21244]
Bleibt noch die Frage, zuerst Warten oder zuerst golbale Variablen setzen und dann warten. Aber das bekommst du bestimmt hin.
Gruß SeBa
Hallo SeBa
' schrieb:Kann man z.B. so lösen:
Für Datenfluß und die daraus resultierenden Gegebenheiten (also z.B. RaceConditions etc) ist es egal, ob man die globalen Variablen mit einzelnen Konstanten beschreibt oder ob man eine Konstante invertiert. Im Fehlerfall unterscheiden sich beide nicht.
Abhilfe auch für den letzten aller Fehlerfälle schaft nur eine möglicherweise notwendige Sequenzierung und eine entsprechend ausfallsichere Programmiervariante. Wenn die beiden Boolschen Variablen aufgrund dessen, was sie tun sollen, grundsätzlich gegenseitig verriegelt sind - dann kann man das so nicht machen. Entweder man muss
eine Variable nehmen anstelle von zwei. Eine Variable (z.B. Enumerator) hat auch nur einen Wert und der ist immer gültig. Zwei Variablen können in Kombination gesehen einen ungültigen Zustand erzeugen.
Will man doch zwei Variablen verwenden, muss man garantieren, dass das Betriebssystem (oder das Runtimesystem von LV) das Beschreiben der beiden Variablen nicht unterbricht. Sowas gibt es auch, aber nicht auf der Ebene, auf der der Programmierer in LV programmiert (auf jeden Fall ist das nicht Sinn der Sache, dem sowas an die Hand zu geben).
' schrieb:Hallo SeBa
Für Datenfluß und die daraus resultierenden Gegebenheiten (also z.B. RaceConditions etc) ist es egal, ob man die globalen Variablen mit einzelnen Konstanten beschreibt oder ob man eine Konstante invertiert. Im Fehlerfall unterscheiden sich beide nicht.
Allse richtig, aber das Haupproblem wurde meines Erachtens noch gar nicht diskutiert. In beiden Schliefen passiert genau alle 30sec nach absoluter Zeit etwas (Metronom). D.h alles was in den beiden Schleifen passiert, ist immer genau gleichzeitig. Da es aber praktisch keine Gleichzeitigkeit gibt, ist es dem Zufall überlassen, in welcher der beiden Schleifen zuerst etwas passiert. Folge: Mal wird die globale Veriable zuerst geschrieben, danach sofort gelesen, mal wird die globle Veriable zuerst gelesen (also erst 30sek nachdem sie zuletzt beschrieben wurde).
Die Struktur ist schlecht bis unbrauchbar.
Eher auf der Höhe der Zeit ist die folgende Struktur. Die beiden Schleifen können auch in verschiedenen VIs sein, ohne daß dann globale Variablen benutzt werden müssen.
[
attachment=21259]
Ein primitive Notlösung wäre die Folgende:
Die Schleife mit dem Express.VI wird so geändert
[
attachment=21261]
Dann werde die globalen Variablen immer 10 ms nachdem sie beschrieben sind gelesen und alles geht seinen Gang.
' schrieb:Hallo SeBa
Für Datenfluß und die daraus resultierenden Gegebenheiten (also z.B. RaceConditions etc) ist es egal, ob man die globalen Variablen mit einzelnen Konstanten beschreibt oder ob man eine Konstante invertiert. Im Fehlerfall unterscheiden sich beide nicht.
(...)
Ok, ich nehm Alles zurück und behaupte das Gegenteil. Man lernt ja gerne was Neues.
Aber dann nur so für mich zum Verständnis...
Im Ausgangsbeispiel gibt es einen Timer und die beiden Variablen die separat beschrieben werden. Das bedeutet es können beliebige Kombinationen der Ausführung vorkommen (z.B. "warten/schreiben1/schreiben2" oder "schreiben2/warten/schreiben1" ect.)
Wenn die beiden Variablen jetzt wie von mir vorgeschlagen verdrahtet werden, dachte ich gibt es nur die Kombinationen "warten/schreiben1+2" oder "schreiben1+2/warten".
Daher hätte ich in einem Sequenzrahmen folgendes gemacht:
1. Seq.: Variablen schreiben
2. Seq.: Warten
3. Seq.: Variablen schreiben
4. Seq.: Warten
und von vorne...
Gru? SeBa
' schrieb:Wenn die beiden Variablen jetzt wie von mir vorgeschlagen verdrahtet werden, dachte ich gibt es nur die Kombinationen "warten/schreiben1+2" oder "schreiben1+2/warten".
Alles das, was sequenziert ist (Paradebespiel: mit ErrorCluster verbunden), gilt als ein Datenfluß. Innerhalb eines expliziten Datenflusses kann es z.B. nie zu ReceConditions kommen und innerhalb eines Datenflusses geht eben alles der Reihe nach - wie eben in einem Fluß aus Wasser auch. Für alle Datenflüsse zusammengenommen wird folgendes definiert: Alle Datenflüsse laufen parallel. Außerdem: ein Datenfluß weiß vom anderen nichts und kann ihn auch nicht manipulieren. Das kommt von der Entkopplung, die automatisch vorhanden ist, wenn zwei Sachen eben nicht in ein und dem selben Datenfluß liegen.
Der Knackpunkt bei deiner Methode ist die Verzweigung! Die Konstante liegt in einem Datenfluß - der sich dann aber teilt: in einen Datenfluß, der zu Glob1 führt, und in einen zweiten Datenfluß, der zum Inverter führt. Dann sind dann aber zwei Datenflüsse - und müssen als parallel abarbeitbar betrachtet werden. Und schon ist es das selbe Problem wie bei Christiann, bei dem es lediglich von vorne herein drei Datenflüsse sind (3.: Warten).
Zitat:Daher hätte ich in einem Sequenzrahmen folgendes gemacht:
Im Prinzip ist das auch richtig so. Weil ein "Datenfluß" existieren soll - und sei es nur, dass er wie bei dir durch einen Sequenzrahmen erzeugt wird. Mit dem Sequenzrahmen wird eben explizit festgelegt, was ohne nur durch Zufall (wie der Kompiler halt gerade übersetzt) nachbar wäre.
In dem speziellen Fall von Christiann ist das Erzeugen eines Datenflusses aber nur ein unwichtiges Problem. Größer sind die beiden anderen Probleme: Zwei Variablen führen zu einem undefinierten Zustand (da kann auch ein Datenfluß nichts dran ändern) und das Verfahren mit den Wartezeiten in beiden SubVIs (siehe Luckis Posting).