Daten seriell an eine C# Anwendung senden

hallo zusammen, ich möchte von meinem Arduino Mega Daten an eine C# Anwendung senden. Umgekehrt ist alles OK, und ich kann den Bot über den PC mittels BT steuern. Ich bin immer wieder auf diesen Thread gestossen "http://arduino.cc/forum/index.php/topic,29380.0.html". Er wurde ursprünglich von Poldi gestartet. Er wollte einen Datenlogger auslesen. Das kam meiner Anwendung sehr nahe. Ich möchte Strings an meine C# Anwendung senden. Dort werden sie auf- und weiter verarbeitet. Der Code lt. wie folgt:

    if(Bumper_Front_Left_State == HIGH)
    {
        count++;
        sensor.bumper = BUMPER_FRONT_LEFT;
        if (count == 1)
        Serial.println("10001");
    }
    else count = 0;

mit count stelle ich sicher, dass nur einmal gesendet wird.

Meine C# Anwendung habe ich so geschrieben:

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            int bytesrx = serialPort1.BytesToRead;
            byte[]data = new byte[bytesrx];

                serialPort1.Read(data, 0, bytesrx);
                string botConsoleRX = String.Empty;
                botConsoleRX += Convert.ToString(data[0] - 48) + (data[1] - 48) + (data[2] - 48) + (data[3] - 48) + (data[4] - 48);
                ARDUINO_Value = Convert.ToInt64(botConsoleRX);

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

Ich werte nur die ersten 5 bytes aus. Das Problem sieht aber wie folgt aus: In bytesrx stehen immer andere Werte. Nicht reproduzierbar. Dementsprechend sind auch die weiteren Werte falsch. Was mache ich falsch? Bin noch sehr unsicher in der C# Landschaft.

Gruß Kucky

Hallo Kucky,

Frag besser im DataReceived Event:

string botConsoleRX = serialPort1.ReadExisting();

ab. Das sollte dich weiter bringen als das aktuell empfangende Byte. Allerdings gibt es noch ein paar Dinge, die du dort beachten solltest. Zum Beispiel gibt der Arduino bei Serial.print nur die einzelnen Zeichen und bei Serial.println auch einen Zeilenumbruch mit. Den sollte man abwarten, bis die Daten komplett sind:

private string dataToReceive = string.Empty;
private char lf = (char)10;//Line Feed
private char cr = (char)13;//Carriage Return
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string msg = serialPort1.ReadExisting();
if (!msg.EndsWith(lf,false,System.Globalization.CultureInfo.CurrentCulture))                     
{
    dataToReceive += msg;
}
else
{
    msg = msg.Replace(lf,'');
    try
    {        
        int ARDUINO_Value = Convert.ToInt16(dataToReceive+msg);
    }catch(Exception ex)
    {
       MessageBox.Show(ex.Message, "Konvertierungsfehler");
    }
    dataToReceive = string.Empty; 
}
}

Das geht sicherlich noch eleganter. Habe ich mal kurz zusammengehackt. Da ich nicht weiß ob du "lf" oder "cr" vom Ardu übermittelt bekommst, musst das das noch testen. Enter & Return machen eben programmatisch einen Unterschied...

Hallo Trip, vielen Dank für die schnelle Antwort. Werde es sofort ausprobieren. Kucky

so, habe das eben versucht:

        private string dataToReceive = string.Empty;
        private char lf = (char)10;//Line Feed
        private char cr = (char)13;//Carriage Return

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string msg = serialPort1.ReadExisting();
            if(!msg.EndsWith(lf, false, System.Globalization.CultureInfo.CurrentCulture)) [color=red]// hier Fehler 1[/color]
            {
                    dataToReceive += msg;
            }
            else
            {
            msg = msg.Replace(cr,'');  [color=red]// hier Fehler 2 das sind 2 Hochkommata[/color]
            try
            {        
                int ARDUINO_Value = Convert.ToInt16(dataToReceive+msg);
            }catch(Exception ex)
            {
               MessageBox.Show(ex.Message, "Konvertierungsfehler");
            }
            dataToReceive = string.Empty; 
        }

Fehler 1:Leeres Zeichenliteral.

Fehler 2: Die beste Übereinstimmung für die überladene string.EndsWith(string, bool, System.Globalization.CultureInfo)-Methode hat einige ungültige Argumente. 1-Argument: Kann nicht von "char" in "string" konvertiert werden.

Wie gesagt, ich bin hier nicht Sattelfest. Gruß Kucky

Das mit dem Literal war Blödsinn von mir. Sorry. Hast es ja beschrieben.

so nun habe fertig. Dein Ansatz war genau der Richtige. Ich musste nur 2 Kleinigkeiten ändern.

  1. if(! msg.EndsWith(Convert.ToString(cr), false, System.Globalization.CultureInfo.CurrentCulture)) Hier musste ich erst das Char in einen String konvertieren.
  2. msg = msg.Remove(5); Der Arduino sendet mit println ein '\r' und ein '\n'. Diese beiden werden gelöscht.

Nochmals vielen vielen Dank und schönen Abend. Gruß Kucky

Hallo Kucky,

das freut mich! Mit dem msg.Remove(5) bekommst du dann später aber Probleme, wenn sich die Länge der übermittelten Zeichenfolge ändern sollte. Oder du vielleicht mal Text übermitteln möchtest. Das geht mit Replace("\r\n","") einfacher, finde ich. Oder Replace(cr+ln,"")

Das gehört dann zu den vorausschauenden Programmierungen, weil einen die fehlende Voraussicht später immer bitter wieder einholt ;-) Aber da du ja noch an den Anfängen der C# Programmierung stehst, wird sich das noch einspielen!

Bei Fragen melde dich ruhig!

Hallo Trip, da hast Du recht. Werde das sofort mit einbeziehen. Ich hatte hier nur das Problem, dass der String nachher so "10001\r", bzw "10001\0" aussah, und dann beim Konvertieren Probleme machte.

Hallo Trip, habe wie, wie angedroht, Deinen Rat befolgt. War ein sehr guter Hinweis, um die ganze Sache generischer zu machen. Ich wollte ursprünglich Daten und Commandos zwischen meinen Bot und der Console übertragen. Dank Deiner Hilfe geht das nun auch. Habe den Code ein klein bisschen geändert und siehe da, alles OK.

       private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            ARDUINO_Command = string.Empty;
            ARDUINO_Value = 0;
            string msg = serialPort1.ReadExisting();  
            if (!msg.EndsWith(Convert.ToString(cr), false, System.Globalization.CultureInfo.CurrentCulture))
            {
                dataToReceive += msg; 
            }
            else
            {
                msg = msg.Replace(Convert.ToString(cr), "" );                
                try
                    {
                        int number;
                        value_receive = Int32.TryParse(msg, out number);
                        if (value_receive)
                        {
                            ARDUINO_Value = Convert.ToUInt32(dataToReceive + msg);
                        }
                        else
                        {
                            ARDUINO_Command += msg;
                            value_receive = false;
                        }
                    }
                catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "Konvertierungsfehler");
                    }

                dataToReceive = string.Empty;
                msg = string.Empty;
             }

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

Seltsam ist nur, dass beim Debugging die Varialble "dataToReceive" immer "", also leer bleibt.

Noch einen schönen Sonntag

Nachtrag:

if (!msg.EndsWith(Convert.ToString(cr), false, System.Globalization.CultureInfo.CurrentCulture))
            {
              dataToReceive += msg; // Hier kommt das Programm lt. Debugger nie hin.
            }

Hallo kucky,

das ist nicht so wild. Der Serielle Controller bekommt die Daten übermittelt und reicht diese dann in einem Rutsch weiter durch. Wenn nun sehr viele Daten übermittelt werden oder schnell hintereinander, dann werden diese prozedural abgearbeitet und es kann dazu kommen, dass die Daten in mehrere Blöcke aufgeteilt werden. In diesem Fall werden die aber dann wieder zusammengesetzt.

Hallo Trip, danke für die Antwort. Um das genau zu verstehen, brauche ich noch was. Der Sinn ist mir aber klar, so dass ich mit meinem Projekt jetzt weiter komme. Wenn ich nicht mehr weiter weis, poste ich wieder. :)

Gruß aus Leverkusen Kucky

Hallo Trip, ich hatte je gesagt, dass ich mich wieder melde. Also es funktioniert sehr gut, aber leider nur im Debug Modus von C#. Ich habe folgenden Code ausprobiert:

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        string dataToReceive = string.Empty;
        char cr = (char)13; //Carriage Return
        ARDUINO_msg = serialPort1.ReadExisting();

        if (!ARDUINO_msg.EndsWith(Convert.ToString(cr), false, System.Globalization.CultureInfo.CurrentCulture))
        {
            dataToReceive += ARDUINO_msg;              
        }
        else
        {
            ARDUINO_msg = ARDUINO_msg.Replace(Convert.ToString(cr), "");                
        }
        this.BeginInvoke(new EventHandler(DoUpdate));  [color=red]// Ich denke es liegt hieran[/color]
  
            serialPort1.DiscardInBuffer();
    }
//-----------------------------------------------------------------------------
private void DoUpdate(object s, EventArgs e)
    {
        value_receive = UInt32.TryParse(ARDUINO_msg, out ARDUINO_Value);
        if (value_receive)    // if there ist a number...
        {
            evaluate_value();
        }
        else
        {
            evaluate_message();
        }
    }
//-----------------------------------------------------------------------------
private void evaluate_message()
    {
        if (ARDUINO_msg == "BumperFrontLeft")
            Bumper_front_left_selected();    // Hier wird z.B. " this.pct_bumper_front_left.Visible = true;" aufgerufen
        else if (ARDUINO_msg == "BumperFrontRight")
            Bumper_front_right_selected(); 
        else if (ARDUINO_msg == "BumperBackLeft")
            Bumper_back_left_selected();
        else if (ARDUINO_msg == "BumperBackRight")
            Bumper_back_right_selected();
    }

Im normalen Modus, werden die Steuerelemente nicht wie gewünscht verändert. Habe mir nun Lektüre bestellt, um C# selbst zu lernen. Ich benötige aber das Programm derzeit schon für mein Arduino-Projekt. Gruß Willi Kannst Du auch hier helfen?

ich bin noch weiter gekommen. Mit…
Debug.WriteLine(ARDUINO_msg);

bin ich dahinter gekommen, dass das erste Zeichen im Realteimemodus “verschluckt” wird. Weiß jemand Rat?
LGW