Autor Thema: USART Empfangspuffer löschen  (Gelesen 9694 mal)

Offline Max Pohl

  • Jr. Member
  • **
  • Beiträge: 65
    • Profil anzeigen
USART Empfangspuffer löschen
« am: März 29, 2010, 18:25:42 Nachmittag »
Hallo zusammen,
ich habe folgendes Problem.
Ich empfange Daten von einem externen Gerät per RS232. Diese Daten gebe ich auf einem GLCD aus.
Die Daten werden alle 500ms aktualisiert und sollen den vorherigen Wert überschreiben.
Also werde alle Daten ab der selben Coursoradresse ausgegeben.
Die erste empfangene String wird exakt an der gewünschten Coursoradresse ausgegeben.
Die zweite sowie alle weiteren werden erstaunlicherweise um ein Zeichen nach rechts versetzt!?!
Wie ist das möglich?
Kann es sein das ich nach der Ausgabe einen Puffer löschen muss? (ähnlich wie bei FFlush)???
hier mal einen Auschschnitt aus meinem Programm.
while(true)
{
      fprintf(RS232,"Abfragebefehl"); //sendet den Abfragebefehl an das externe Gerät
      fgets(Empfange,RS232);//Antwort wird in String Empfange abgelegt
      lcd_coursor_pos(1,6);//Setzte Coursoradresse
      printf(lcd_uebertrage_zeichen,"%s    ",Empfange);//Ausgabe auf dem GLCD
      delay_ms(500);
}

Offline Coltfisch

  • Hero Member
  • *****
  • Beiträge: 501
    • Profil anzeigen
    • BASE 32
Re: USART Empfangspuffer löschen
« Antwort #1 am: März 30, 2010, 10:45:48 Vormittag »
Zitat
Kann es sein das ich nach der Ausgabe einen Puffer löschen muss?
Nicht das ich wüßte, fgets sollte den Buffer "Empfange" eigentlich immer überschreiben.
Anhand Deines kurzen Codeschnipsels ist jedoch auch nicht direkt abzuleiten, wo nun der Fehler liegt (in den LCD-Funktionen oder im RS232-Code von CCS).
Lass Dir doch einfach mal die Länge der Zeichenkette "Empfange" ausgeben, während Dein "externes Gerät" immer den gleichen String über RS232 ausgibt.

Wie ist denn "Empfange" eigentlich in Deinem Programm definiert?

Gruß
Daniel

Offline Max Pohl

  • Jr. Member
  • **
  • Beiträge: 65
    • Profil anzeigen
Re: USART Empfangspuffer löschen
« Antwort #2 am: März 30, 2010, 18:13:43 Nachmittag »
Also ich setzte nun vor jedem Empfang den Puffer manuell auf 0.
Nun funktioniert alles wie gewollt.

Empfange ist ein pointer.

Offline Coltfisch

  • Hero Member
  • *****
  • Beiträge: 501
    • Profil anzeigen
    • BASE 32
Re: USART Empfangspuffer löschen
« Antwort #3 am: März 30, 2010, 20:27:11 Nachmittag »
Empfange ist ein pointer.
Nur ein Pointer, oder zeigt dieser Pointer auch auf einen entsprechenden Speicherbereich?

Offline Max Pohl

  • Jr. Member
  • **
  • Beiträge: 65
    • Profil anzeigen
Re: USART Empfangspuffer löschen
« Antwort #4 am: März 31, 2010, 21:33:50 Nachmittag »
Ja genau der pointer zeigt auf einen speicherbereich.

Offline Bernd

  • Hero Member
  • *****
  • Beiträge: 3820
    • Profil anzeigen
Re: USART Empfangspuffer löschen
« Antwort #5 am: März 31, 2010, 23:42:20 Nachmittag »
Um noch einmal die Frage von Coltfish zu wiederholen: Wie es „Empfange“ in Deinem Code definiert? Wenn es ein Pointer ist, müßte es

char *Empfange;
sein. Ohne Initialisierung zeigt dieser Pointer ins Nirvana. Zur Initialisierung muß dem Pointer eine Adresse zugewiesen werden, z.B.

char array_empfangen[20];            // Array, welches die Daten aufnimmt

char *Empfange = array_empfangen;    // Zeiger auf das Array, welches die Daten aufnimmt

Zitat
Also ich setzte nun vor jedem Empfang den Puffer manuell auf 0.

Was genau setzt Du auf Null? Das erste Element (oder alle Elemente) des Empfangs-Arrays oder den Zeiger? Auch hier wäre der von Dir verwendete Code hilfreich.


Viele Grüße

Bernd

Offline Max Pohl

  • Jr. Member
  • **
  • Beiträge: 65
    • Profil anzeigen
Re: USART Empfangspuffer löschen
« Antwort #6 am: April 01, 2010, 18:36:18 Nachmittag »
#byte RCREG2 = 0XF6E

char get_pos(void)
{
   char *recieve;
   recieve = malloc(sizeof(char));

      RCREG2 = 0;
      fputs("POS",MOTOR1);
      fgets(recieve,MOTOR1);
  

   free(recieve);
   return recieve;
  
}

So in etwa sieht meine Funktion aus.
Damit funktioniert es wunderbar.

Offline Coltfisch

  • Hero Member
  • *****
  • Beiträge: 501
    • Profil anzeigen
    • BASE 32
Re: USART Empfangspuffer löschen
« Antwort #7 am: April 02, 2010, 11:04:18 Vormittag »
Zitat
Damit funktioniert es wunderbar.
Tja dann kann ich nur sagen: Schwein gehabt.

Mit
recieve = malloc(sizeof(char));reservierst Du genau ein jämmerliches Byte. Sollte Dein externes Gerät mal mehr als nur ein einzelnes Zeichen übertragen, ergibt sich hier ein nahezu unendliches Spektrum möglicher Fehlfunktionen. Der Funktion fgets ist es nämlich egal, wie viel Speicher für die Variable receive reserviert ist, sie wird sämtliche empfangene Zeichen zusammenhängend dort abspeichern. Alle Speicherstellen hinter dem Speicherbereich für das eine Byte von "receive" werden dabei gnadenlos übergebügelt. Werden diese Speicherbereiche auch noch mit Variablen belegt, die für den Ablauf des Programms relevant sind, dann sind die Folgen nicht abzusehen.

Nebenbei gesagt würde ich Dir grundsätzlich von der Verwendung der dynamischen Speicherverwaltung (malloc / free) auf einem 8-Bit Microkontroller abraten, es sei denn, Du weißt genau was Du tust. Einerseits ist dies meistens einfach überflüssig, viel schlimmer ist aber, dass sich das Fehlerpotenzial damit deutlich erhöht und auch die Fehlersuche schwieriger wird.

Und noch eine böse Sache:
Was möchtest Du mit der Funktion get_pos eigentlich zurückliefern? So wie sie definiert ist, wir ein einzelner char zurückgeliefert. Mit dem Return lieferst Du dann aber die Variable "receive" zurück, wobei receive ein Pointer auf char ist. Macht keinen Sinn.
Aber selbst, wenn Du den Rückgabewert auf char* ändern würdest, gäbe es ein Problem:
Den Speicherbereich von "receive" gibst Du direkt vor der Übergabe mit free frei.

Lange Rede kurzer Sinn:
Ich bezweifle stark, dass diese Funktion so wie sie dargestellt ist fehlerfrei funktioniert. Und wenn doch, dann tut sie dies nur zufällig und unter ganz bestimmten Bedingungen. Es wäre (zu Deinen Gunsten) vielleicht nicht schlecht, hier mal den vollständigen, tatsächlichen Code zu posten.

Gruß
Daniel



Offline Max Pohl

  • Jr. Member
  • **
  • Beiträge: 65
    • Profil anzeigen
Re: USART Empfangspuffer löschen
« Antwort #8 am: April 02, 2010, 11:47:50 Vormittag »
Hätte nicht gedacht das mein Code so Schrott ist:)

Zitat
reservierst Du genau ein jämmerliches Byte.
So wird die Speicherreservierung in meinem Buch nunmal beschrieben...


Zitat
Den Speicherbereich von "receive" gibst Du direkt vor der Übergabe mit free frei.

Der Befehl free hebt doch nur die Speicherreservierung wieder auf, ohne ihn zu löschen. Oder habe ich da etwas falsch verstanden???



Angenommen ich lasse die dynamische Speicherverwaltung weg und sichere die
empfangene String in einem Char array.
Wie kann ich dann dieses array zurückgeben?

Ich möchte nur eine Funktion die mir einen String zurückliefert...
Die ich dann z.B. so ausgeben kann.
printf("%s",funktionxy());
Wie würde dazu eine Profilösung aussehen?


Grüße
Max

Offline Coltfisch

  • Hero Member
  • *****
  • Beiträge: 501
    • Profil anzeigen
    • BASE 32
Re: USART Empfangspuffer löschen
« Antwort #9 am: April 02, 2010, 12:40:23 Nachmittag »
Zitat
Hätte nicht gedacht das mein Code so Schrott ist:)
Nein, würde ich so nicht formulieren, bei Dir funktioniert es ja  ;)
Ich würde Deinen Code eher gefährlich nennen  :)

Zitat
reservierst Du genau ein jämmerliches Byte.
So wird die Speicherreservierung in meinem Buch nunmal beschrieben...
Nunja, vermutlich ein Buch für C-Programmierung auf PCs...
Allerdings wird doch dort auch stehen, wie man die Größe des reservierten Speichers festlegt. Wenn Du z.B. einen 20 Zeichen langen String ablegen möchtest, würde man das so tun:
receive = malloc(sizeof(char)*21)Man darf nicht vergessen, dass ein String üblicherweise ein Terminierungszeichen '\0' enthält. Daher reserviere ich hier 21 Bytes, um 20 Bytes "Nutzzeichen" abzulegen.

Zitat
Der Befehl free hebt doch nur die Speicherreservierung wieder auf, ohne ihn zu löschen. Oder habe ich da etwas falsch verstanden???
Das ist zwar richtig, aber es entsteht folgende Situation:
Mit dem Return gibst Du nur einen Zeiger auf diesen Speicherbereich zurück, in dem Deine Nutzdaten liegen und keine Kopie. Jetzt teilst Du dem Compiler durch das free mit, dass der Speicherbereich wieder zur Verfügung steht und mit anderen Daten belegt werden dürfte. Es ist nun durchaus denkbar, dass - noch bevor Du selber dazu kommst, die Nutzdaten zu verarbeiten - der freigegebene Speicher vom Compiler mit anderen Daten überschrieben wird. Und dann hast Du den Salat.
Wenn Du einen Speicherbereich einmal mit free freigegeben hast, solltest Du ihn auf keinen Fall mehr anpacken bzw. davon ausgehen, dass sich der Inhalt nicht ändert. Das ist saugefährlich, erst recht auf einem PC sollte man das lassen!

Ich möchte nur eine Funktion die mir einen String zurückliefert...
Die ich dann z.B. so ausgeben kann.
printf("%s",funktionxy());
Wie würde dazu eine Profilösung aussehen?

Mein Vorschlag:

char* get_pos(char *str)
{
   fputs("POS",MOTOR1);
   fgets(str,MOTOR1);
 
   return str;
}

// und dann im Hauptprogramm:

char str[21];  // Speicherbereich für 20 Zeichen + '\0' reservieren
printf("%s",get_pos(str));


Der Funktion get_pos() wird hier einmal ein Zeiger auf ein Array übergeben, in das die Funktion Zeichen ablegen darf. Anschließend gibt die Funktion ebenfalls einen Pointer auf dieses Array zurück, damit Du get_pos bequem aus printf aufrufen kannst.

Gruß
Daniel

Offline Max Pohl

  • Jr. Member
  • **
  • Beiträge: 65
    • Profil anzeigen
Re: USART Empfangspuffer löschen
« Antwort #10 am: April 02, 2010, 13:11:30 Nachmittag »
Ah ok alles klar, ich hatte wohl nur viel Glück. :)
Vielen Dank für deinen Vorschlag funktioniert einwandfrei.
Das Problem mit der Pufferlöschung habe ich allerdings immernoch.
Ohne RCREG1 = 0; wird automatisch ein Leerzeichen an erster Stelle eingesetzt.
Kann dies daran liegen das die Funktion fgets den Empfang bei erreichen des Terminierungzeichens beendet?
Der String ist jedoch so aufgebaut: String[CR][LF]
Also würde [LF] immernoch im Puffer sitzen?!?!

Gruß
Max

Offline Coltfisch

  • Hero Member
  • *****
  • Beiträge: 501
    • Profil anzeigen
    • BASE 32
Re: USART Empfangspuffer löschen
« Antwort #11 am: April 02, 2010, 18:43:08 Nachmittag »
Zitat
Kann dies daran liegen das die Funktion fgets den Empfang bei erreichen des Terminierungzeichens beendet?
Ja, das Geheimnis liegt hier wahrscheinlich in der Umsetzung der fgets-Funktion.
Eleganter wirst Du das "Problem" umgehen können, wenn Du an der lcd_uebertrage_zeichen-Funktion ansetzt. Wie sieht diese denn aus? Scheinbar gibt diese Funktion für den Linefeed [LF] ein Leerzeichen aus. Das könntest Du natürlich unterbinden. Kannst Du den Code mal posten?

Gruß
Daniel

 


* Recent Topics