Laden...

SerialPort: Daten müssen häppchenweise gelesen werden

Erstellt von Fabian_81 vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.567 Views
F
Fabian_81 Themenstarter:in
37 Beiträge seit 2008
vor 14 Jahren
SerialPort: Daten müssen häppchenweise gelesen werden

Moin,

mein Mikrocontroller sendet mir 47 Bytes Daten zum PC. Dort nutze ich ein c#-Programm zum Einlesen. Folgenden Code nutze ich:


        private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort port = (SerialPort)sender;
            byte[] buffer = new byte[1024];
            int i = 0;

            System.Threading.Thread.Sleep(500);            
            
            while (port.BytesToRead > 0)
            {
                int b = 0;
                if ((b = port.ReadByte()) != -1)
                {
                    buffer[i] = (byte)b;
                    i++;
                }
                else
                    break;
            }

            byte command = 0x00;
            byte[] packet = new byte[i - 1];
            command = buffer[0];                        // sichern des ersten Bytes (Befehl)
            Array.Copy(buffer, 1, packet, 0, i - 1);    // kopieren des Rests in packet

            Decode_Received_UART(command, packet);
        }

Nun ist es leider so, dass teilweise irgendwie nicht alle Daten auf einmal ankommen. Die Routine springt an, aber es sind z.B. nur 46 Bytes da... Das letzte folgt dann erst beim nächsten Aufruf der oben gezeigten Routine. Den Sleep-Befehl hab ich schon dort drin, weil er sonst noch viel weniger Daten empfängt. Kann das sein, dass irgendein Puffer voll ist oder so?

Danke und viele Grüße!

S
8.746 Beiträge seit 2005
vor 14 Jahren

Es gibt auf der seriellen Schnittstelle keine Pakete. Du musst deinen Code entsprechend bauen, dass er damit zurechtkommt, dass die Daten in beliebiger "Zerteilung" eintrudeln.

Das Sleep kannste rausnehmen, es kann das Verhalten nicht verhindern.

BTW: Du solltest anstelle der Schleife mit SerialPort.Read arbeiten.

Ansonsten hier schauen:

http://blogs.msdn.com/bclteam/archive/2006/10/10/Top-5-SerialPort-Tips-5B00_Kim-Hamilton_5D00.aspx

888 Beiträge seit 2007
vor 14 Jahren

Hallo,

1.
Es ist normal, dass man nie weiss was, wann von der Schnittstelle kommt.

2.
Du wirst sehen, dass wenn Du den Sleep-Wert erhöhst auch gute Ergebnisse
erzeilen wirst. Das ist aber sehr unsauber, da nicht logisch gelöst.
Es ist besser auf eine Abbruchbedingung zu prüfen, wie das geht kannst du Dir z.B.
hier angucken:

Template SerialPort

F
Fabian_81 Themenstarter:in
37 Beiträge seit 2008
vor 14 Jahren

Guten Morgen!

Alles klar, danke! Problem ist, dass ich keine ASCII-Zeichen sende sondern Bytes, die alle Werte zwischen 0x00 und 0xFF annehmen können. daher sieht es mit der Abbruchbedingung schlecht aus. Ich habe es nun folgendermaßen umgesetzt. Ich sende 47 Bytes:

Byte[0] : Kommando ()
Byte[1] : Anzahl der folgenden Daten
Byte[2] : Erstes Datenbyte
|
|
|
Byte[46] : Letztes Datenbyte

Und diese gesendeten Bytes empfange ich auf dem PC folgendermaßen:


private void readDataFromSerialPort(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                this.bytes_to_read = this.serialPort.BytesToRead;
                this.bytes_received += this.bytes_to_read;

                this.dataToRecieve += this.serialPort.ReadExisting();
                byte[] buffer = new byte[bytes_to_read];
                buffer = StringToByteArray(this.dataToRecieve);

                if (this.length_byte_read == false)
                {
                    this.length_byte = buffer[1];
                    this.length_byte_read = true;
                }

                if (this.bytes_received == this.length_byte)
                {
                    byte[] packet = new byte[this.bytes_received];
                    packet = StringToByteArray(this.dataToRecieve);

                    // Packet verarbeiten....

                    this.dataToRecieve = String.Empty;
                    this.bytes_received = 0;
                    this.length_byte_read = false;
                }
            }
            catch ()
            {
                // folgt
            }
        }

Was meint ihr dazu? Hab den Controller heute leider nicht zum Testen hier...

Grüße

185 Beiträge seit 2005
vor 14 Jahren

Wenn du die Übertragung im Microcontroller auch selbst programmierst, dann würde ich ein Start und ein Stopp-Zeichen einfügen.

F
Fabian_81 Themenstarter:in
37 Beiträge seit 2008
vor 14 Jahren

Ja das wäre mir auch am liebsten, aber wie würde das Start/Stop-Zeichen deiner Meinung nach aussehen, wenn auch die Datenbytes jeden Wert von 0x00 bis 0xFF annehmen können? Das Start/Stop-Zeichen wäre ja ebenfalls in diesem Wertebereich.

185 Beiträge seit 2005
vor 14 Jahren

du musst dann die Werte, die mit den Steuerzeichen kollidieren wandeln.

Beispiel:

Steuerzeichen F0 - FF sind Steuerzeichen
F0 = Start of Frame
FE = ESC
FF = End of Frame

Wenn ein Zeichen >F0 dann wird das ESC vorrangestellt, dann das Zeichen mit einem gelöschtem Höchstwertigen übertragen.

Eine Checksume wäre hier auch von vorteil.