Forum: PC-Programmierung C# Serielle Schnittstelle per Intervall abfragen


von rlbb0206 (Gast)


Lesenswert?

Hallo zusammen,

ich würde gerne in Visual Studio (C#) eine Software erstellen die über 
die Serielle Schnittstelle (RS485/ModBus) nach einem Klick auf den 
entsprechenden Button im sekundentakt Daten vom Slave abfragt und 
ausgibt.
Hier komme ich nicht weiter. Ich habe es mit einem Timerevent probiert 
aber dann kann ich nichts mehr in dem Programm machen (noch nicht einmal 
schließen).
Die Abfrage und die Ausgabe ist kein Problem. Das einzige Problem das 
ich habe ist dies jede Sekunde zu machen und ich trotzdem noch das 
Programm bedienen kann.

Ich hoffe ihr könnt mir da weiter helfen.

von bluppdidupp (Gast)


Lesenswert?

Nimm einen BackgroundWorker und starte den bei Klick auf den Button und 
öffne in der DoWork des BackgroundWorkers den SerialPort und lese da im 
Sekundentakt raus. Wenn SerialPort.Read...-Funktionen blockieren wirkt 
es sich dann nicht direkt auf die Oberfläche aus, weil es dann 
unabhängig dazu parallel ausgeführt wird.
Vom BackgroundWorker aus z.B. via dessen .ReportProgress() für die UI 
relevante Infos zurück ans UI übermitteln (z.B. um was vom SerialPort 
empfangenes in einer Textbox hinzuzufügen)

(Aktuell hängt vermutlich der Code in deinem Timer-Event, weil z.B. eine 
dort aufgerufene .Read-Methode des SerialPort-Objekts blockiert, weil 
sie auf Daten wartet)

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

a) serielle Schnittstellen haben beinen Puffer (in den 
Systemeinstellungen konfigurierbar), da muss man nicht auf jedes 
einzelne Zeichen warten oder Angst haben, etwas zu verpassen (sofern man 
nicht allzulange wartet).  Dieser Puffer ist üblicherweise irgendwas 
zwischen 32Byte und 4k groß ...

b) ich kenne zwar speziell C# nicht, aber in C++ gibts die Funktion 
Serial.available(). Die liefert die Anzahl der Zeichen im Puffer bzw. 
ein true/false, je nachdem, ob etwas da ist - damit wäre ein Polling 
recht schnell zu erledigen. Sollte mit C# auch machbar sein.

c) das Abfragen, Auslesen und Verarbeiten kann man auch in einen Thread 
packen, dann sollte der Rest der App oder zumindest die GUI problemlos 
weiterlaufen (nennt man "Nebenläufigkeit")

d) man kann mit dem Empfang der seriellen Schnittstelle auch einen 
Interrupt verknüpfen, dann muss man auch nicht pollen

e) in Javascript gibts "Promises", so eine Art scharf gemachter 
Einmal-Thread, derauf ein Ereignis (meist die Antwort auf einen 
AJAX-Request) wartet. Sollte es das in C# nicht auch irgendwie geben?

von Christian B. (christian_b5)


Lesenswert?

Frank E. schrieb:
> b) ich kenne zwar speziell C# nicht, aber in C++ gibts die Funktion
> Serial.available(). Die liefert die Anzahl der Zeichen im Puffer bzw.
> ein true/false, je nachdem, ob etwas da ist - damit wäre ein Polling
> recht schnell zu erledigen. Sollte mit C# auch machbar sein.

Es gibt in .net SerialPort.BytesToRead.
Jedoch sollte man in folgende Informationen beachten:

https://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport

Das .BytesToRead eher schlecht funktioniert habe ich auch schon erfahren 
müssen. Vom DataRecieved Event ganz zu schweigen.
Hardware mit USB-Uart IC's (z.b. FT232 oder ähnlich) haben bei mir mit 
dem .Net SerialPort mehr Probleme bereitet(insbesondere ein USB-Rs485 
Adapter mit Profilic IC), wie das benutzen der USB Schnittstelle von ARM 
Controllern.
Bei Lesen von Daten kommen diese oft mit Verzögerung, falsch oder 
garnicht an. Das senden von Daten funktionierte jedoch mit dem .Net 
SerialPort. Da die selbe Hardware mit Programmen die nicht in .Net 
geschrieben sind einwandfrei funktioniert, kann ich die im Link 
gennanten Probleme bestätigen.

von N. M. (mani)


Lesenswert?

DataReceivedHandler ist auch noch ein Stichwort das mit den bereits 
genannten Mitteln helfen kann

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Christian B. schrieb:

> Das .BytesToRead eher schlecht funktioniert habe ich auch schon erfahren
> müssen. Vom DataRecieved Event ganz zu schweigen.

Unsinn. Benutze ich seit Jahrzehnten und funktioniert ganz hervorragend. 
Und zwar genau in dieser Kombination. Sprich: Im Eventhandler wird mit 
BytesToRead erfragt, wieviel zu lesen sind und genau diese Zahl wird 
dann auch gelesen.

Man muss sich halt nur im Klaren darüber sein, dass der Eventhandler 
nicht im Kontext des GUI-Threads läuft und die entsprechenden Maßnahmen 
treffen, wenn man die Daten in eben jenem benötigt...

von bluppdidupp (Gast)


Lesenswert?

Es gibt da schon diverse Fallstricke, je nachdem wie man die Daten 
ausliest.
z.B. (aus der Doku zu ReadExisting):
"The SerialPort class buffers data, but the stream object contained in 
the SerialPort.BaseStream property does not. Therefore, the SerialPort 
object and the stream object might differ on the number of bytes that 
are available to read. When bytes are buffered to the SerialPort object, 
the BytesToRead property includes these bytes in its value; however, 
these bytes might not be accessible to the stream contained in the 
BaseStream property."
je nachdem wie man dann ausliest kann man da schon leicht ungewollt den 
Thread blockieren.

Ich nehme immer einen BackgroundWorker/Thread und lese da einfach in 
Schleife via .Read() (Byte-Variante) aus. Das funktioniert bislang immer 
zuverlässig.

von Euro (Gast)


Lesenswert?

Christian B. schrieb:
> Bei Lesen von Daten kommen diese oft mit Verzögerung,
Das ist korrekt.

Christian B. schrieb:
> falsch oder garnicht an.
Das ist mir neu.

von c-hater (Gast)


Lesenswert?

bluppdidupp schrieb:

> Ich nehme immer einen BackgroundWorker/Thread

Kann man machen, ist aber überflüssig, da der SerialPort selber einen 
Thread für das Lesen erzeugt (übrigens auch schon unnötigerweise, denn 
er benutzt selber wiederum das asynchrone File-API, was seinerseits auch 
bereits einen Lesethread erzeugt).

Du sattelst also auf bereits zwei Threads nochmal einen drauf... Zwei 
der drei sind eigentlich schlicht über, ganz sicher aber der dritte...

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.