mikrocontroller.net

Forum: PC-Programmierung C# ComPort Problem


Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich bin nun schon seit fast einer Woche dabei den folgenden Fehler zu 
Suchen.

Rahmenbedingungen:

Auf dem uRechner läuft ein Programm, welches Messwerte erfassen soll. 
Diese werden in Arrays gespeichert. Ein kleine C# Sharp Programm soll 
die Messerte auslesen und in einer Datei Speichern, welche mittels Ajax 
auf eine Webseite geladen wird.

Auf dem uRechner sind Baudraten und Parity so wie Stop bits richtig 
gesetzt. Es wird ein 20MHz eingesetzt. Die Taktrate habe ich mit 
_delay_ms(1000) und einer blinkenden LED schon getestet.

das Problem:

Sende ich ein bestimmtes Zeichen an den Controller beginnt dieser damit 
254 Byte an den PC zu schicken. Mittels hTerm klappt dies Wunderbar. Bei 
C# kommen aber immer unterschiedlich viele Zeichen an. meistens so an 
die 120 bis 180 und dann hört es einfach auf.

Mitlerweile habe ich das Programm schon so angeändert, dass immer nur 25 
byte übertragen werden und der uRechner dann erst auf eine Checksumme 
des PCs Wartet. Aber selbst hier treten sehr oft Checksummen Fehler auf 
oder es kommen nicht alle 25 Byte am PC an. Hier nochmal. Mit hTerm kein 
Problem.

In Visual C# nutze ich die fertige SerialPort Klasse. Es sind 8 bit 
Daten, 2 Stop bits und keine Parität eingetragen. Der Puffer ist auf den 
Standartmäßigen 4kb. Es ist keine Timeout überwachung.

Die Daten lese ich mit dem Interrupt aus, welches ausgelöst wird, wenn 
sich ein neues byte im Puffer befindet. Es wird dann immer nur ein byte 
mit .Readbyte() aus dem ComPort gelesen. Trotzdem gehen jede Menge Daten 
verloren oder kommen fehlerhaft an.

Die einstellungen bei Visual C# sind genau die gleichen wie bei hterm.
Was vieleicht noch eine Interessante Information ist, ist dass es auf 
meinem Desktop PC auch mit C# wunderbar klappt. Auf allen anderen 
Laptops allerdings nicht. Die USB-Serial Adapter sind die gleichen mit 
gleichem Treiber und gleichem OS.

Am ATmega644 ist ein MAX232 vor den UART geschaltet.

Ich hoffe mir kann jemand helfen. Bin echt am verzweifeln. Ich würde 
auch euf eine andere Programmiersprache umsteigen, wenn mir jemand die 
Einbindung der Bibliotheken erklährt. Vieleicht gibt es auch ne 
Alternative zur .net Klasse von C#.

Ein Umsteigen auf Visual C++ oder VB wird wahrscheinlich keinen sinn 
machen, da diese ja die gleiche Klasse verwenden.

Danke für eure Bemühungen.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der fehler liegt sehr wahrscheinlich im Quellcode. Ohne den können wir 
nicht sinnvoll zu hilfe beitragen.

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm dass das als Antwort kommt habe ich mir fast gedacht. Prolem ist, 
dass der Qullcode ziemloch groß ist. Ich veruche mal die Relevanten 
Teile darzustellen:

c#

//Comport Initialisieren
ComPort = new System.IO.Ports.SerialPort(this.components);
ComPort.Parity = System.IO.Ports.Parity.None;
ComPort.BaudRate = 9600;
ComPort.PortName = "COM10";
ComPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(ComPort_DataReceived);
ComPort.DataBits = 8;
ComPort.StopBits = 2;

//mit einem Klich auf eine Schaltfläche wird der Comport geöfnet

private void onButton(object sender, EventArgs e)
{
    try
   {
          ComPort.Open();
          ComPort.Write(new byte[] { (byte)(0x02) }, 0, 1);
   }
   catch (Exception ex)
   {
       MessageBox.Show(ex.Message);
   }
}

private int counter; //Steht hier natürlich nicht in echt ;)

private void ComPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
  byte puffer = Convert.ToByte(ComPort.ReadByte());
  Console.WriteLine("Befehlteil: " + counter + "//" + puffer);
  counter++;
}


Und der Atmel
#define BAUD 9600UL      //halbe Baudrate
 
// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
 
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
#endif  

void USART1_init()
{
  //Baudrate einstellen
    UBRR1H = UBRR_VAL >> 8;
    UBRR1L = UBRR_VAL & 0xFF;

  //Empfangen und Senden
  //8 Bit
  //2 Stop Bit
  //None Parity

  UCSR1B = 0b10011000;
  UCSR1C = 0b10001110;
}

void USART1_send_Byte(uint8_t byte)
{
  while(!( UCSR1A & (1<<UDRE1))); //warten auf Datenregister empty;
  //_delay_ms(40); //Steht dieser wert auf 100 oder mehr läuft es einigermaßen gut. Ist aber ja kein Zustand
  UDR1= byte;
}

ISR (USART1_RX_vect) 
{
  cli();
  uint8_t puffer = UDR1;
         if(puffer == 0x02)
         {
               for(uint8_t i = 0; i<254;i++)
               {
                 USART1_send_Byte(Datenarray[i]); // das Array ist natürlich lang genug und woanders definiert
                }
         }
}

Das ist ja eigendlich alles was man wissen muss denke ich. Ich habe 
vorsichtshalber noch einmal ein sehr abgespecktes Programm geschrieben, 
was nur mit diesem Quellcode aufgebaut ist. Auch da kommen nach manchmal 
gerade 20 byte keine neuen Daten mehr an. Mit hterm werden ohne Probleme 
254 Byte mit dem Richtigen Inhalt empfangen.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jan schrieb:
> private void ComPort_DataReceived(object sender, 
System.IO.Ports.SerialDataReceivedEventArgs e)
> {
>   byte puffer = Convert.ToByte(ComPort.ReadByte());
>   Console.WriteLine("Befehlteil: " + counter + "//" + puffer);
>   counter++;
> }
woher weist du das nur 1byte ankommt?

while ( ComPort.BytesToRead > 0 ) {
   byte puffer = Convert.ToByte(ComPort.ReadByte());
   Console.WriteLine("Befehlteil: " + counter + "//" + puffer);
   counter++;
}

sinnvoller ist es aber vermutlich gleich alle verfügbaren bytes mit Read 
in ein array einzulesen.

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnte ich mal ausprobieren. Aber ich muss dann wissen wie viele es 
sind.

Seltsam ist dass es auf dem Desktop PC geht. Aber aber der hat auch 
wesendlich mehr Rechnleistung als der Laptop. Vieleicht ist es ja 
tatsäch so hinzubekommen. Werde morgen mal 2 Testprogramme schreiben und 
hochladen und es da dann direkt ausprobieren.

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jan schrieb:

> Die Daten lese ich mit dem Interrupt aus, welches ausgelöst wird, wenn
> sich ein neues byte im Puffer befindet. Es wird dann immer nur ein byte
> mit .Readbyte() aus dem ComPort gelesen. Trotzdem gehen jede Menge Daten
> verloren oder kommen fehlerhaft an.

1.: Passendes Encoding eingestellt? Sollte 
System.Text.Encoding.GetEncoding(28591) (ISO-8859-1) sein, da die 
anderen u.U. die übertragenen Werte verändern (ASCII "kürzt" alle Bytes 
> 127, UTF-8 wartet u.U. auf Multibyte-Zeichen etc.)
2.: Wie ist der ReceivedBytesThreshold eingestellt? U.U. diesen höher 
stellen
3.: Im DataReceived-Event sollte mit BytesToRead abgefragt werden wie 
viele Bytes im Buffer sind z.B.
private static void SP_OnDataReceived(object sender, SerialDataReceivedEventArgs e) {
    SerialPort sp = (SerialPort)sender;
    byte[] buffer = new byte[sp.BytesToRead];
    sp.Read(buffer, 0, buffer.Length);
    // do something
}
Falls Strings übertragen werden kann man ReadExisting() verwenden.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jan schrieb:
> Seltsam ist dass es auf dem Desktop PC geht. Aber aber der hat auch
> wesendlich mehr Rechnleistung als der Laptop.
das ist doch klar, der PC schafft es bei jeden byte die Methode 
aufzurufen, der Laptop schafft es scheinbar nicht. Es aber aber drozdem 
ein Programmierfehler.

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe gerade nochmal ein Testprogramm geschrieben.
Die Usart schnittstelle läuft tatsächlich sehr viel besser, wenn alle 
verfügbaren bytes ausgelesen werden. Es treten zwar immernoch oft Fehler 
auf aber das ist nicht schlimm.

Normalerweise hat aber der Comport schon einen Buffer der 4kb groß ist. 
Selbst wenn mein Laptop also nicht in der lage ist immer gleich die 
bytes einzulesen wenn ich sie einzeln einlese müssten sie aber im 
Speicher puffer bleiben. Der uRechner sendet nach 25 byte erst weiter 
wenn ein CRC empfange wurde. Der 4kB speicher kann also nie überlaufen.

Naja Hauptsache es geht so. Danke für die Hilfe.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jan schrieb:
> Normalerweise hat aber der Comport schon einen Buffer der 4kb groß ist.
> Selbst wenn mein Laptop also nicht in der lage ist immer gleich die
> bytes einzulesen wenn ich sie einzeln einlese müssten sie aber im
> Speicher puffer bleiben. Der uRechner sendet nach 25 byte erst weiter
> wenn ein CRC empfange wurde. Der 4kB speicher kann also nie überlaufen.

das Probelm ist/war das die funktion SerialDataReceivedEventArgs auch 
wenn 25byte im Puffer sind, nur einmal aufgerufen wird. Wenn du jetzt 
nur 1byte abrufst, dann bleiben noch 24byte im Puffer und es erfolgt 
kein ReceivedEvent mehr, weil ja nichts neues Empfangen wurde.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.