Forum: PC-Programmierung c# AVR sendet Daten an C# Consolenprogramm


von Willi K. (kucky)


Lesenswert?

Hallo zusammen,
ich werde hier nicht schlau draus.
Ich sende mit eimem AVR einen String an meine C#-Console:

Serial.print("BumperFrontLeft\r");

In dem C#-Programm kommt das auch so an. Aber nur wenn ich im Debugmodus 
einen Breakpoint setzte, und den Wert auslese.
Hier der Auszug:
1
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
2
    {
3
        string dataToReceive = string.Empty;
4
        //private char lf = (char)10; //Line Feed
5
        char cr = (char)13; //Carriage Return
6
        ARDUINO_msg = serialPort1.ReadExisting();
7
8
        if (!ARDUINO_msg.EndsWith(Convert.ToString(cr), false, System.Globalization.CultureInfo.CurrentCulture))
9
        {
10
            dataToReceive += ARDUINO_msg;              
11
        }
12
        else
13
        {
14
            ARDUINO_msg = ARDUINO_msg.Replace(Convert.ToString(cr), "");                
15
        }
16
17
            this.BeginInvoke(new EventHandler(DoUpdate));
18
            serialPort1.DiscardInBuffer();
19
        }
20
//-------------------------------------------------------------------------
21
private void DoUpdate(object s, EventArgs e)
22
    {
23
        value_receive = UInt32.TryParse(ARDUINO_msg, out ARDUINO_Value);
24
        if (value_receive)    // if there ist a number...
25
        {
26
            evaluate_value();
27
        }
28
        else
29
        {
30
            evaluate_message();
31
        }
32
    }

Wenn ich nun mittels Debug.writeline(msg) zu Laufzeit den String 
anschaue, fehlt meistens das erste Zeichen, also "B". Manchmal auch noch 
"u". Wenn ich aber den Bumper schnell hintereinander drücke ist das 
Ergebnis irgendwann OK. Ich habe hier viele Beträge zu ähnlichen Themen 
gefunden, und umgesetzt, aber nun hänge ich.

LG Willi

von Peter II (Gast)


Lesenswert?

ist ja auch klar warum.

ReadExisting();

liest du das was da ist, wenn zu diesem Zeitpunkt noch nicht alles da 
ist, dann fehlt es.

Es ist oft gar nicht sinnvoll mit dem Event zu arbeiten, wenn du auf die 
Daten wartest.

while( true ) {
  daten += serialPort1.Read();

  //aufwerten von Daten
  //danach daten leer machen
}

von Karl H. (kbuchegg)


Lesenswert?

In deiner serialPort1_DataReceived gehst du davon aus, dass du hier

serialPort1.ReadExisting()

einen kompletten String vom Arduino kriegst. So lange du dein Programm 
mit dem Debugger zwischendruch immer wieder mal anhältst, wird das auch 
so sein. Nur wenn es dann full-speed läuft, ist dem nicht mehr so.

Und so wie ich das sehe, setzt du die Einzelteile, die bei mehreren 
Aufrufen der Funktion jeweils eintrudeln, falsch zusammen.

Geh davon aus, dass beim ersten Aufruf der Funktion von der Seriellen 
der String

   "Bum"

eingetroffen ist.

Beim nächsten mal liefert ReadExisting

  "perFront"


und erst beim dritten mal kommt der dann noch fehlende Rest

  "Left\r"

Dein Code muss diese Teilstücke zusammensetzen und erst dann wenn alles 
beisammen ist, kannst du mit diesem jetzt kompletten String 
weiterarbeiten.


(Streng genommen müsste dein Code auch mit


  "Bum"
  "perFront"
  "Left\rBum"

klar kommen. Wenn also der \r mitten drinnen in dem String steckt, den 
du von ReadExisting bekommst. Kommt drauf an, wie schnell der µC seine 
Statusupdates rausschickt)

von Karl H. (kbuchegg)


Lesenswert?

>            this.BeginInvoke(new EventHandler(DoUpdate));
>            serialPort1.DiscardInBuffer();

Holla.
Du kannst doch nicht einfach deinen Buffer verwerfen! In der 
Zwischenzeit, die der EventHandler zur Behandlung gebraucht hat, können 
doch noch weitere Zeichen eingetrudelt sein. Die Fehlen dir dann 
logischerweise.

von Willi K. (kucky)


Lesenswert?

Danke für die Antworten,
hatte es schon fast vermutet.
@ PeterII: Ich muss aber schon das DataReceived.Event aufrufen, oder? 
Wie erfährt das Programm sonst, das eine Taste gedrückt wurde?

@ K.H. Buchegger: "serialPort1.DiscardInBuffer()" Das hatte ich schon 
auskommentiert. Ich hatte hier verschiedene Dinge versucht.

Das mit dem "zuammen bauen" werde ich nun mal versuchen.

LGW

von Peter II (Gast)


Lesenswert?

Willi K. schrieb:
> Ich muss aber schon das DataReceived.Event aufrufen, oder?
> Wie erfährt das Programm sonst, das eine Taste gedrückt wurde?
nein, man kann auch einen eigenen thread starten der ständig von dem 
com-port daten einliest.

von Willi K. (kucky)


Lesenswert?

ich muss nun leider zugeben, dass ich das (noch!!)nicht kann. Ich bin in 
C# noch nicht so weit. Bin gerade dabei mich in C# einzuarbeiten. Bei 
den threads bin ich noch nicht. Dies ist auch "nur" ein Programm um 
meinen ersten Bot per BT fern zu steuern. Ist es zuviel verlangt, mir 
einen Code zu posten.
Wenn der Bot dann funktioniert, werde ich mich intensiv mit C# befassen. 
Versprochen.
LG Willi

von bluppdidupp (Gast)


Lesenswert?

Thread erstellen ist eigentlich recht simpel.

Die Klasse um eine Thread-Funktion erweitern:
1
private void MeinThread()
2
{
3
   SerialPort sp=new SerialPort("COM1", 9600, Parity.None, 8, 1);
4
   sp.Encoding=Encoding.Default; // Zeichensatz setzen
5
   
6
   while(true)
7
   {
8
       // Zeilen abrufen:
9
       string zeile=sp.ReadLine(); // oder .Read / .ReadByte oder was passt
10
       // ...und dann irgendwas damit anstellen...
11
   }
12
}

...und den Thread irgendwo starten:
1
Thread t = new Thread(new ThreadStart(this.MeinThread));
2
t.Start();

von Willi K. (kucky)


Lesenswert?

Vielen vielen Dank,
mache mich gleich an die Arbeit. Melde mich dann wieder, kann aber etwas 
dauern.

Schönen Abend noch
Willi

von Willi K. (kucky)


Lesenswert?

Moin moin,
habe mir "fast" die Nacht um die Ohren geschlagen, bin aber hier hängen 
geblieben.
bluppdidupp schrieb:

...und den Thread irgendwo starten:
>
1
> Thread t = new Thread(new ThreadStart(this.MeinThread));
2
> t.Start();
3
>

Was meinst Du mit "irgendwo starten"? Ich muss doch ein Ereignis 
abwarten, eben das was der Taster auslöst. Wie schon gesagt, ich bin 
noch nicht so weit.

LG
Willi

von Karl H. (kbuchegg)


Lesenswert?

Willi K. schrieb:

> Was meinst Du mit "irgendwo starten"?

Na, einfach starten, loslegen lassen, damit der Code auch läuft.

> Ich muss doch ein Ereignis
> abwarten, eben das was der Taster auslöst.

Du verwechselst da was.
Ein Thread ist ein zweiter Handlungsfaden innerhalb deines Programms. 
Der Thread von da oben der läuft einfach. Wenn er gestartet wird, dann 
öffnet er die serielle Schnittstelle und mittels ReadLine wartet er, bis 
von der Gegenstelle eine komplette Zeile eingetroffen ist. Die zerlegt 
er dann und macht damit, was immer es damit zu machen gibt. Bis er sich 
(durch die Schleife) wieder auf die Lauer legt und auf die nächste Zeile 
von der Seriellen wartet. Das alles läuft dann völlig unabhängig vom 
restlichen Programm.
Wenn du so willst: anstatt dass du alleine eine Arbeit machst, hast du 
dir mit dem Thread einen Kumpel eingeladen, dem du Arbeit zuweist und 
der die dann alleine bearbeitet. Ab und zu kommt er und sagt: Du hör 
mal, da in der Post (serielle Schnittstelle) war die und die Rechnung, 
die musst du bearbeiten.

> Wie schon gesagt, ich bin
> noch nicht so weit.

Du brauchst ein C# Buch

von Willi K. (kucky)


Lesenswert?

Guten Morgen Karl Heinz Buchegger,
danke für die Erläuterungen. Habe ich verstanden. Ist "fast" wie ein 
Interrupt.
Das Buch habe ich bereits "Visual C# 2010" von Markt und Technik. Bin 
hier aber erst auf Seite 159.

Ich bleibe aber dran.

Schönes Wochenende.

von Willi K. (kucky)


Lesenswert?

Hallo,
so jetzt funktioniert es. Erst einmal danke an alle. Das Zauberwort hieß 
"ReadLine" und von der AVR-Seite "Serial.print("....\n").
Alle eure Hinweise haben schlußendlich zum Ziel geführt. Das Theading 
war mir noch zu kompliziert. Sorry Karl Heinz Buchegger. Was ich hier 
aber gelernt habe, ist das debuggen und die Meldungen genau lesen.
1
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
2
{
3
    char lf = (char)10; //Line Feed
4
5
    string msg = serialPort1.ReadLine();
6
    Debug.WriteLine(ARDUINO_msg);
7
8
    if (!msg.EndsWith(Convert.ToString(lf), false, System.Globalization.CultureInfo.CurrentCulture))
9
        {
10
            ARDUINO_msg += msg;
11
        }
12
    else
13
        {
14
            ARDUINO_msg = ARDUINO_msg.Replace(Convert.ToString(lf), "");
15
        }
16
    Debug.WriteLine(ARDUINO_msg);
17
    this.Invoke(new EventHandler(DoUpdate));
18
}
ob man den else-Zweig wirklich braucht, weis ich noch nicht.
Nochmals Dank an alle
Schönes Wochenende
Willi

von bluppdidupp (Gast)


Lesenswert?

.ReadLine() gibt normalerweise den String ohne CR/LF zurück.
1
// Statt...
2
char lf = (char)10;
3
// ...kann man auch einfach...
4
char lf='\n';
5
// ...schreiben. CR wäre '\r'
6
7
// Bei '\r' und '\n' ist Groß-/Kleinschreibung egal, du hättest daher auch einfach
8
if (!msg.EndsWith("\n"))
9
{
10
// ...schreiben können ;D

von Peter II (Gast)


Lesenswert?

und ReadLine sollte man nicht im event verwenden. Da soll man nur daten 
abrufen die schon vorhanden sind.

von Willi K. (kucky)


Lesenswert?

bluppdidupp schrieb:
> .ReadLine() gibt normalerweise den String ohne CR/LF zurück.
stimmt, ist umgesetzt.

Peter II schrieb:
> und ReadLine sollte man nicht im event verwenden. Da soll man nur daten
> abrufen die schon vorhanden sind.

Ich denke, hier meinst Du das mit den Threads. Die kann ich, wie gesagt, 
noch nicht. Ich empfange einen kompletten String und es funktioniert. 
Wenn Du einen andern Weg, ohne Thread weißt, bitte immer her damit.

schönen Sonntag noch
Willi

von Sven H. (dsb_sven)


Lesenswert?

Problem ist halt, wenn keine komplette Zeile empfangen wurde, wartet ein 
Programm im EventHandler bis eine definierte Wartezeit erreicht ist.

Du solltest im EventHandler mit ReadExisting() alle vorhandenen Bytes 
einlesen und irgendwo abspeichern, bis dein Zeilenendezeichen empfangen 
wurde und dann mit der Verarbeitung der Daten beginnen.

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.