Hallo Leute,
ich arbeite gerade an einer SPS-Steuerung. Der gesamte Ablauf wird in C-Sharp programmiert. Die Kommunikation mit der SPS ist über eine eigene Bibliothek realisiert.
Der Ablauf ist folgendermaßen:
Alle 15ms werden nacheinander die folgenden Methoden aufgerufen:
Die SPS-Ein-und Ausgänge sind jeweils in einer Struktur hinterlegt.
Bisher wurde die Methode "Bearbeite" mit einer switch/case-Anweisung realisiert und nach einem "case-Block" wurde die "switch-Variable" verändert. Beim nächsten Durchgang (nach 15ms) wurde dann erneut die switch/case-Anweisung mit der neuen Variablen aufgerufen und etwas anderes wurde durchgeführt.
int a=0;
public void Bearbeiten(ref struct SPSein, ref struct SPSaus)
{
switch (a)
Case 0:
//Mache was beim ersten Aufruf
a=1;
break;
Case 1:
//Mache was beim nächsten Aufruf
....
Hierbei verliert man aber irgendwann schnell den Überblick und auch die Durchlaufzeit wird immens hoch. Daher wollte ich nun mehrere Blöcke zusammenfassen.
Jetzt stehe ich aber vor dem folgenden Problem:
Der Methode Bearbeiten übergebe ich den Strukturen der SPS mit ref.
public void Bearbeiten(ref struct SPSein, ref struct SPSaus)
{
SPSaus.motoran = 1
// Warte kurz
if (SPSein.motorläuft==1)
{
//hier kommt man beim ersten Aufruf nicht rein
}
}
Scheinbar werden die Variablen in der struct erst nach dem Verlassen der Methode geändert und nicht sofort, oder irre ich mich da.
Gibt es eine andere Möglichkeit dies zu realisieren?
Vielen Dank für eure Hilfe.
Doch, die Werte werden sofort geändert; ist schließlich eine Referenz auf das gemeinsame Objekt/Instanz.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo esparki,
wenn du in deiner Methode "wartest", blockierst du damit vermutlich auch den Aufrufer, der dadurch nicht auf deine Aktion reagieren kann.
Evt. hilfts wenn du die Methode Asynchron gestaltest.
Lg, XXX
Die Werte sind ab dem Zeitpunkt geändert wo man sie setzt.
Kannst du nicht Objekte verwenden? Da gings ohne ref.
Wird der Wert der 1 sein soll tatsächlich vorher gesetzt? Du weißt schon dass du SPSaus.motoran = 1 setzt und im darauf folgenden if etwas ganz anderes abfragst?
Einen sonstigen Zusammenhang sehe ich in deinem Beispiel nicht. Was soll es wie zeigen?
Hallo esparki,
warum nicht einfach in die MSDN Doku schauen? (Bitte beachte [Hinweis] Wie poste ich richtig? Punkt 1.1 und [Hinweis] Bitte schau in die SDK-/MSDN-Doku.
Das ref-Schlüsselwort bewirkt, dass ein Argument durch einen Verweis und nicht durch seinen Wert übergeben wird. Die Übergabe per Referenz bewirkt, dass jede Änderung des Parameters innerhalb der Methode die zugrunde liegende Argumentvariable der aufrufenden Methode betrifft. Der Wert eines Verweisparameters ist immer der selbe wie der Wert der zugrunde liegenden Argumentvariable.
Außerdem kann man es leicht selbst ausprobieren (öffentliche Felder sollte man regulär nicht verwenden, aber für einen Test geht das in Ordnung):
using System;
static class App
{
private static A a = new A (5);
public static void Main ()
{
M (ref a.i);
}
private static void M (ref int i)
{
Console.WriteLine (i);
Console.WriteLine (a.i);
i = 20;
Console.WriteLine (i);
Console.WriteLine (a.i);
}
}
public class A
{
public int i;
public A (int i)
{
this.i = i;
}
}
Ausgabe:
5
5
20
20
Der Wert der per ref übergebenen Variable ändert sich also direkt und bevor die Methode verlassen wird.
herbivore
Wenn ich Deinen Code so anschaue, dann halte ich es für wichtiger, daß Du den Struct beibehälst, aber einfach sprechende Variablen wählst oder zum Beispiel neben den ints auch boolsche Variablen oder enums verwendest.
SPSein.motorläuft==1
Switch statements werden sehr schnell abgearbeitet.
Switch statements werden sehr schnell abgearbeitet.
Wir sollten solche Aussagen mit Sorgfalt genießen; denn switch Statements sind lange nicht soo schnell wie viele denken. Sie sind nur schneller, wenn der Compiler daraus eine Jumptable generieren kann.
Siehe auch if vs switch performance comparison
Wichtiger ist in diesem Fall der lesbarere Code.
Bitte das hier aber nicht diskutieren; zur Not ein extra Thread eröffnen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
@esparki_
Sorry, aber wenn ich "ref struct " sehe, dann bekomme ich Bauchschmerzen.
Wozu meinst du soeinen vollkommen schrecklichen Parameter zu benötigen?
Wir sind hier nicht mehr bei C wo man soetwas brauchte.
Wird wahrscheinlich daran liegen, dass die 99,9% der Elemente bei SPS eben structs
sind und sich die Entwickler daher an diese Art und Weise bei eigenen Dingen gewöhnen.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Vielen Dank erstmal für die rege Unterstützung
@FZelle: Ich habe den Quellcode von meinem Vorgänger bekommen und arbeite darauf weiter. Aber wie Abt schon richtig vermutet, ist die Bibliothek der SPS schon mit struct aufgebaut.
@weismat und chilic Der Code war nur ein kurz zusammengefasstes Beispiel. Mit dem Ausgang schalte ich den Motor ein und mit dem Eingang frage ich bspw. einen Drehgeber-Sensor ab, der mir sagt, das mein Motor auch wirklich dreht. Die eigentliche Abfrage läuft Byteweise ab (Ein 8fach SPS-Eingangsmodul = 1 Byte), sprich vorher werden die Bytes auf Bits und dann in verständliche Variablen umgewandelt. Da findet dann auch die Umwandlung in bool statt.
@herbivore ich denke mal, so wie die meißten habe ich vor meinem Beitrag auch die MSDN durchforstet und vereinzelt Testcode geschrieben. Leider bin ich nicht auf das passende Ergebnis gekommen.
@xxxprod Genau das habe ich nun gemacht. Ich habe nun die Ein-Ausgabe der SPS und die eigentliche Bearbeitung in zwei verschiedene Threads gepackt. In dem Thread der SPS wird die Input-struct immer mit den aktuellen Daten der SPS beschrieben und die Daten in der Output-struct immer in die SPS-geschrieben. Während die Bearbeitung parallel läuft und auf beide struct zugreift. Um die Zeitverzögerung zwischen dem schreiben in die SPS und ein dafür logisches Eingangssignal zu erhalten verwende ich kurze Schleifen. Hierdurch kann ich auch ein eventuelles hängen in der Anlage abgreifen. Innerhalb der Schleife frage ich auch ab, ob der gewünschte Zsutand schon erreicht ist und springe dann raus um unnötige Wartezeit zu minimieren.
clTimer_TimeOut.Set_ms(150);
while (!clTimer_TimeOut.Abgelaufen())
{
if(/*logischer Zustand schon erreicht?*/)
break;
}
Vielen Dank noch einmal für eure schnelle Hilfe.
Aber wie Abt schon richtig vermutet, ist die Bibliothek der SPS schon mit struct aufgebaut.
Was nicht bedeutet das man diesen .. weitermachen muss.
Benutze diese Structs als DTO und benutze ansonsten Klassen, dann musst du diese und viele andere Klimzüge nicht machen.
Oder nimm gleich die OPCDaAuto.dll - dann brauchst Du garkeine eigene, selbst gebastelte Bibliothek, bei der Du mit irgendwelchen Schleifen auf irgendwas warten musst.