Forum: PC-Programmierung C# Serielle kommunikation - bin datei transferieren.


von amateur (Gast)


Lesenswert?

Hallo ich möchte einzelne Zeichen aus einer binärdatei lesen und an eine 
serielle schnittstelle übergeben (COM Port zu einem ZigBee Modul) jedoch 
habe ich das Problem das es nicht funktioniert wie ich es will

private void button1_Click(object sender, EventArgs e)
          {
              using (BinaryReader b = new 
BinaryReader(File.Open("C:/Users....compression.bin", FileMode.Open)))
              {


                  // 2.
                  // Position and length variables.
                  int pos = 0;
                  //string x;
                  // 2A.
                  // Use BaseStream.
                  int length = (int)b.BaseStream.Length;
                  char[] buff = new char[length];
                  while (pos < length)
                  {

                      // 3.
                      // Read integer.
                      buff[pos] = b.ReadChar(); // einzelne Zeichen 
auslesen
                      string x = new string(buff);
                      serialPort1.Write(x);
                      {
                      buff[pos] = v[i];
                      }
                      */
                      // 4.
                      // Advance our position variable.
                      pos ++;

                  }
                  string s = new string(buff);
                      //x=ByteArrayToString(buff);
                  textBox1.AppendText(s);

              }

           }
Als Fehlermeldung bekomme ich: Der Ausgabe-Zeichenpuffer zu klein für 
die codierten Zeichen. Codierung von "Unicode (UTF-8)" in 
Ausweichposition "System.Text.DecoderReplacementFallback".
Parametername: chars

Mache ich das richtig oder gibt es auch eine andere Lösung für mein 
Vorhaben

von Peter II (Gast)


Lesenswert?

string x = new string(buff);
serialPort1.Write(x);

warum wandelst du auch erst in einen String um? Sende doch gleich das 
byte. WriteByte oder so.

von amateur (Gast)


Lesenswert?

anders gehts nicht es gbt kein bytewrite

von Peter II (Gast)


Lesenswert?

amateur schrieb:
> anders gehts nicht es gbt kein bytewrite

klar geht es anders - stings sind er falsche weg!!!!

Eventuell mal selber die doku lesen?

http://msdn.microsoft.com/de-de/library/system.io.ports.serialport.aspx

Write(Byte[], Int32, Int32)   Schreibt eine angegebene Anzahl von Bytes 
unter Verwendung von Daten aus einem Puffer in den seriellen Anschluss.

von amateur (Gast)


Lesenswert?

Hier etwas sauberer:


private void button1_Click(object sender, EventArgs e)
          {
              using (BinaryReader b = new 
BinaryReader(File.Open("C:/Users...compression.bin", FileMode.Open)))
              {



                  int pos = 0;
                  int length = (int)b.BaseStream.Length;
                  char[] buff = new char[length];
                  while (pos < length)
                  {

                      buff[pos] = b.ReadChar();

                      string x = new string(buff);
                      serialPort1.

                      pos ++;

                  }
                  string s = new string(buff);

                  textBox1.AppendText(s);

              }

          }

von amateur (Gast)


Lesenswert?

So richtig?


private void button1_Click(object sender, EventArgs e)
          {
              using (BinaryReader b = new 
BinaryReader(File.Open("C:/Users...compression.bin", FileMode.Open)))
              {



                  int pos = 0;
                  int length = (int)b.BaseStream.Length;
                  byte[] buff = new byte[length];
                  while (pos < length)
                  {

                      buff[pos] = b.ReadByte();
                      //string x = new string(buff);


                      pos ++;

                  }
                  //
                  serialPort1.Write(buff, 0, length);
                  string s=ByteArrayToString(buff);
                  textBox1.AppendText(s);

              }

          }

von OMG (Gast)


Lesenswert?

Deine Version würde mit einer for-Schleife besser aussehen:

private void button1_Click(object sender, EventArgs e)
          {
              using (BinaryReader b = new
BinaryReader(File.Open("C:/Users...compression.bin", FileMode.Open)))
              {
                  int length = (int)b.BaseStream.Length;
                  byte[] buff = new byte[length];
                  for (int pos = 0; pos < length; pos++)
                      buff[pos] = b.ReadByte();
                  serialPort1.Write(buff, 0, length);
                  string s=ByteArrayToString(buff);
                  textBox1.AppendText(s);
              }
          }

Probiere mal dieses:

   FileStream s = new FileStream("test.txt", FileMode.Open);
   byte[] Data;
   s.Read(Data, 0, s.Length);
   serialPort1.Write(Data, 0, Data.Length);

von amateur (Gast)


Lesenswert?

wie ist es eigtlich wenn ich jpeg habe?

von Klaus W. (mfgkw)


Lesenswert?

Dann solltest du nicht "test.txt" als Dateinamen nehmen, vermute ich.
Oder was meinst du mit der Frage?

von amateur (Gast)


Lesenswert?

OK. Aber wie funktioniert es mit der rekonstruktion dieses Files auf der 
anderen seite?

von Peter II (Gast)


Lesenswert?

amateur schrieb:
> OK. Aber wie funktioniert es mit der rekonstruktion dieses Files auf der
> anderen seite?

was soll diese dumme frage? Es kommen doch daten aus der Datei drüben 
an, wenn sie dort genauso wieder in eine Datei geschrieben werden hast 
du das Bild drüben.

Es spielt überhaupt keine rolle was das für eine Datei ist, es kann auch 
ein Video sein.

von Eddy C. (chrisi)


Lesenswert?

Google mal X-, Y- oder Z-Modem. Das sind Protokolle zur Übertagung von 
Dateien per DFÜ (seufz), bzw. serieller Schnittstelle. Sicherlich gibt 
es auch Implementierungen in C#.

von amateur (Gast)


Lesenswert?

Hallo, ich bin jetzt soweit dass ich die bin dateien RICHTIG einlese.

using (FileStream fs = File.OpenRead(path))
            {
                Int64 f = fs.Length;
                byte[] b = new byte[f];
                UTF8Encoding temp = new UTF8Encoding(true);
                while (fs.Read(b, 0, b.Length) > 0)
                {
                    string s = ByteArrayToString(b);
                    textBox1.AppendText(s);
                    serialPort1.Write(b, 0, b.Length);
                }

In b steht genau das was ich möchte....

Das Problem ist leider auf der Empfängerseite...

private void serialPort1_DataReceived
            (object sender, System.IO.Ports.SerialDataReceivedEventArgs 
e)
          {
              RxString = serialPort1.ReadExisting();
              int y = serialPort1.BytesToRead;
              serialPort1.Read(buff, 0, 96966);
              this.Invoke(new EventHandler(DisplayText));
          }

Es werden jedoch nur 392(y=0x188) übertragen :-( und das irgendwo in dem 
File -> also nicht schön von anfang an). Als Übertragungsmedium habe ich 
ZigBee Module die als Wireless Uart laufen. Was mache ich hier falsch?

von Peter II (Gast)


Lesenswert?

amateur schrieb:
> RxString = serialPort1.ReadExisting();
>               int y = serialPort1.BytesToRead;
>               serialPort1.Read(buff, 0, 96966);
>               this.Invoke(new EventHandler(DisplayText));

das ist ja auch unsinn, die liest hier 2mal ein. DAs kann ja nicht gut 
gehen.

einmal hier:
> RxString = serialPort1.ReadExisting();

und noch einmal

> serialPort1.Read(buff, 0, 96966);

und wall soll diese zahl dort? Du kannst gar nicht wissen ob so viele 
zeichen da sind.

du braucht nur:

readSize += serialPort1.Read(buff, readSize, serialPort1.BytesToRead );

readSize ist dabei die größe die bis zu diesem zeitpunkt angekommen ist. 
muss also eine variabel außerhalb von serialPort1_DataReceived sein, 
sinnvoll ist auch voher die Größe der Datei zu übertragen sonst weist du 
ja nicht wenn schluss ist.

von ruffy d. monkey (Gast)


Lesenswert?

Peter II schrieb:
> das ist ja auch unsinn, die liest hier 2mal ein. DAs kann ja nicht gut
> gehen.
>
> einmal hier:
>> RxString = serialPort1.ReadExisting();
>
> und noch einmal

Das ist nur für die ausgabe auf dem Textbox :-)

Peter II schrieb:
> und noch einmal
>
>> serialPort1.Read(buff, 0, 96966);
>
> und wall soll diese zahl dort? Du kannst gar nicht wissen ob so viele
> zeichen da sind.

Ich weiss dass so viele Daten anliegen...
Aber auch wenn ich da einfach so mal 1000 eingebe kommen keine 1000 
Daten an sondern 458. Und das komische ist jetzt es fängt vorne an und 
nach einpaar Daten (~15) springt es zu einer anderen Stelle??? und macht 
da weiter. Das Ende stimmt auch (die letzten paar Daten).

von ruffy d. monkey (Gast)


Lesenswert?

Ich habe inzwischen herausgefunden dass immer 10 Byte auf einmal 
gesendet werden und dann sprung irgendwohin und noch mal 10 Byte und 
noch mal und noch mal un am ende die letzten 127 Byte richtig ...

von Peter II (Gast)


Lesenswert?

ruffy d. monkey schrieb:

> Das ist nur für die ausgabe auf dem Textbox :-)
das darfst du drozdem nicht machem, dann nach dem Lesen sind die Daten 
weg, man kann sie nicht 2 mal lesen!

> Ich habe inzwischen herausgefunden dass immer 10 Byte auf einmal
> gesendet werden und dann sprung irgendwohin und noch mal 10 Byte und
> noch mal und noch mal un am ende die letzten 127 Byte richtig ...

nein das ist nicht so, es können auf einer Seriellen Leitung nicht 10 
byte auf einmal gesendet werden! Sie werden immer die reihe nach 
gesendet. Wegen der Puffer in der Harder oder im Betriebsystem kommen 
sie in verschienden Blöcken an, die anzahl kann aber jedes mal anders 
sein!

> letzten 127 Byte richtig
glaube ich nicht, weil im Puffer nur 10 byte reinpassen

von ruffy d. monkey (Gast)


Lesenswert?

Wie kann ich mir die "Sprünge" erklären? Kommen die ZigBee Module nicht 
nach?

von Peter II (Gast)


Lesenswert?

ruffy d. monkey schrieb:
> Wie kann ich mir die "Sprünge" erklären? Kommen die ZigBee Module nicht
> nach?

optimierung. Warum sollte der PC für jedes byte einzeln die 
Empfangsroutinge aufrufen?  Dann wartet man lieber bis ein baar bytes da 
sind.

von ruffy d. monkey (Gast)


Lesenswert?

jetzt muss ich leider weg, da ich noch ein Test schreiben muss 
Regelungstechnik :D vielen dank für die antworten und anregungen ich 
werds mir morgen nochmal intensiv anschauen.

von ruffy d. monkey (Gast)


Lesenswert?

hallo,
guten morgen bin wieder da! Ich habe grad vorhin probiert mit HTerm 
Daten zu senden. Wenn ich eigene Eingaben mache und diese nicht sehr 
lange mache (bis 138 Byte) wird alles übertragen. Genau ab diesen 139 
Byte geht schon 1 Byte verloren. Wenn ich 276 Byte übertrage kommen nur 
20 heil an??? Was ist das?

von Peter II (Gast)


Lesenswert?

ruffy d. monkey schrieb:
> Was ist das?

keine ahnung, dafür müssten wir mal den code sehen mit dem du die daten 
empfängst.

von ruffy d. monkey (Gast)


Lesenswert?

welchen Code meinst du? auf den ZigBee 
Modulen?(RZWirelessUart-http://www.atmel.com/tools/RZ600.aspx?tab=documents 
(RZ600 HW)) kann der COM Port Treiber nicht schuld sein? oder die USB?

von Peter II (Gast)


Lesenswert?

nein dein C# code

von ruffy d. monkey (Gast)


Lesenswert?

Aber wenn es auch mit dem HTerm Terminal nicht funktioniert muss doch an 
anderer Stelle das Problem sein.

von ruffy d. monkey (Gast)


Lesenswert?

1
 using System;
2
  using System.Collections.Generic;
3
  using System.ComponentModel;
4
  using System.Data;
5
  using System.Drawing;
6
  using System.Text;
7
  using System.Windows.Forms;
8
  
9
  namespace SimpleSerial
10
  {
11
      public partial class Form1 : Form
12
      {
13
          // Add this variable
14
15
          string RxString;
16
          byte[] buff = new byte[127];
17
          
18
          public Form1()
19
          {
20
              InitializeComponent();
21
          }
22
  
23
          private void buttonStart_Click(object sender, EventArgs e)
24
          {
25
              serialPort1.PortName = "COM8";
26
              serialPort1.BaudRate = 57600;
27
  
28
              serialPort1.Open();
29
              if (serialPort1.IsOpen)
30
              {
31
                  buttonStart.Enabled = false;
32
                  buttonStop.Enabled = true;
33
                  textBox1.ReadOnly = false;
34
              }
35
          }
36
  
37
          private void buttonStop_Click(object sender, EventArgs e)
38
          {
39
              if (serialPort1.IsOpen)
40
              {
41
                  serialPort1.Close();
42
                  buttonStart.Enabled = true;
43
                  buttonStop.Enabled = false;
44
                  textBox1.ReadOnly = false;
45
              }
46
  
47
          }
48
  
49
          private void Form1_FormClosing(object sender, FormClosingEventArgs e)
50
          {
51
              if (serialPort1.IsOpen) serialPort1.Close();
52
          }
53
  
54
          private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
55
          {
56
              // If the port is closed, don't try to send a character.
57
58
              if(!serialPort1.IsOpen) return;
59
  
60
              // If the port is Open, declare a char[] array with one element.
61
              char[] buff = new char[1];
62
              
63
              // Load element 0 with the key character.
64
65
              buff[0] = e.KeyChar;
66
  
67
              // Send the one character buffer.
68
              serialPort1.Write(buff, 0, 1);
69
  
70
              // Set the KeyPress event as handled so the character won't
71
              // display locally. If you want it to display, omit the next line.
72
              e.Handled = true;
73
          }
74
75
          private void DisplayText(object sender, EventArgs e)
76
          {
77
              textBox1.AppendText(RxString);
78
          }
79
80
          private void serialPort1_DataReceived
81
            (object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
82
          {
83
              //RxString = serialPort1.ReadExisting();
84
              int y = serialPort1.BytesToRead;
85
              serialPort1.Read(buff, 0, y);
86
87
          }
88
      }
89
  }

von ruffy d. monkey (Gast)


Lesenswert?

So ich schreibe jetzt die 10 Byte Daten an den Serialport und lese diese 
dann ein und füge sie zusammen. Aber 110. Byte ist noch in Ordnung 
111.-119. ist die Wieder holung des letzten Blockes

    [101]  101  byte
    [102]  65  byte
    [103]  0  byte
    [104]  147  byte
    [105]  101  byte
    [106]  65  byte
    [107]  0  byte
    [108]  183  byte
    [109]  26  byte
bis hier  [110]  65  byte     richtig
    [111]  101  byte
    [112]  65  byte
    [113]  0  byte
    [114]  147  byte
    [115]  101  byte
    [116]  65  byte
    [117]  0  byte
    [118]  183  byte
    [119]  26  byte

danach geht es ab der 111 im Originalen weiter... Wieso???



1
//Sender
2
private void button1_Click(object sender, EventArgs e)
3
        {
4
            
5
            string path = @"C:\Users\ipa\Desktop\jpeg_compression.txt";
6
7
           
8
9
                       //Open the stream and read it back.
10
            using (FileStream fs = File.OpenRead(path))
11
            {
12
                Int64 f = fs.Length;
13
                byte[] b = new byte[f];
14
                int off = 0;
15
                decimal pakete = f/10;
16
                decimal paket = Math.Round(pakete);
17
                fs.Read(b, 0, b.Length);
18
19
                for (int a = 1; a < paket; a++)
20
                {
21
                    serialPort1.Write(b, off, 10);
22
                    off = (10 * a);
23
                }                
24
            }
25
        }
26
27
//Empfänger
28
private void serialPort1_DataReceived
29
            (object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
30
          {
31
              serialPort1.Read(buff, 0, 10);
32
              buff.CopyTo(buff2, offset);
33
              offset = offset + 10;
34
                    if (offset >= 98150)
35
                    {
36
                        CreateFile(buff2);
37
                    }
38
          }

von Peter II (Gast)


Lesenswert?

serialPort1.Read(buff, 0, 10);

hier ist schon mal ein fehler. Es ist nicht sicherstellt das wirklich 10 
zeichen gelesen werden. Man muss den return wert von Read auswerten, 
dort steht drin wie viele daten wirklich gelesen wurden.

Und dann mit dem 2. array kannst du dir sparen, was glaubst du was der 
2. parameter der Read funktion macht? - es ist der offset für das array.

von ruffy d. monkey (Gast)


Lesenswert?

Peter II schrieb:
> Und dann mit dem 2. array kannst du dir sparen, was glaubst du was der
> 2. parameter der Read funktion macht? - es ist der offset für das array.

Na um es später in eine Datei reinzuschreiben. Ich habe das Problem dass 
wenn ich viele Bytes schreibe sich das Programm sehr komisch verhält so 
finktioniert es zum größten Teils (bis auf einige effekte).

Immernoch dasselbe mit

serialPort1.Read(buff, 0, serialPort1.BytesToRead);

von Peter II (Gast)


Lesenswert?

ruffy d. monkey schrieb:
> Immernoch dasselbe mit
>
> serialPort1.Read(buff, 0, serialPort1.BytesToRead);

wie sie der code complett aus? Mit so einer zeile kann niemand etwas 
anfangen.

von ruffy d. monkey (Gast)


Angehängte Dateien:

Lesenswert?

hier -> code gezippt

von Peter II (Gast)


Lesenswert?

steht doch immer noch der gleiche unsinn drin
1
 private void serialPort1_DataReceived
2
            (object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
3
          {
4
              serialPort1.Read(buff, 0, 10);
5
              buff.CopyTo(buff2, offset);
6
              offset = offset + 10;
7
                    if (offset >= 98150)
8
                    {
9
                        CreateFile(buff2);
10
                    }
11
          }

du musst auch abfragen wie viele daten gelesen wurden, nur weil du 10 
byte willst bekommst du sich nicht immer.

von ruffy d. monkey (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab das hier vergessen (sender seite)

Peter II schrieb:
> steht doch immer noch der gleiche unsinn drin

Ich hab rumprobiert ohne erfolg also alles rückgängig gemacht

von Peter II (Gast)


Lesenswert?

ruffy d. monkey schrieb:
> Ich hab rumprobiert ohne erfolg also alles rückgängig gemacht

dann kann man dir nicht helfen.

Ich habe dir gezeigt wo der fehler ist, keine ahnung wie du versucht 
hast ihn zu beheben, aber mit diesem empfangscode wird es NIE sauber 
gehen.

Schreibt erstmal eine ordentliche funktion, dabei achtest du auf 
folgendes:

- du musst BytesToRead verwenden um rauszubekommen wie viel du lesen 
darst
- du muss den Returnwert von read verwenden um zu wissen wie viel 
gelesen wurde


dann postest du diese routine, auch wenn sie eventuell noch nicht geht.

von Sven H. (dsb_sven)


Lesenswert?

ruffy d. monkey schrieb:
> Aber wenn es auch mit dem HTerm Terminal nicht funktioniert muss doch an
> anderer Stelle das Problem sein.

Stimmt allerdings.

von ruffy d. monkey (Gast)


Lesenswert?

so? brint aber auch nicht viel aber es sind bis zum 4033. byte 
identisch(Eingabe = Ausgabe). Danach keine Übereinstimmung.

private void serialPort1_DataReceived
            (object sender, System.IO.Ports.SerialDataReceivedEventArgs 
e)
          {
              int x=serialPort1.Read(buff2, 0, serialPort1.BytesToRead);
              //buff.CopyTo(buff2, offset);
              offset = offset + x;
                    if (offset >= 98150)
                    {
                        CreateFile(buff2);
                    }
          }

von Peter II (Gast)


Lesenswert?

verbinde doch mal direkt die sende und empfangsleitung am PC - stimmt 
dann die gesendeten und empfangen daten?

Ich kenne diese funktmodule nicht, was seht denn dort zur 
datensicherheit? Kümmern sich die geräte selber darum oder muss du das 
machen?

von ruffy d. monkey (Gast)


Lesenswert?

Also inzwischen bin ich mir sicher, dass das Problem die zu schnelle 
Übergabe der Daten an den Modul ist. Denn sobald ich nach jeden 88 Bytes 
einen Sleep(99) mache kann ich 12kByte ohne Probleme übertragen. Man 
sagte mir aber ich müsste mich um diese Laufzeiten bzw. dieses warten 
nicht kümmern da es in den unteren Schichten gemacht werden müssten. Der 
Treiber ist glaub schuld...

von Peter II (Gast)


Lesenswert?

dann musst du eventuell die Flusskontrolle nutzen.

Wenn dein Gerät außer Reichweite ist, dann bekommst du es ja gar nicht 
mit und sendest fröhlich weiter.

von ruffy d. monkey (Gast)


Lesenswert?

ich habe eine Art Terminalprogramm geschrieben in C#, welches mir 
Datenpakete(kleiner 127 Byte) aus einer JPEG file bildet und diese 
werden dann übertragen. Auf der Empfängerseite werden diese Pakete 
wieder zusammengesetzt. Mein Problem ist, dass nach ~12 kByte nichts 
mehr ankommt. Bis 12kByte ist alles OK. Das was gesendet wird wird auch 
empfangen und zusammengesetzt. Dies funktioniert jedoch nur, wenn ich 
zwischen diesen Paketen pausen einlege (Sleep(100)) (ms). Erste Frage: 
Wieso muss ICH diesen Sleep implementieren, wird es nicht vom 
Betriebssystem bzw. vom COM Port Treiber gemacht? Zweite Frage: Wieso 
hört es immer bei 12 kByte auf? Puffer voll?? Wird es aber nach dem 
lesen nicht geleert?

Sender:
private void button1_Click(object sender, EventArgs e)
        {

            string path = @"C:\Users\ipa\Desktop\adidas.jpg";



                       //Open the stream and read it back.
            using (FileStream fs = File.OpenRead(path))
            {

                Int64 f = fs.Length;
                byte[] b = new byte[f];

                decimal pakete = f/100; /100 Byte große Datenpakete
                decimal paket = Math.Round(pakete);
                fs.Read(b, 0, b.Length);
                Int32 offset=0;


                for (int a = 0; a <= paket-1; a++)
                {
                    serialPort1.Write(b,offset,100);
                    System.Threading.Thread.Sleep(60);
                    offset = offset + 100 ;


                }serialPort1.Close();
            }


        }

Empfänger:
private void serialPort1_DataReceived
            (object sender, System.IO.Ports.SerialDataReceivedEventArgs 
e)
          {

              do
              {
                  x = serialPort1.Read(buff2, offset, 
serialPort1.BytesToRead);
                  offset = offset + x;

              } while (offset <= 31130); //das File ist 31142 Byte groß;

              CreateFile(buff2); //JPEG datei wird reproduziert




          }

von Peter II (Gast)


Lesenswert?

ruffy d. monkey schrieb:
> Dies funktioniert jedoch nur, wenn ich
> zwischen diesen Paketen pausen einlege (Sleep(100)) (ms). Erste Frage:
> Wieso muss ICH diesen Sleep implementieren, wird es nicht vom
> Betriebssystem bzw. vom COM Port Treiber gemacht?

hast du die Frage darüber gelesen?

> dann musst du eventuell die Flusskontrolle nutzen.

dafür müsste man aber die doku deiner module lesen

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.