Guten Morgen Leute!
Ich habe ein Problem. Und zwar sende ich Daten von einem Sensor auf
einem Breakoutboard, der mit einem NUCLEOF411RE MC verbunden ist, per
UART an meinen PC. Funktioniert auch alles richtig gut. Mit Putty kann
ich mir die Daten anschauen die ankommen( siehe Bild ). Jetzt habe ich
noch eine Anwendung in C# programmiert die mir den String aufteilt und
in Textboxen anzeigt ( siehe Bild ). Das Funktioniert auch. Nur ist die
Aktualisierung dieser werte ziemlich schlecht. Die neuen Werte sollten
eigentlich die alten ziemlich schnell überschreiben so das es wie eine
Echtzeitübertragung wirkt. Manchmal werden die Werte überhaupt nicht
erneuert und manchmal mehrere hintereinander. Mein UART auf dem MC sowie
mein UART in meiner C# anwendung ist auf eine BaudRate von 115200
eingestellt. Hat jemand vielleicht einen Tipp?
kabelklaus schrieb:> SerialPort - DataReceiveEvent> (falls du das nutzt) ?
Ob es da einen Bug gibt weiß ich nicht. Bin neu in der C# und
Applikation Programmierung. habe in der Form1.cs halt einen serialPort
hinzugefügt und auf Buttonklick dann das hier.
private void button1_Click(object sender, EventArgs e)
{
serial.Open();
try
{
while (true)
{
string A = serial.ReadLine();
char[] Leerzeile = new char[] { ' ', '\t' };
String[] Stringsizes = A.Split(Leerzeile);
textBox1.Text = Stringsizes[0];
textBox2.Text = Stringsizes[1];
textBox3.Text = Stringsizes[2];
textBox4.Text = Stringsizes[3];
textBox5.Text = A;
Task.Delay(500);
}
}
catch (System.IO.IOException)
{
}
}
Walt N. schrieb:> Daniel -. schrieb:>> Wie liest du die serielle Schnittstelle aus?>> Kannst du deinen Code zeigen?>> string A = serial.ReadLine();>> genau so eigentlich
Ja super. Und wann immer?
Nutze ein Event.
Das Problem liegt sicher nicht am ComPort oder an C# sondern an deinem
Programm.
Readline habe ich nie benutzt. Ich habe read benutzt und die Daten in
Buffer
gesammelt. Anderes mal habe ich readexisting benutzt.
Hast du versucht timeoutread kleiner zu setzen?
Ein While und darin ein Task.Delay sind natürlich sehr, sehr übel und
gehören so nicht in eine C# Applikation.
Du musst Dir unbedingt angewöhnen, mit Events zu arbeiten.
Für Deinen konkreten Fall machst Du einen Event-Handler und meldest ihn
beim SerialPort an (dieser Code wird automatisch erzeugt, wenn Du Dir
das im Designer zusammenklickst):
1
serialPort = new System.IO.Ports.SerialPort();
2
serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
Der Handler zum empfangen der Daten könnte etwa so aussehen:
Erstmal würde ich sagen falsches Forum, zweitens: Nutz doch deinen alten
Thread weiter?
Ansonsten wurde alles gesagt, nutze Events, du kannst auch thresholds
setzen und ganze Blöcke auslesen. Somit wird das ganze recht performant.
Mit ReadLine() und ReadExisting() wäre ich sehr vorsichtig, denn das
Problem damit ist, dass diese noch mit dem auf dem PC eingestellten
Textencoding zusammenhängen (Codepage, UTF, etc.). Es kann dann
passieren, dass Dein programmierter Textparser z.B. auf einem Deutschen
Windows geht und auf einem Englischen nicht oder umgekehrt.
Daher würde ich solche Daten immer unverfälscht mit Read() einlesen und
danach erst das Bytearray mit dem passenden Encoding in einen String
umwandeln. Für ASCII, wie es von einem Mikrocontroller kommt, so:
System.Text.Encoding.ASCII.GetString(rxbuffer);
Ich habe jetzt einen Event erstellt. Nur bin ich mir noch nicht so
sicher wie das ganze funktioniert mit den Events. In diesem Eventhandler
von dir lese ich quasi jedesmal ein und mehr nicht. Die Umwandlung in
den String und die ausgabe an die Textboxen mache ich wohl eher nicht
auch noch in dem Eventhandler? Wie komme ich jetzt außerhalb dieses
eventhandlers an diesen rxbuffer um damit die umwandlungen zu machen und
kontinuierlich die neuen werte an die textboxen weitergebe
Walt N. schrieb:> Ich habe jetzt einen Event erstellt. Nur bin ich mir noch nicht so> sicher wie das ganze funktioniert mit den Events. In diesem Eventhandler> von dir lese ich quasi jedesmal ein und mehr nicht. Die Umwandlung in> den String und die ausgabe an die Textboxen mache ich wohl eher nicht> auch noch in dem Eventhandler? Wie komme ich jetzt außerhalb dieses> eventhandlers an diesen rxbuffer um damit die umwandlungen zu machen und> kontinuierlich die neuen werte an die textboxen weitergebe
Lern erst mal mal ein paar Grundlagen. Wie wär das?
Walt N. schrieb:> Ich habe jetzt einen Event erstellt. Nur bin ich mir noch nicht so> sicher wie das ganze funktioniert mit den Events. In diesem Eventhandler> von dir lese ich quasi jedesmal ein und mehr nicht. Die Umwandlung in> den String und die ausgabe an die Textboxen mache ich wohl eher nicht> auch noch in dem Eventhandler? Wie komme ich jetzt außerhalb dieses> eventhandlers an diesen rxbuffer um damit die umwandlungen zu machen und> kontinuierlich die neuen werte an die textboxen weitergebe
Du hast es mundgerecht serviert bekommen, und kannst damit immer noch
nichts anfangen? Wenn man einige Techniken nicht kennt, sollte man aber
zumindestens Code lesen können, wenn man an sowas rangeht.... Geh Tee
kochen
> Die Umwandlung in> den String und die ausgabe an die Textboxen mache ich wohl eher nicht> auch noch in dem Eventhandler?
auf jeden Fall ist der Event-Handler die Quelle deiner Daten und dann
rufst du dort eben die Funktion welche die Daten weiter verarbeiten soll
auf - ob du dann irgendwann darunter eine Textbox fuellst oder sonstiges
machst ist völlig egal
ganz wichtig: serielle Kommunikation ist kein Protokoll mit festen
Datengrößen oder irgendwelchen Garantien sondern ein Stream wie TCP/IP
wenn der Sender "hallo" schickt kann es sein das dein Event-Handler
mehrfach aufgerufen wird
1. Event "ha"
2. Event "ll"
3. Event "o"
und alle anderen Varianten - das MUSS deine weiter Verarbeitung können
(denk nicht nur weil das jetzt so aussieht als wenn alles als Block
kommt das es auch so bleibt - GRÖSSTER Fehler in der RS232
programmierung)
und über RS232 gibt es keinen Protokollstandard - d.h. es ist total
abhängig vom Sender wie die Verarbeitung aussehen muss - hast du eine
Protokollbeschreibung?
folge Varianten könnte es geben
du schickst per RS232 ein Befehl und das Gerät antwortet (oder sendet
z.B. auch ständig Daten):
dabei kann es sein:
-du kennst die notwendige Datenmenge aufgrund des abgesetzen Befehls
(und wartes auf die Menge)
-die ist irgendwo am Anfang der Antwort mit eingebettet (du merkst dir
die Anzahl und wartest so lange)
-es gibt eine Endekennung (Zeichenfolge), du wartest auf die Endekennung
damit kannst du die Daten die per seriell kommen wieder in logische
Pakete zerlegen
Wenn du uns die Beschreibung zu dem RS32 Protokoll zeigst wäres es
einfacher - oder einen Gerätenamen usw.
Walt N. schrieb:> Jetzt habe ich> noch eine Anwendung in C# programmiert die mir den String aufteilt und> in Textboxen anzeigt
und
1
privatevoidbutton1_Click(objectsender,EventArgse)
2
{serial.Open();
3
...
4
while(true)
5
{stringA=serial.ReadLine();
6
...
7
}
8
...
Dein Programm ist es, was den Mist baut. Nun hab ich mich bislang NICHT
mit Cdoppelvollpfosten befaßt, aber so ganz allgemein macht man das etwa
so:
1. man kreiert einen zweiten Thread, der rein prozedural läuft (also
NICHT ereignisgesteuert) und der in sinnvollen Zeitabschnitten (20..50
ms) den seriellen Kanal (serial.xxxx...) pollt und bei Vorliegen von
Empfangszeichen diese zu einer Art Kommandozeile, also einem String
zusammenfaßt. Wenn diese Zeile voll ist (entweder ein Zeilenende erkannt
oder eine Maximalanzahl von Zeichen drin), dann übergibt dieser Thread
dem Hauptthread die Zeile. Entweder per Event oder wenn's geht, eben
direkt, z.B. Refresh oder per Invalidate eines der Anzeigen oder so
ähnlich.
W.S.
>1. man kreiert einen zweiten Thread, der rein prozedural läuft (also>NICHT ereignisgesteuert) und der in sinnvollen Zeitabschnitten (20..50>ms) den seriellen Kanal (serial.xxxx...) pollt und bei Vorliegen von>Empfangszeichen diese zu einer Art Kommandozeile, also einem String>zusammenfaßt.
Äußerst unnötig verkompiliziert, warum sollte er dafür einen Thread
brauchen - die Unabhängigkeit von seiner Konsole/UI ist doch schon durch
den Event gegeben, du erweiterst das Push-Prinzip des Events noch mit
einem pollenden Pull-Prinzip und machst das ganze dann auch noch gleich
Data-Race-Condition freundlich
Er ist doch schon genug am rudern da sind solche Tips nicht wirklich
hilfreich
W.S. schrieb:> 1. man kreiert einen zweiten Thread, der rein prozedural läuft (also> NICHT ereignisgesteuert) und der in sinnvollen Zeitabschnitten (20..50> ms) den seriellen Kanal (serial.xxxx...) pollt
zu kompliziert
Walt N. schrieb:> Ich habe jetzt einen Event erstellt. Nur bin ich mir noch nicht so> sicher wie das ganze funktioniert mit den Events. In diesem Eventhandler> von dir lese ich quasi jedesmal ein und mehr nicht. Die Umwandlung in> den String und die ausgabe an die Textboxen mache ich wohl eher nicht> auch noch in dem Eventhandler? Wie komme ich jetzt außerhalb dieses> eventhandlers an diesen rxbuffer um damit die umwandlungen zu machen und> kontinuierlich die neuen werte an die textboxen weitergebe
Für einfache Dinge kannst die Verarbeitung und Ausgabe des Strings schon
im Eventhandler erledigen. Der Computer erledigt das ja normalerweise im
(geschätzt) Millisekundenbereich.
Wie bereits erwähnt wurde, weisst Du nicht, wievielmal der Eventhandler
aufgerufen wird, bis Deine Daten vollständig empfangen wurden; daher
wirst Du noch einen Buffer brauchen, welcher alles empfangene sammelt.
Das geht gut mit z.B. einer Liste:
1
List<byte> empfangsbuffer = new List<byte>();
Im Eventhandler kannst Du dann einfach die empfangenen Daten zufügen:
1
empfangsbuffer.AddRange(rxbuffer);
2
3
// Nun auswerten ob Du ein komplettes Datenpacket hast und wenn ja, dieses verarbeiten und aus "empfangsbuffer" löschen.
Da der Eventhandler asynchron von einem anderen Thread aufgerufen wird,
kannst Du darin nicht einfach GUI-Elemente ansprechen, sonst stürtzt das
Programm ab. In einem Beispiel oben findest Du die Lösung dafür mit
"BeginInvoke"...