Forum: PC-Programmierung C# Bytes von einem Arduino über die serielle Schnittstelle auslesen


von Jannick K. (jannick)


Angehängte Dateien:

Lesenswert?

Guten Tag,

der PC ist mit einem Arduino Mega 2560 verbunden.
Der Arduino sendet alle 2 Sekunden eine 6 Byte lange Nachrricht über die 
Seriel Schnittstelle an den PC.

Die 6 Bytes sollen in 6 Textboxen anzeigen werden. -> Byte 1 = Textbox 3 
usw.

Ich habe versucht dies mit der Methode DataReceivedHandler zu 
realisieren.
Jedoch kommt nach dem starten des Programms die Fehlermeldung (siehe 
Bild):

"Ein Ausnahmefehler des Typs "System.InvalidOperationException" ist in 
System.Windows.Forms.dll aufgetreten.
Zusätzliche Informationen: Ungültiger threadübergreifender Vorgang: Der 
Zugriff auf das Steuerelement textBox3 erfolgte von
einem anderen Thread als dem Thread, für den es erstellt wurde."

Was kann man unternehmen das in der Funktion DataReceivedHandler die 
Daten über die Textboxen ausgegeben werden kann.

Hier noch mein Code:
1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Data;
5
using System.Drawing;
6
using System.Linq;
7
using System.Text;
8
using System.Threading.Tasks;
9
using System.Windows.Forms;
10
using System.IO.Ports;
11
12
namespace Serial_Communication
13
{
14
    public partial class Form1 : Form
15
    {
16
        public Form1()
17
        {
18
            InitializeComponent();
19
            getAvailablePorts();
20
        }
21
22
        void getAvailablePorts()
23
        {
24
            String[] ports = SerialPort.GetPortNames();
25
            comboBox1.Items.AddRange(ports);
26
        }
27
28
        private void Form1_Load(object sender, EventArgs e)
29
        {
30
31
        }
32
33
        private void button3_Click(object sender, EventArgs e)
34
        {
35
36
37
            serialPort1.PortName = comboBox1.Text;
38
            serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
39
            serialPort1.Open();
40
            serialPort1.DtrEnable = true;
41
            serialPort1.RtsEnable = true;
42
            serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
43
44
            button3.Enabled = false;
45
            button4.Enabled = true;
46
        }
47
48
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
49
        {
50
            
51
            byte[] data = new byte[6];
52
            serialPort1.Read(data, 0, 6);
53
            
54
            textBox3.Text = Convert.ToString(data[0]);
55
            textBox4.Text = Convert.ToString(data[1]);
56
            textBox5.Text = Convert.ToString(data[2]);
57
            textBox6.Text = Convert.ToString(data[3]);
58
            textBox7.Text = Convert.ToString(data[4]);
59
            textBox8.Text = Convert.ToString(data[5]);
60
61
        }
62
        
63
        private void button4_Click(object sender, EventArgs e)
64
        {
65
            serialPort1.Close();
66
            button3.Enabled = true;
67
            button4.Enabled = false;
68
            
69
        }
70
    }
71
}

Vielen Dank für Ihre Hilfe.

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Ungültiger threadübergreifender Vorgang

suche doch einfach mal Google mach danach. Bei C# darf man die GUI nur 
aus dem Hauptthread ansprechen. Die Events der Seriellen Schnittstelle 
laufen aber in einem Extra Thread.

Du musst mit "Delegate" und "Invoke" arbeiten.

von Jannick K. (jannick)


Lesenswert?

Ich hab Google bemüht und meinen Code erweitert (Hier nur ein Auszug der 
Erweiterten Zeilen):
1
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
2
        {    
3
            serialPort1.Read(Addata, 0, 6);
4
            this.Invoke(new EventHandler(DisplayText));
5
        }
6
7
        private void DisplayText(object sender, EventArgs e)
8
        {
9
            textBox3.Text = Convert.ToString(Addata[0]);
10
            textBox4.Text = Convert.ToString(Addata[1]);
11
            textBox5.Text = Convert.ToString(Addata[2]);
12
            textBox6.Text = Convert.ToString(Addata[3]);
13
            textBox7.Text = Convert.ToString(Addata[4]);
14
            textBox8.Text = Convert.ToString(Addata[5]);
15
        }

Die Ausgabe Funktioniert jetzt auch. Jedoch sind die ankommenden Daten 
nicht nicht korrekt.

Wie ich bereits erwähnt habe besteht meine Nachricht aus 6 Byte:
1 Byte = konstanter Wert (255)
2 Byte = konstanter Wert (170)
3 Byte = variabler  Wert (0-254)
4 Byte = konstanter Wert (238)
5 Byte = variabler  Wert (0-254)
6 Byte = konstanter Wert (10)

Prinzipiell müssten sich ja lediglich die Werte 3 und 5 in den Textboxen 
ändern. Bei meiner Anzeige jedoch wird beispielsweise das erste Byte mit 
dem Wert 255 nicht angezeigt.

In den Textboxen 1-4 werden für mich nicht nachvollziehbare Werte 
angezeigt.

Ich geh doch recht in der Annahme, dass wenn der Arduino die Nachricht 
verschickt hat der DataReceivedHandler aktiv wird die 6 Byte ausliest 
und dann die Textboxen aktualisiert?

Woher könnte es rühren, dass die Bytes nicht in der gewünschten 
Reihenfolge angezeigt werden?

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Woher könnte es rühren, dass die Bytes nicht in der gewünschten
> Reihenfolge angezeigt werden?

weil es überhaupt nicht definiert ist, was der 1.Byte ist. Wenn du das 
erste Byte verpasst, wird das 2.Byte zu ersten Byte.

Was wird dann wirklich übertragen?

binary Daten oder Text? gibt es eine Protokoll?

> serialPort1.Read(Addata, 0, 6);
ist außerdem falsch, wenn keine 6 Bytes ankommen, musst du auch den 
return-wert auswerten, dort steht drin wie viele Daten Empfangen wurden.

Es könnte also sein, das für jedes Byte das Event kommmt.

von Jannick K. (jannick)


Lesenswert?

Peter II schrieb:
> Jannick K. schrieb:
>> Woher könnte es rühren, dass die Bytes nicht in der gewünschten
>> Reihenfolge angezeigt werden?
>
> weil es überhaupt nicht definiert ist, was der 1.Byte ist. Wenn du das
> erste Byte verpasst, wird das 2.Byte zu ersten Byte.
>
> Was wird dann wirklich übertragen?
>
> binary Daten oder Text? gibt es eine Protokoll?

Das Protokoll ist oben Beschrieben. Eine Nachricht besteht immer aus 6 
Bytes. Es werden binäre Daten übertragen. Das 1. Byte hat immer den Wert 
255 usw...

Wie kann ich den das erste Byste verpassen?? Der Pc bekommt alle 2 
Sekunden eine Nachricht vom Arduino. Dadurch müsste doch der Event 
Handler getriggert werden und somit diese 6 Bytes auslesen.

>
>> serialPort1.Read(Addata, 0, 6);
> ist außerdem falsch, wenn keine 6 Bytes ankommen, musst du auch den
> return-wert auswerten, dort steht drin wie viele Daten Empfangen wurden.
>
> Es könnte also sein, das für jedes Byte das Event kommmt.

Habe mir in hterm die ankommenden Daten angeschaut und es sind immer 6 
Byte.
Wie ist es möglich den return-wert von der Read() Methode auszuwerten?

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Das Protokoll ist oben Beschrieben. Eine Nachricht besteht immer aus 6
> Bytes. Es werden binäre Daten übertragen. Das 1. Byte hat immer den Wert
> 255 usw...

oh hatte ich übersehen.

Dann ist es am einfachsten, die Bytes einzeln zu lesen.

Nur schnell getippt, es werden noch fehler drin sein
1
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
2
{
3
   static int DataPos = -1;
4
   static int[] data = int[5];
5
6
   int cnt = serialPort1.BytesToRead();
7
   for( int i = 0; i < cnt; ++ i ) {
8
      Byte b = SerialPort.ReadByte();
9
      if ( b == 255 ) {
10
         DataPos = 0;
11
         continue;
12
      };
13
14
      if ( DataPos >= 0 ) {
15
         data[DataPos] = b;
16
         DataPos++;
17
      };
18
19
      if ( DataPos == 6 ) {
20
         //todo Gui aktualisieren
21
         DataPos = -1;
22
      };
23
}

Jannick K. schrieb:
> Wie kann ich den das erste Byste verpassen?? Der Pc bekommt alle 2
> Sekunden eine Nachricht vom Arduino. Dadurch müsste doch der Event
> Handler getriggert werden und somit diese 6 Bytes auslesen.

in dem z.b. das Kabel nicht am PC steckt und erst beim 2 Byte angesteckt 
wird.

> Habe mir in hterm die ankommenden Daten angeschaut und es sind immer 6
> Byte.
das kann man nicht sehen

von Thorsten (Gast)


Lesenswert?

Hi,

dein Andurino und PC sind halt nicht synchron. Ich würde dein Protokoll 
noch etwas optimieren, damit gehst Du auf Nummer sicher, eventuell ist 
auch ein Alive-Signal von deinem Andurino hilfreich, welches z.B. jede 
Sekunde gesendet werden muss, wenn Du das Alivesignal nicht innerhalb 
deiner Timeoutzeit erhälst, dann ist die Verbindung unterbrochen oder 
dein Andurino hängt.

Protokollvorschlag:
StartByte, CRC, Datalength, Data's, EndByte

Dein StartByte etc. sollte natürlich nicht in der Rangevon den Nutzdaten 
liegen, aber Du kannst dich an der ASCII Tabelle orientieren.

http://www.torsten-horn.de/techdocs/ascii.htm

StartByte z.B. 0x02 und EndByte 0x03, wenn Du verschlüsselte Daten 
benötigst gibt es natütlich andere Möglichkeiten.

Das Beispiel von PeterII ist nicht schlecht, aber ich würde die Daten 
einfach in ein Buffer schreiben und die Auswertung außerhalb des Events 
tätigen.

von Jannick K. (jannick)


Lesenswert?

Erstmal vielen Danke für Eure Hilfe :).

Ich hab das Programm so angepasst, dass es jetzt immer die 6 Bytes aus 
dem Eingangspuffer ausliest und mir in den Textboxen darstellt. Hierfür 
wird das Globale Daten Array für 6 Bytes genutzt.
1
public partial class Form1 : Form
2
    {
3
        byte[] DataBuffer = new byte[6];
4
5
6
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
7
        {
8
            int bytes = serialPort1.BytesToRead;
9
            int i =0 ;
10
            for (i = 0; i < 6; ++i)                    //ReadBufferSize = Ruft die Größe des SerialPort - Eingabepuffers ab oder legt diese fest.
11
            {
12
                int b = serialPort1.ReadByte();        //Liest synchron ein Byte aus dem Serialport Eingabepuffer
13
                DataBuffer[i] = Convert.ToByte(b);
14
            }
15
            this.BeginInvoke(new EventHandler(DisplayText));
16
17
        }
18
        private void DisplayText(object sender, EventArgs e)
19
        {
20
            textBox3.Text = Convert.ToString(DataBuffer[0]);
21
            textBox4.Text = Convert.ToString(DataBuffer[1]);
22
            textBox5.Text = Convert.ToString(DataBuffer[2]);
23
            textBox6.Text = Convert.ToString(DataBuffer[3]);
24
            textBox7.Text = Convert.ToString(DataBuffer[4]);
25
            textBox8.Text = Convert.ToString(DataBuffer[5]);
26
        }

Der EventHandler wird nur genutzt um die 6 Bytes in das Array zu 
schreiben. Die Nachfolgende Weiterverarbeitung soll außerhalb des Events 
statt finden.

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Ich hab das Programm so angepasst, dass es jetzt immer die 6 Bytes aus
> dem Eingangspuffer ausliest und mir in den Textboxen darstellt. Hierfür
> wird das Globale Daten Array für 6 Bytes genutzt.

du hast leider viel von dem wichtigen code entfernt und neue fehler 
eingebaut (auch wenn es eventuell funktioniert)

Man liest im Event nur so viele Daten wie vorhanden sind. Aus dem grunde 
wurde vorher BytesToRead abgefragt.

Man Prüft ob das Startbyte auch das Startbyte ist.

Dein Programm kommt durch einander, wenn die Kommunikation mal 
unterbrochen ist. Warum hast du es nicht 1:1 übernommen und nur 
eventuell Fehler entfernt?

von Jannick K. (jannick)


Lesenswert?

Als ich Ihren Code verwendet habe, hat sich der erste Variablen wert 
nach ca 4-6 Sekunden verändert und der zweite variable Wert nach ca. 
10-20 Sekunden.
Das Verstehe ich nicht, da der Arduino alle 2 Sekunden die beiden Werte 
ändert. Haben Sie evtl eine Vermutung woher die Verzögerung kommt?
Prinzipiell müssten sich doch jedesmal nach 2 Sekunden 6 Bytes im 
Eingangspuffer befinden die ausgelesen werden könnten oder liege ich 
hier falsch?

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Als ich Ihren Code verwendet habe, hat sich der erste Variablen wert
> nach ca 4-6 Sekunden verändert und der zweite variable Wert nach ca.
> 10-20 Sekunden.

keine Ahnung, dafür gibt es den Debugger. Eventuell ist noch ein Fehler 
drin.

du kannst doch einfach mal eine Debugausgabe machen, wenn die 255 
empfangen wird.
1
 if ( b == 255 ) {
2
         DataPos = 0;
3
         System.Diagnostics.Debug.WriteLine("255 empfangen");
4
         continue;
5
      };

dann sollte aller 6 Sekunden diese ausgabe kommen.

von Jannick K. (jannick)


Lesenswert?

Es kommt alle 2 Sekunden "255 empfangen".
Ich hab mir auch mal die Werte von dem Ausschnitt:
1
if (DataPos >= 0)
2
{
3
    DataBuffer[DataPos] = Convert.ToByte(b);
4
    System.Diagnostics.Debug.WriteLine(b);
5
    DataPos++;
6
}

anzeigen gelassen. Hier ist ein Ausschnitt hiervon:
1
255 empfangen
2
0
3
2
4
238
5
250
6
10
7
255 empfangen
8
170
9
8
10
238
11
255 empfangen
12
170
13
255 empfangen
14
170
15
20
16
238
17
232
18
10
19
255 empfangen

Ist es möglich das die Daten vom Arduino zu schnell ankommen und mein 
Programm nicht die nötige Zeit hat diese zu verarbeiten? Oben sieht man 
das selten alle 5 Bytes nach dem Start Byte auftauchen.

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Ist es möglich das die Daten vom Arduino zu schnell ankommen und mein
> Programm nicht die nötige Zeit hat diese zu verarbeiten?
wenn du nicht gerade vor einem alten 486 sitzt - nein

> Oben sieht man das selten alle 5 Bytes nach dem Start Byte auftauchen.
Bist du sicher das dein Arduino richtig sendet?

Prüfe erst mal mit einen andere Programm

http://realterm.sourceforge.net/

von Jannick K. (jannick)


Angehängte Dateien:

Lesenswert?

Ja der Arduino sendet Richtig.
Im Anhang finden Sie mal ein Ausschnitt.

Ich Verwende ein Globales Array in das die Werte rein geschrieben 
werden.
Die Textboxen werden anhand eines Timers aktualisiert. Der Timer ist auf 
ein Intervall von 1 Sekunde eingestellt.

Könnte hier etwas schief laufen?

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Könnte hier etwas schief laufen?

eigentlich nicht, wenn schon die debug ausgaben fehlerhaft sind stimmt 
etwas anderes nicht.

Kannst du mal den aktuellen code zeige, der die Ausgaben mit den lücken 
ezeugt hat?

von Jannick K. (jannick)


Lesenswert?

Klar. Das hat die Ausgabe ausgegeben:
1
public partial class Form1 : Form
2
    {
3
        byte[] DataBuffer = new byte[6];
4
        
5
       
6
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
7
        {
8
            int DataPos = -1;
9
            int bytes = serialPort1.BytesToRead;
10
11
            for (int i = 0; i < bytes; ++i)                
12
            {
13
                int b = serialPort1.ReadByte();            
14
                if (b == 255)
15
                {
16
                    DataPos = 0;
17
                    System.Diagnostics.Debug.WriteLine("255 empfangen");
18
                    continue;
19
                }
20
                if (DataPos >= 0)
21
                {
22
                    DataBuffer[DataPos] = Convert.ToByte(b);
23
                    System.Diagnostics.Debug.WriteLine(b);
24
                    DataPos++;
25
                }
26
                if (DataPos == 6)
27
                {
28
                    DataBuffer[DataPos] = Convert.ToByte(b);
29
                    DataPos = -1;
30
                }
31
32
            }
33
        }
34
35
        private void timer2_Tick(object sender, EventArgs e)
36
        {
37
            textBox3.Text = Convert.ToString(DataBuffer[0]);
38
            textBox4.Text = Convert.ToString(DataBuffer[1]);
39
            textBox5.Text = Convert.ToString(DataBuffer[2]);
40
            textBox6.Text = Convert.ToString(DataBuffer[3]);
41
            textBox7.Text = Convert.ToString(DataBuffer[4]);
42
        }

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Klar. Das hat die Ausgabe ausgegeben:

sieht richtig aus, wenn auch noch etwas umständlich.

wenn du
1
byte b = serialPort1.ReadByte();

verwendest, kannst du dir das ganze Convert sparen.

Teste mal nur mit debug
1
 private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
2
        {
3
            int bytes = serialPort1.BytesToRead;
4
            for (int i = 0; i < bytes; ++i)                
5
            {
6
                Byte b = serialPort1.ReadByte();            
7
                System.Diagnostics.Debug.WriteLine(b);
8
            }
9
        }

von Jannick K. (jannick)


Lesenswert?

Peter II schrieb:
> Jannick K. schrieb:
>> Klar. Das hat die Ausgabe ausgegeben:
>
> sieht richtig aus, wenn auch noch etwas umständlich.
>
> wenn du
>
>
1
> byte b = serialPort1.ReadByte();
2
>
>
> verwendest, kannst du dir das ganze Convert sparen.
>
Dachte ich mir auch schon. Jedoch will er das nicht... Es kommt ein 
Fehler mit "Der Typ int kann nicht implizit in byte konvertiert werden"

> Teste mal nur mit debug

Wenn ich das Teste sieht es richtig gut aus. Hier mal ein Auszug:
1
255
2
0
3
2
4
238
5
250
6
10
7
8
255
9
170
10
8
11
238
12
244
13
10
14
15
255
16
170
17
14
18
238
19
238
20
10
21
22
255
23
170
24
20
25
238
26
232
27
10

von Jannick K. (jannick)


Lesenswert?

Darum hab ich mir überlegt im Event Handler nur die Bytes in ein Array 
zu schreiben und die Auswertung sprich Startbyte prüfen usw in einer 
anderen Funktion.

von Peter II (Gast)


Lesenswert?

ich sehe den fehler.

 int DataPos = -1;

darf nicht in der Funktion angelegt werden! mache es mal global. (ich 
hatte es extra static gemacht - aber das geht so in C# nicht)
1
 if (DataPos == 6)
2
                {
3
                    DataBuffer[DataPos] = Convert.ToByte(b);
4
                    DataPos = -1;
5
              }

die Zuweisung  DataBuffer[DataPos] = Convert.ToByte(b);
 ist hier zu viel. Das wurde schon gemacht. An dieser stelle must du die 
GUI ansprechen, weil ein Datensatz vollständig ist.

von Jannick K. (jannick)


Lesenswert?

Es läuft!! Top. Vielen Dank für deine Zeit und mühe mir dabei zu helfen.

Würdest du mir evtl noch erklären warum es einen "so großen" unterschied 
macht ob ich DataPos Global oder in der Funktion anlege?

von Peter II (Gast)


Lesenswert?

Jannick K. schrieb:
> Würdest du mir evtl noch erklären warum es einen "so großen" unterschied
> macht ob ich DataPos Global oder in der Funktion anlege?

wie schon oben geschrieben, kann man vorher nicht wissen wie viele Daten 
auf einmal in dem Event geliefert werden. Es kann passieren, das 6 
Events für 6 Byte kommen, oder es kommt 1 Event mit 6 Bytes.

Aus dem Grund darf der Zähler nicht wieder bei -1 beginnen, wenn die 
Funktion verlassen wird.

Jetzt kannst du auch deinen Timer loswerden, in dem du per invoke die 
GUI aufrufst.

von Jannick K. (jannick)


Lesenswert?

Alles klar werde ich machen!!! Kann mich nur nochmals bedanken. Fühl 
dich auf ein Bier eingeladen :D

von Draco (Gast)


Lesenswert?

Was ist... wenn einer deiner Daten mal den Wert 255 hat? Wie fängst du 
das ab?

Ich löse das übrigens immer so - das ganze lasse ich über einen extra 
Thread laufen und gut. Vorausgesetzt natürlich ein linetermination:
1
byte[] inchar = new byte[32];
2
3
public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
4
{
5
      //Redirecting Serial Port for Atomic Protection
6
      SerialPort sp = (SerialPort)sender;
7
      
8
      //Read full Buffer to string
9
      string indata = sp.ReadExisting();      
10
      
11
      //Convert string to global Array  
12
      inchar = indata.ToArray();
13
}

von Peter II (Gast)


Lesenswert?

Draco schrieb:
> Was ist... wenn einer deiner Daten mal den Wert 255 hat? Wie fängst du
> das ab?
muss er gar nicht, es laut Protokoll kommt das nicht vor.


> Ich löse das übrigens immer so - das ganze lasse ich über einen extra
> Thread laufen und gut. Vorausgesetzt natürlich ein linetermination:
bei dir sind aber auch böse Fallstricke drin
1
 string indata = sp.ReadExisting();

Das arbeiten mit String ist hier falsch, dabei wird eine 
Zeichensatzkodierung vorgenommen. damit versaut man sie die Daten.

Das mit den Extra Thread kann durchaus hilfreich sein, aber intern macht 
der SerialPort auch nichts anderes. Hier bringt es zumindest keine 
Vorteile.

von Draco (Gast)


Lesenswert?

Peter II schrieb:
> Draco schrieb:
>> Was ist... wenn einer deiner Daten mal den Wert 255 hat? Wie fängst du
>> das ab?
> muss er gar nicht, es laut Protokoll kommt das nicht vor.

Achso... ja die Liste oben habe ich jetzt erst gesehen. Dann passt das 
ja.

Peter II schrieb:
> Das arbeiten mit String ist hier falsch, dabei wird eine
> Zeichensatzkodierung vorgenommen. damit versaut man sie die Daten.

Wieso sollte da eine Kodierung stattfinden? Ein String ist im Grunde 
auch "bloß" ein Array aus Zeichen. Wenn in einem Byte in einem String 
0x4B steht dann steht da auch eine 0x4B oder ein DEC 113, ein OCT 61 
oder eben ein ASCII "K" - komme was wolle. "Konvertiert" in ein ASCII 
wird es ja erst bei Rückgabe/Ausgabe.

Peter II schrieb:
> Das mit den Extra Thread kann durchaus hilfreich sein, aber intern macht
> der SerialPort auch nichts anderes. Hier bringt es zumindest keine
> Vorteile.

Echt? Danke, das wusste ich nicht - habe ich auch noch nie beobachtet um 
genau zu sein.

von Peter II (Gast)


Lesenswert?

Draco schrieb:
> Wieso sollte da eine Kodierung stattfinden? Ein String ist im Grunde
> auch "bloß" ein Array aus Zeichen. Wenn in einem Byte in einem String
> 0x4B steht dann steht da auch eine 0x4B oder ein DEC 113, ein OCT 61
> oder eben ein ASCII "K" - komme was wolle. "Konvertiert" in ein ASCII
> wird es ja erst bei Rückgabe/Ausgabe.

nicht bei C#!

Da muss die Encoding Eigenschaft vom SerialPort richtig setzen. In C# 
ist jeder String eine UTF8 String. Alles was nicht ASCII ist, wird 
umgewandelt in mehr als ein Byte.

Damit kommt bei Sonderzeichen bei dir Unsinn raus. Es gibt nicht ohne 
Grund auch die Read-Methoden die ein Byte Array auslesen. String ist 
wirklich nur die Text gedacht.

von Eric B. (beric)


Lesenswert?

Jannick K. schrieb:
> Hier ist ein Ausschnitt hiervon:
> 255 empfangen
> 0
> 2
> 238
> 250
> 10
--> da war die 1. Nachricht

> 255 empfangen
> 170
> 8
> 238
> 255 empfangen
> 170
--> Da war die 2. Nachricht

> 255 empfangen
> 170
> 20
> 238
> 232
> 10
--> Da war die 3. Nachricht.

> 255 empfangen
>
> Ist es möglich das die Daten vom Arduino zu schnell ankommen und mein
> Programm nicht die nötige Zeit hat diese zu verarbeiten? Oben sieht man
> das selten alle 5 Bytes nach dem Start Byte auftauchen.

Wie? Ich sehe 3 wunderbare 6-byte große Nachrichten. Nur dumm, dass der 
255-Marker auch als Data in der NAchricht auftauchen kann, eh?

von Draco (Gast)


Lesenswert?

Eric B. schrieb:
> Wie? Ich sehe 3 wunderbare 6-byte große Nachrichten. Nur dumm, dass der
> 255-Marker auch als Data in der NAchricht auftauchen kann, eh?

Kann nicht passieren:

Jannick K. schrieb:
> Wie ich bereits erwähnt habe besteht meine Nachricht aus 6 Byte:
> 1 Byte = konstanter Wert (255)
> 2 Byte = konstanter Wert (170)
> 3 Byte = variabler  Wert (0-254)
> 4 Byte = konstanter Wert (238)
> 5 Byte = variabler  Wert (0-254)
> 6 Byte = konstanter Wert (10)

von Peter II (Gast)


Lesenswert?

Eric B. schrieb:
> Nur dumm, dass der
> 255-Marker auch als Data in der NAchricht auftauchen kann, eh?

bitte alles lesen! Er kann nicht auftauchen, es war noch ein Fehler im 
code der schon lange behoben wurde.

von Eric B. (beric)


Lesenswert?

Peter II schrieb:
> Eric B. schrieb:
>> Nur dumm, dass der
>> 255-Marker auch als Data in der NAchricht auftauchen kann, eh?
>
> bitte alles lesen! Er kann nicht auftauchen, es war noch ein Fehler im
> code der schon lange behoben wurde.

Ich habe alles gelesen. Wer sagt mir, dass da nicht noch mehr Fehler 
drinne sind?

Entweder verliert er tatsächlich Bytes, oder die Annahme über das Format 
stimmt nicht. Im minimalen Log-Abschnitt kamen die 255'er aber ganz 
schön im 6-Byte Takt, nur die andere Bytes hielten sich nicht an der 
Spec:

> 1 Byte = konstanter Wert (255)
> 2 Byte = konstanter Wert (170)
> 3 Byte = variabler  Wert (0-254)
> 4 Byte = konstanter Wert (238)
> 5 Byte = variabler  Wert (0-254)
> 6 Byte = konstanter Wert (10)

von Peter II (Gast)


Lesenswert?

Eric B. schrieb:
> Ich habe alles gelesen. Wer sagt mir, dass da nicht noch mehr Fehler
> drinne sind?

Der Text z.b.

> Es läuft!! Top.

von Draco (Gast)


Lesenswert?

Der feste Rhytmus kommt doch nun:

-255  Start
-170
-n
-238
-n
-10   Ende

...

-255  Start
-170
-n
-238
-n
-10   Ende

...

-255  Start
-170
-n
-238
-n
-10   Ende

von Jannick K. (jannick)


Lesenswert?

Es ist ein fester Rhythmus aus Bytes die alle 2 Sek vom Arduino 
geschickt werden. Das letzte Byte was in meinen Ausschnitten immer den 
festen Wert von (Dec = 10) hatte hab ich noch in eine CheckSumme 
umgewandelt. Sprich der Aufbau des Protokolls sieht wie folgt aus:

1 Byte = konstanter Wert (255)
2 Byte = konstanter Wert (170)
3 Byte = variabler  Wert (0-254)
4 Byte = konstanter Wert (238)
5 Byte = variabler  Wert (0-254)
6 Byte = CheckSumme Wert ((2 Byte + 3 Byte + 4 Byte + 5 Byte)/4).

Sprich der Arduino berechnet die Checksumme und schickt sie mit und auf 
dem Pc rechne ich die Checksumme der ankommenden Daten aus. Beide werden 
dann vergleichen. Somit habe ich noch eine Absicherung eingebaut.

Das Programm läuft auch stabil habe es heute über 40 Min laufen lassen 
ohne das Fehler aufgetreten sind.

: Bearbeitet durch User
von Georg (Gast)


Lesenswert?

Jannick K. schrieb:
> Das Programm läuft auch stabil habe es heute über 40 Min laufen lassen
> ohne das Fehler aufgetreten sind.

Schön. Du musst aber auf jeden Fall dafür sorgen, dass das System nach 
einem Fehler wieder in Tritt kommt, die Voraussetzung ist ja gegeben, da 
das Protokoll mit 255 anfängt. Wenn du also die Receivefunktion 
aufrufst, muss die alles verwerfen bis ein 255 kommt, und dann 6 Bytes 
einlesen.

Georg

von Peter II (Gast)


Lesenswert?

Georg schrieb:
> Schön. Du musst aber auf jeden Fall dafür sorgen, dass das System nach
> einem Fehler wieder in Tritt kommt, die Voraussetzung ist ja gegeben, da
> das Protokoll mit 255 anfängt. Wenn du also die Receivefunktion
> aufrufst, muss die alles verwerfen bis ein 255 kommt, und dann 6 Bytes
> einlesen.

genau das haben wir doch gemacht? Hast du überhaupt die Kommentare 
gelesen?

von Thorsten (Gast)


Lesenswert?

>1 Byte = konstanter Wert (255)
>2 Byte = konstanter Wert (170)
>3 Byte = variabler  Wert (0-254)
>4 Byte = konstanter Wert (238)
>5 Byte = variabler  Wert (0-254)
>6 Byte = CheckSumme Wert ((2 Byte + 3 Byte + 4 Byte + 5 Byte)/4).

Sieht echt gut aus, falls Du auf der PC Seite noch kein Fehlerhändling 
drin hast, dann empfehle ich Dir noch einen Timeout mit einzufügen, z.B. 
nach >4 Sekunden keine Empfangssequenz eine interne Fehlermeldung.

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.