Forum: PC-Programmierung Datei versenden über RS232 in C# blockiert kompl. Rechner


von Thomas (Gast)


Lesenswert?

Hallo zusammen,

ich versuche seit Wochen, eine Datei zeilenweise mit C# (SharpDevelop)an 
einen Mikrocontroller zu senden und auf die Antwort zu warten.
Der Programmablauf ist in etwa folgender: Beim Klick auf Button1 wird 
folgendes gestartet:

Open_File();
Open_SerialPort1();
foreach line in file
{
  create_message();  //Zeile in Datenpaket packen (mit Adresse und 
Prüfsumme)
  send_message();  //Nachricht absenden
  delay();    //warten bis ein Timer abgelaufen ist (ca. 500ms)
  check_answer();  //Prüfen, ob erwartetes Antwortpaket empfangen wurde
}

Da das Antwortpaket schon mal ne halbe Sekunde auf sich warten lässt, 
warte ich immer so lange, bis ich die empfangenen Antwortdaten prüfe. 
Das kostet unnötig Zeit, weil die Antwort meist schon nach 20 ms da ist. 
Des Weiteren blockiert die Senderoutine mein Formular, wo ich gerne eine 
Uhr und einen Progressbalken mit laufen lassen würde. Jetzt habe ich 
schon verstanden, dass ich das mittels Threading lösen muss. Aber was 
muss in welchen Thread? Und vor allem wie?
Filename und Portparameter sowie Adressdaten stehen in verschiedenen 
TextBoxen. Diese muss die Senderoutine ja auslesen (oder sollte ich sie 
ihr übergeben?)
Sollte ich jew. einen Thread zum Senden, Empfangen und Dateilesen 
machen, oder alles in einem Thread machen. Und wie kann ich die 
Empfangsdaten prüfen, ohne generell so lange zu warten?

Ich weiß, das ist ziemlich viel auf einmal, aber vielleicht kann mir ja 
trotzdem jemand weiterhelfen.
Achja – prinzipiell funktioniert das Programm – aber ewig langsam und 
mit blockiertem System (andere Programme wollen auch nicht mehr so 
richtig während der Laufzeit und der Lüfter dreht auf Hochtouren)

Vielen Dank, Thomas

von Markus V. (valvestino)


Lesenswert?

Hi Thomas,

Thomas wrote:
> Hallo zusammen,
>
> ich versuche seit Wochen, eine Datei zeilenweise mit C# (SharpDevelop)an
> einen Mikrocontroller zu senden und auf die Antwort zu warten.
> Der Programmablauf ist in etwa folgender: Beim Klick auf Button1 wird
> folgendes gestartet:
>
> Open_File();
> Open_SerialPort1();
> foreach line in file
> {
>   create_message();  //Zeile in Datenpaket packen (mit Adresse und
> Prüfsumme)
>   send_message();  //Nachricht absenden
>   delay();    //warten bis ein Timer abgelaufen ist (ca. 500ms)
>   check_answer();  //Prüfen, ob erwartetes Antwortpaket empfangen wurde
> }
>
> Da das Antwortpaket schon mal ne halbe Sekunde auf sich warten lässt,
> warte ich immer so lange, bis ich die empfangenen Antwortdaten prüfe.
> Das kostet unnötig Zeit, weil die Antwort meist schon nach 20 ms da ist.
> Des Weiteren blockiert die Senderoutine mein Formular, wo ich gerne eine
> Uhr und einen Progressbalken mit laufen lassen würde. Jetzt habe ich
> schon verstanden, dass ich das mittels Threading lösen muss. Aber was
> muss in welchen Thread? Und vor allem wie?

Packe den obigen Code-Abschnitt komplett in einen Thread. Zum Threading 
gibt's bei MS entsprechende Artikel:
http://www.microsoft.com/germany/msdn/library/net/VerwendenVonThreads.mspx?mfr=true
http://msdn2.microsoft.com/en-us/library/e1dx6b2h(VS.85).aspx

> Filename und Portparameter sowie Adressdaten stehen in verschiedenen
> TextBoxen. Diese muss die Senderoutine ja auslesen (oder sollte ich sie
> ihr übergeben?)

Letzteres. Software sollte strikt aufgeteilt sein in Oberfläche und 
Datenmodell. Siehe hierzu das MVC Architekturmodell, z.B. in Wikipedia.

> Sollte ich jew. einen Thread zum Senden, Empfangen und Dateilesen
> machen, oder alles in einem Thread machen.

Ein Thread.

> Und wie kann ich die
> Empfangsdaten prüfen, ohne generell so lange zu warten?

ReadTimeout Property beim SerialPort Objekt setzen, z.B. auf 500ms.

> Ich weiß, das ist ziemlich viel auf einmal, aber vielleicht kann mir ja
> trotzdem jemand weiterhelfen.
> Achja – prinzipiell funktioniert das Programm – aber ewig langsam und
> mit blockiertem System (andere Programme wollen auch nicht mehr so
> richtig während der Laufzeit und der Lüfter dreht auf Hochtouren)

Ich weiß nicht wirklich, was Dein delay() Methode veranstaltet. Aber 
nachdem Du schreibst, daß Dein Rechner auf Vollast läuft, schätze ich 
mal, daß Du dort einen sogenannten Busy-Wait durchführst (verbraten von 
CPU-Zeit). Absolut tödlich auf Multiprocessing Systemen. Lasse den 
delay() Aufruf komplett weg und verwende, wie bereits oben geschrieben 
den ReadTimeout.

> Vielen Dank, Thomas

Grüße
Markus

von Thomas (Gast)


Lesenswert?

Hallo Markus,

vielen Dank für Deine Tips. Ich werde vermutlich morgen mal sehen, wie 
weit ich komme. Bin gerade erstmal dabei das Programm so umzuschreiben, 
dass ich kaum noch globale Variablen brauche und alles mit Übergabe und 
Rückgabeparametern erschlage.
Mit dem Delay hast Du recht. Ich setze eine Hilfsvariable, starte einen 
Timer und der setzt sie zurück. Die Zeit schlage ich mit >> 
while(hifsvariable); << tot. War mir schon klar, dass das nicht OK ist. 
Werde mal sehen, wie ich das anders löse...

Gruß, Thomas

von Jojo S. (Gast)


Lesenswert?

wenn schon warten dann einfach mit Thread.Sleep(500); Und zum 
Progressbar gibts auch Beispiele in der C# Doku. Wenn die Kommunikation 
in einen seperaten Thread verlegt wird dann wirst du noch auf das 
Problem stossen das du aus dem Worker-Thread nicht auf Steuerelement in 
deinem Dialog zugreifen darfst. Dafür solltest du die Invoke-Beispiele 
übernehmen.

von Markus V. (valvestino)


Lesenswert?

Hi Thomas,

Thomas wrote:
> Hallo Markus,
>
> vielen Dank für Deine Tips. Ich werde vermutlich morgen mal sehen, wie
> weit ich komme. Bin gerade erstmal dabei das Programm so umzuschreiben,
> dass ich kaum noch globale Variablen brauche und alles mit Übergabe und
> Rückgabeparametern erschlage.
> Mit dem Delay hast Du recht. Ich setze eine Hilfsvariable, starte einen
> Timer und der setzt sie zurück. Die Zeit schlage ich mit >>
> while(hifsvariable); << tot. War mir schon klar, dass das nicht OK ist.
> Werde mal sehen, wie ich das anders löse...

Wie ich bereits oben geschrieben habe, lasse den Aufruf von delay()
komplett weg. Du mußt das Lesen vom COM-Port so aufsetzen, daß Du z.B.
auf ein Zeichen mit Timeout wartest und wenn das Zeichen ankommt, mit
Thread.Sleep(...) nochmals ein paar Millisekunden wartest, damit der
Rest der Sendung übertragen werden kann. Die Zeit solltest Du über das 
Datenvolumen und die Baudrate berechnen können. Dann ermittelst Du mit 
SerialPort.BytesToRead, wieviel Daten anliegen und liest diese mit 
SerialPort.Read() ein. Dein delay() ist dabei völlig
überflüssig weil das Warten entweder beim Lesen vom Com-Port oder über
Thread.Sleep() stattfindet. Beide Arten zu Warten sind
multi-processing-verträglich.

>
> Gruß, Thomas

Grüße
Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.