Anlage mit C# steuern

Für alle Diskussionen rund um digitale Modellbahntechnik und alles zum Thema Software Modellbahnplanung und Modellbahnsteuerung
leinad

Anlage mit C# steuern

Beitrag von leinad » Sonntag 30. März 2008, 12:33

Ich habe eine Frage und zwar habe ich eine Modellbahn mit einem Märklin Interface. Ich bin gerade dabei ein eigens Programm für die Steuerung dieser Anlage in C# zu schreiben.
Das manuelle wählen der Weichen und Loks funktioniert auch schon ganz gut.
Nun zu meiner Frage weiß jemand von euch wie das mit der Rückmeldung unter C# funktioniert ich habe nämlich bereits einiges versucht. Aber leider hat nichts zum Erfolggeführt.
Würde mich sehr über ein Antwort freuen. Wenn jemand Problem mit der Ansteuerung der Weichen oder Loks hat kann er sich gerne auch bei mir melden ich werde dann versuchen zu helfen.

Benutzeravatar
Flashbanger
Forumane
Beiträge: 366
Registriert: Samstag 29. Juli 2006, 22:57
Kontaktdaten:

Beitrag von Flashbanger » Montag 31. März 2008, 11:05

Wenn du ein Märklin 6050 /6051 hast, dann geht dies so:

entweder du rufst alle rückmelder bis zu einem Modul ab. Dann sendest du

129...159 auf der seriellen Schnittstelle. Wie das unter C# geht weis ich nicht.

Ein beispiel: Du willst bis zum 5. S88 auslesen. Dann musst du

Code: Alles auswählen

129 + 5 - 1
Also 133 Nach dem senden musst du auf empfangen schalten. Du wirst dann 10 Bytes auf der Schnittstelle bekommen.

Das erste Bit des ersten Bytes ist auch der 1. Kontakt am 1. S88. Das 1. Bit im 2. Byte ist der 9. Kontakt im ersten S88. usw. usw.

Die andere Möglichkeit ist das auslesen eines einzelnen Rückmelders.

Dazu musst du die zahlen 192...223 senden. Dann wieder auf Empfang schalten und die Zwei Bytes auslesen.

Gruß Flashbanger
MfG Flashbanger
______________________
CU+6050 + C-Gleis
Software: TC4.7 oder
MBSS v 0.1 beta

:jump:

leinad

Beitrag von leinad » Montag 31. März 2008, 14:16

Danke für die Antwort dies weiß ich aber schon selber. Das eigentliche Problem ist wie es in C# geht.

Benutzeravatar
HaNull
Forumane
Beiträge: 4381
Registriert: Freitag 2. Februar 2007, 01:47
Wohnort: Rhein-Sieg-Kreis

Beitrag von HaNull » Montag 31. März 2008, 15:20

leinad hat geschrieben:Das eigentliche Problem ist wie es in C# geht.
Wieviel weißt Du denn schon?

Ich habe mal F1 gedrückt und "System.IO.Ports Namespace" gefunden.

Und wenn Du bei www.google.de nach "new SerialDataReceivedEventHandler" (einschl. Anführungszeichen) suchen lässt, findest Du auch Beispielcode.

Mit Google nach Beispielen suchen ...

HTH - sonst bitte Frage präzisieren.
████████   Gruß aus NRW
████████   Thomas
████████   Multi-MISTler: 1. Siegburg (RSK) - 2. Köln rrh. - 3. Rheinbreitbach

leinad

Beitrag von leinad » Samstag 5. April 2008, 13:36

Danke für eure Zahlreichen Tipps ich habe es mittlerweile hin bekommen.

Benutzeravatar
Flashbanger
Forumane
Beiträge: 366
Registriert: Samstag 29. Juli 2006, 22:57
Kontaktdaten:

Beitrag von Flashbanger » Samstag 5. April 2008, 20:47

Wäre gut wenn dus mal veröffendlichen würdest.(Am besten mit der Code funktion) aber bitte nur das was nötig ist. Dann können andere User die Lösung suchen und müssen sie nicht erneut erfragen.
MfG Flashbanger
______________________
CU+6050 + C-Gleis
Software: TC4.7 oder
MBSS v 0.1 beta

:jump:

leinad

Beitrag von leinad » Samstag 5. April 2008, 21:15

Wird zum Beispiel durch einen Timer ausgelösst:

public string []C = new string[32];
public string []D = new string [32];
public int anzahl = 2;
public int[] Kontakt = new int[400];//noch nicht der entgültige wert



serialPort1.Open();


serialPort1.Write(new byte[] { (byte)(128 + anzahl) }, 0, 1);
System.Threading.Thread.Sleep(5);
B = Convert.ToString(serialPort1.BytesToRead);
do
{
j++;
textBox3.Text=(Convert.ToString(j));
C[j] = Convert.ToString(serialPort1.ReadByte());
D[j] = Convert.ToString(serialPort1.ReadByte());
Aswerten(j, Convert.ToInt32(C[j]), Convert.ToInt32(D[j]));

} while (j <= anzahl-1);

serialPort1.Close();



public void Auswerten(int rückmeldeModulNummer, int I, int K)
{


int J = 16*(rückmeldeModulNummer -1); //Nummer des Rückmeldemoduls





if (I >= 128)
{
Kontakt[1 + J] = 1;
I = I - 128;

}
else
Kontakt[1 + J] = 0;
if (I >= 64)
{
Kontakt[2 + J] = 1;
I = I - 64;

}
else
Kontakt[2 + J] = 0;
if (I >= 32)
{
Kontakt[3 + J] = 1;
I = I - 32;

}
else
Kontakt[3 + J] = 0;
if (I >= 16)
{
Kontakt[4 + J] = 1;
I = I - 16;

}
else
Kontakt[4 + J] = 0;
if (I >= 8)
{
Kontakt[5 + J] = 1;
I = I - 8;

}
else
Kontakt[5 + J] = 0;
if (I >= 4)
{
Kontakt[6 + J] = 1;
I = I - 4;

}
else
Kontakt[6 + J] = 0;
if (I >= 2)
{
Kontakt[7 + J] = 1;
I = I - 2;

}
else
Kontakt[7 + J] = 0;
if (I >= 1)
{
Kontakt[8 + J] = 1;
I = I - 1;

}
else
Kontakt[8 + J] = 0;


if (K >= 128)
{
Kontakt[9 + J] = 1;
K = K - 128;

}
else
Kontakt[9 + J] = 0;
if (K >= 64)
{
Kontakt[10 + J] = 1;
K = K - 64;

}
else
Kontakt[10 + J] = 0;
if (K >= 32)
{
Kontakt[11 + J] = 1;
K = K - 32;

}
else
Kontakt[11 + J] = 0;
if (K >= 16)
{
Kontakt[12 + J] = 1;
K = K - 16;

}
else
Kontakt[12 + J] = 0;
if (K >= 8)
{
Kontakt[13 + J] = 1;
K = K - 8;

}
else
Kontakt[13 + J] = 0;
if (K >= 4)
{
Kontakt[14 + J] = 1;
K = K - 4;

}
else
Kontakt[14 + J] = 0;
if (K >= 2)
{
Kontakt[15 + J] = 1;
K = K - 2;

}
else
Kontakt[15 + J] = 0;
if (K >= 1)
{
Kontakt[16 + J] = 1;
K = K - 1;

}
else
Kontakt[16 + J] = 0;


Anzeigen();
}

Ich hoffe ihr kommt mit dem Code Ausschnit klar.
Wenn jemand einen besseren Forschlag oder eine Frage hat kann er sich ruhig melden.

Benutzeravatar
HaNull
Forumane
Beiträge: 4381
Registriert: Freitag 2. Februar 2007, 01:47
Wohnort: Rhein-Sieg-Kreis

Beitrag von HaNull » Samstag 5. April 2008, 23:12

Hallo!

Danke für das Veröffentlichen Deiner Lösung; vielleicht programmiere ich irgendwann auch etwas in dieser Richtung.
leinad hat geschrieben:System.Threading.Thread.Sleep(5);
Das sieht ein bißchen nach "busy waiting" aus.
"new SerialDataReceivedEventHandler" scheint mir da ein besserer Ansatz.
Mein PC ist recht leise - es sei denn, Programme treiben die CPU mit busy waiting zu Rekordtemperaturen und den Lüfter auf Hochtouren ...

BTW: wenn Du dein Listing zwischen [_QUOTE] und [/QUOTE_] (jeweils ohne Unterstriche) packst, dann bleiben die Leerzeichen (Einrückungen) erhalten.
████████   Gruß aus NRW
████████   Thomas
████████   Multi-MISTler: 1. Siegburg (RSK) - 2. Köln rrh. - 3. Rheinbreitbach

leinad

Beitrag von leinad » Sonntag 6. April 2008, 07:29

Danke für die Tipps werde ich bei Gelegenheit mal versuchen.

Benutzeravatar
Peter Müller
Forumane
Beiträge: 4291
Registriert: Dienstag 25. Januar 2005, 12:43

Beitrag von Peter Müller » Sonntag 6. April 2008, 07:34

else
Kontakt[4 + J] = 0;
if (I >= 8)
{
Kontakt[5 + J] = 1;
I = I - 8;
... seit wann darf man denn Smilies im Sourcecode verwenden? :wink:
Grüße, Peter

Bei campact.de per E-Mail abstimmen: 49-Euro-Ticket retten! ... das haben Stand 25.08.2023 um 20:45 Uhr schon 115.000 Menschen getan.

Und Aktionen bei campact.de wirken, siehe Wikipedia, da wird darüber berichtet.

Benutzeravatar
HaNull
Forumane
Beiträge: 4381
Registriert: Freitag 2. Februar 2007, 01:47
Wohnort: Rhein-Sieg-Kreis

Beitrag von HaNull » Sonntag 6. April 2008, 19:24

Hier mal der Beitrag von leinad als Code formatiert (ohne Smilies):

Code: Alles auswählen

Wird zum Beispiel durch einen Timer ausgelösst:

public string []C = new string[32];
public string []D = new string [32];
public int anzahl = 2;
public int[] Kontakt = new int[400];//noch nicht der entgültige wert

serialPort1.Open();
            

serialPort1.Write(new byte[] { (byte)(128 + anzahl) }, 0, 1);           
System.Threading.Thread.Sleep(5);
B = Convert.ToString(serialPort1.BytesToRead);
do
{
  j++;
  textBox3.Text=(Convert.ToString(j));
  C[j] = Convert.ToString(serialPort1.ReadByte());
  D[j] = Convert.ToString(serialPort1.ReadByte());
  Auswerten(j, Convert.ToInt32(C[j]), Convert.ToInt32(D[j]));
} while (j <= anzahl-1);

serialPort1.Close();


public void Auswerten(int rückmeldeModulNummer, int I, int K)
{
  int J = 16 * (rückmeldeModulNummer - 1); //Nummer des Rückmeldemoduls
  if (I >= 128)
  {
    Kontakt[1 + J] = 1;
    I = I - 128;
  }
  else
    Kontakt[1 + J] = 0;
  if (I >= 64)
  {
    Kontakt[2 + J] = 1;
    I = I - 64;
  }
  else
    Kontakt[2 + J] = 0;
  if (I >= 32)
  {
    Kontakt[3 + J] = 1;
    I = I - 32;
  }
  else
    Kontakt[3 + J] = 0;
  if (I >= 16)
  {
    Kontakt[4 + J] = 1;
    I = I - 16;
  }
  else
    Kontakt[4 + J] = 0;
  if (I >= 8)
  {
    Kontakt[5 + J] = 1;
    I = I - 8;
  }
  else
    Kontakt[5 + J] = 0;
  if (I >= 4)
  {
    Kontakt[6 + J] = 1;
    I = I - 4;
  }
  else
    Kontakt[6 + J] = 0;
  if (I >= 2)
  {
    Kontakt[7 + J] = 1;
    I = I - 2;
  }
  else
    Kontakt[7 + J] = 0;
  if (I >= 1)
  {
    Kontakt[8 + J] = 1;
    I = I - 1;
  }
  else
    Kontakt[8 + J] = 0;

  if (K >= 128)
  {
    Kontakt[9 + J] = 1;
    K = K - 128;
  }
  else
    Kontakt[9 + J] = 0;
  if (K >= 64)
  {
    Kontakt[10 + J] = 1;
    K = K - 64;
  }
  else
    Kontakt[10 + J] = 0;
  if (K >= 32)
  {
    Kontakt[11 + J] = 1;
    K = K - 32;
  }
  else
    Kontakt[11 + J] = 0;
  if (K >= 16)
  {
    Kontakt[12 + J] = 1;
    K = K - 16;
  }
  else
    Kontakt[12 + J] = 0;
  if (K >= 8)
  {
    Kontakt[13 + J] = 1;
    K = K - 8;
  }
  else
    Kontakt[13 + J] = 0;
  if (K >= 4)
  {
    Kontakt[14 + J] = 1;
    K = K - 4;
  }
  else
    Kontakt[14 + J] = 0;
  if (K >= 2)
  {
    Kontakt[15 + J] = 1;
    K = K - 2;
  }
  else
    Kontakt[15 + J] = 0;
  if (K >= 1)
  {
    Kontakt[16 + J] = 1;
    K = K - 1;
  }
  else
    Kontakt[16 + J] = 0;

  Anzeigen();
}

Ich hoffe ihr kommt mit dem Code Ausschnit klar.
Wenn jemand einen besseren Forschlag oder eine Frage hat kann er sich ruhig melden.
████████   Gruß aus NRW
████████   Thomas
████████   Multi-MISTler: 1. Siegburg (RSK) - 2. Köln rrh. - 3. Rheinbreitbach

Gast

Beitrag von Gast » Montag 7. April 2008, 14:44

h-zero hat geschrieben:Hier mal der Beitrag von leinad als Code formatiert (ohne Smilies):

Code: Alles auswählen

Wird zum Beispiel durch einen Timer ausgelösst:
System.Threading.Thread.Sleep(5);
Ist das der Wert der Wartezeit zwischen 2 Timerereignissen zum Auslesen der S88? Dann ist diese Zeit zu lang. Um zeitnah die S88 abzufragen muss man unter 1 Sek bleiben. Ich lasse alle 501mS die S88 abfragen.

In VB6 bedeutet der Befehl "Sleep" dass dieses Programm für die angegebene Zeit schlafen gelegt wird. Das ist gefährlich, da während dieser Zeit keine Programmausführung erfolgt, also auch kein Befehl an das Interface gesendet wird.

:wink: BB

leinad

Beitrag von leinad » Montag 7. April 2008, 15:07

Danke das ihr die Smillies raus getan hab ich hatte am Wochenende leider keine Zeit um da zu erledigen.

Nun zu deiner Frage:
Nein das ist nur einen kurze Unterbrechung zwischen dem schreiben und lesen der Schnittstelle. Zudem sind das nur 5/1000 Sekunden.
Denn Timer habe ich direkt in der Form definiert.

Mich freut das so viele Interesse an diesem Thema haben.

Gast

Beitrag von Gast » Montag 7. April 2008, 19:41

Hast Du dein Programm schon im praktischen Versuch geprüft?
Mir erscheint die Zeit von 5/1000 Sek doch sehr unwahrscheinlich. Welches Interface benutzt Du?

:wink: BB

leinad

Beitrag von leinad » Dienstag 8. April 2008, 15:45

Das funktioniert sehr gut.
Wenn ich die 5/1000 funktioniert es nicht ich denke nämlich dass das eher mit der Ansteuerung der Schnittstelle etwas zu tun hat und nicht mit dem Interface.

Aber das ist nur eine Vermutung du kannst es ja mal Probieren.

Oder wenn jemand eine andere Idee hat warum es so sein muss kann er sich auch gerne melden.

Gast

Beitrag von Gast » Dienstag 8. April 2008, 17:17

leinad hat geschrieben:Das funktioniert sehr gut.
Wenn ich die 5/1000 funktioniert es nicht ich denke nämlich dass das eher mit der Ansteuerung der Schnittstelle etwas zu tun hat und nicht mit dem Interface.
:roll: Also, mit diesem Satz kann ich nun gar nichts anfangen. Funktioniert das Programm nun oder nicht? Welches Interface hast Du denn nun?

:wink: BB

leinad

Beitrag von leinad » Dienstag 8. April 2008, 17:39

Funktioniert einwandfrei.
Ich benutze das normale Interface von Märklin (6050) ist meines Wissens nach die bestellnummer.

Benutzeravatar
Oysos
Forumane
Beiträge: 793
Registriert: Samstag 4. August 2007, 11:43
Wohnort: Kiel

Beitrag von Oysos » Mittwoch 9. April 2008, 15:49

Moin,

@h-zero: gerade Sleep() Funktionen sollten keine CPU-Last erzeugen, sondern den Thread für die Zeit schlafenlegen, vor allem wenn es von MS im .NET bereitgestellt wird.

@leinad: warum das Sleep()?
Eigentlich gehören Lesen und Schreiben doch in zwei verschiedene Funktionen, die in unterschiedlichen Threads laufen, zumindest sollten die das wenn du ihne Events arbeitest.

Gruß
Hannes

Benutzeravatar
HaNull
Forumane
Beiträge: 4381
Registriert: Freitag 2. Februar 2007, 01:47
Wohnort: Rhein-Sieg-Kreis

Beitrag von HaNull » Mittwoch 9. April 2008, 16:37

Hallo!
Oysos hat geschrieben:@h-zero: gerade Sleep() Funktionen sollten keine CPU-Last erzeugen, sondern den Thread für die Zeit schlafenlegen, vor allem wenn es von MS im .NET bereitgestellt wird.
Mit Sleep(5) wird die Funktion 200mal pro Sekunde ausgeführt - das ist nicht viel, aber viel schlechter als das Warten auf ein Event ...
████████   Gruß aus NRW
████████   Thomas
████████   Multi-MISTler: 1. Siegburg (RSK) - 2. Köln rrh. - 3. Rheinbreitbach

Gast

Beitrag von Gast » Donnerstag 10. April 2008, 11:35

Hallo leinad,
wenn dein Programm funktioniert, was hast Du dann für ein Problem mit Deiner seriellen Schnittstelle?

:roll: BB

Antworten