www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Nicht alle Datensätze werden per UART gesendet


Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe im moment ein sehr komisches Problem, und ich komm einfach 
nicht dahinter.
Ich habe einen GPS Empfänger an einen AVR angeschlossen.
Der GPS Empfänger sendet alles richtig, wenn ich ihn direkt an meinen PC 
anschließe, bekomme ich genau das, was ich sehen will:
$GPGGA,120056.000,0000.0000,N,00000.0000,E,0,00,0.0,0.0,M,0.0,M,,0000*6D

$GPGSA,A,1,,,,,,,,,,,,,0.0,0.0,0.0*30

$GPRMC,120056.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*7C

$GPVTG,000.0,T,,M,000.0,N,000.0,K,N*02

Genau das sehe ich auch, wenn ich folgendes Programm auf den AVR 
schreibe und mir anschaue was der AVR sendet:
#define F_CPU 7372800UL  

#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.c"

uint8_t main(void)
{
  while(1)
  {
  }
}

ISR(USART_RX_vect)
{
  unsigned char character;
  character = UDR0;
  uart_putc(character);
}

Soweit ist ja alles ok, nur wenn ich alles in der ISR in einen Buffer 
schreibe und dann den Buffer per UART ausgebe, sind nur noch die $GPRMC 
und $GPGGA Datensätze da...

Hier mein Code:
#define F_CPU 7372800UL  

#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.c"

volatile uint8_t string_received = 0;
volatile uint8_t i = 0;
char buffer[100] = {0};

uint8_t main(void)
{
  while(1)
  {
    if(string_received == 1)
    {
      uart_puts(buffer);
      string_received = 0;
    }
  }
}

ISR(USART_RX_vect)
{
  unsigned char character;
  character = UDR0;

  if(character == '\n' || i == 99)
  {
    buffer[i] = '\0';
    i = 0;
    string_received = 1;
  }
  else
  {
    buffer[i] = character;
    i++;
  }
}

Also gehen wohl irgendwo die Datensätze verloren.. nur wieso?!
Ich habe dann versucht in der main loop nur den 4. Buchstaben im Buffer 
auszugeben, also so:
while(1)
{
  if(string_received == 1)
  {
    uart_putc(buffer[3]);
    string_received = 0;
  }
}
Mit diesem Code sehe ich das hier im Terminal:
GGRVGGRV

Also werden doch anscheinend alle Datensätze in den Buffer geschrieben?!
Und wieso sehe ich dann nicht alle wenn ich den kompletten Buffer 
ausgeben will?

Ich hoffe ihr versteht mein Problem und habt eventuell einen 
Lösungsvorschlag...
Danke schonmal für eure Hilfe ;)

Viele Grüße

: Verschoben durch Moderator
Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ups, der Beitrag sollte eigentlich ins "µC & Elektronik" Forum.. wäre 
nett wenn das jemand verschieben könnte :)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
johannes schrieb:

>   while(1)
>   {
>     if(string_received == 1)
>     {
>       uart_puts(buffer);

Wie sieht uart_puts aus.

Dein GPS Empfänger ist nicht so freundlich mit der nächsten Übertragung 
zuzuwarten, bis du dann endlich deine Zeile mittels uart_puts an den 
Mann gebracht hast.

Du musst da schon double-buffern.
Während uart_puts die Zeile seinerseits absetzt, muss der 
Empfangsinterrupt die in der Zwischenzeit hereinkommenden Zeichen 
irgendwo zwischenspeichern. Und zwar ohne dass er sich mit dem Buffer in 
die Quere kommt, aus dem uart_puts heraus seine Zeile an den PC schickt.

Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ;)

hier erstmal der Code für die Serielle Schnittstelle:
void uart_putc(unsigned char data)
{
  while( !(UCSR0A & (1<<UDRE0)) )
  {
  }

  UDR0 = data;
}


void uart_puts(char *string)
{
  while(*string)
  {
          uart_putc(*string);
          string++;
  }
}

Selbst wenn ich 2 Buffer verwende geht es nicht.. Hier der Code dazu:
#define F_CPU 7372800UL  

#include <avr/io.h>
#include <avr/interrupt.h>
#include "uart.c"

volatile uint8_t string_received = 0;

volatile uint8_t i = 0;
char buffer1[100] = {0};
char buffer2[100] = {0};

char* buffer_interrupt = buffer1;
char* buffer_evaluate = buffer2;

uint8_t main(void)
{
  while(1)
  {
    if(string_received == 1)
    {
      uart_puts(buffer_evaluate);
      string_received = 0;
    }
  }

  return 0;
}

ISR(USART_RX_vect)
{
  unsigned char character;
  character = UDR0;

  if(character == '\n' || i == 99)
  {
    buffer_interrupt[i] = '\0';
    i = 0;

    char* tmp;
    tmp = buffer_interrupt;
    buffer_interrupt = buffer_evaluate;
    buffer_evaluate = tmp;

    string_received = 1;
  }
  else
  {
    buffer_interrupt[i] = character;
    i++;
  }
}

Im Terminal kommen nur die $GPRMC und $GPGGA Datensätze an.
Langsam weiß ich echt nicht mehr an was das liegen könnte..

Danke für deine Hilfe ;)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn die ISR einen kürzeren Datensatz schneller empfangen kann, als dein 
Pgm benötigt um einen längeren Datensatz auf den Weg zu bringen, dann 
stimmt das string_received Flag nicht mehr. In der Hauptschleife löscht 
du dir nach dem uart_puts dann unter Umständen die 1 in der die ISR die 
Vollständigkeit des nächsten Datensatzes vermerkt hat.
uint8_t main(void)
{
  while(1)
  {
    if(string_received == 1)
    {
      string_received = 0;
      uart_puts(buffer_evaluate);
    }
  }

  return 0;
}

Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wow, danke :)
genau das wars... ;)

Auf sowas komm ich natürlich nicht..
Nochmals Danke :)

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

könnte mir das vlt noch einer erklären? Oder einen Link geben der dieses 
Verhalten erklärt?
Ich versteh nicht wieso ich mehr Zeichen empfangen kann, wenn ich die 
Variable vor dem Senden verändere und nicht nach dem Senden?!

mfg

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus B. schrieb:
> Hallo,
>
> könnte mir das vlt noch einer erklären? Oder einen Link geben der dieses
> Verhalten erklärt?
> Ich versteh nicht wieso ich mehr Zeichen empfangen kann, wenn ich die
> Variable vor dem Senden verändere und nicht nach dem Senden?!

Weil hier dem Grunde nach 2 'Prozesse' gleichzeitig ablaufen.

der eine Prozess sendet und wenn er fertig ist setzt er eine Variable 
auf 0
der andere Prozess empfängt und wenn er fertig ist setzt er dieselbe 
Variable auf 1


Ist nun der Empfangsprozess schneller fertig, dann setzt er 
pflichtgemäss die Variable auf 1
Irgendwann später wird dann auch der Sendeprozess fertig und setzt 
danach die Variable auf 0

-> die vorher gesetzte 1 geht verloren, denn der Sendeprozess hat ja zum 
Schluss auf jeden Fall eine 0 gesetzt.

Damit ist aber auch dem Vergessen anheim gefallen, dass in der 
Zwischenzeit der Empfangsprozess eine neue komplette Zeile empfangen 
hat.


Das ist eine ganz normale Race-Condition, wie sie in Multitasking 
Systemen immer wieder auftritt und die saubere Lösung dafür lautet: 
Nicht ein Flag setzen oder löschen, sondern mit einer Semphore einen 
Zähler einrichten. Hat der Empfangsthread eine Zeile fertig, erhöht er 
die Sempahore um 1. Hat der Sendethread eine Zeile fertig verschickt, 
erniedrigt er die Semaphore um 1. Damit stimmt dann der Zähler immer, 
indem ein Zählerstand > 1 anzeigt, dass es noch (mindestens) 1 Zeile 
gibt, die zwar schon vollständig empfangen, aber noch nicht verschickt 
wurde.

In diesem speziellen Fall, lässt sich das Problem auch durch eine simple 
Codemodifikation umgehen. Dies auch mit dem Hintergrund, dass das Pgm 
sowieso nicht in der Lage ist, mehr als 1 komplette Zeile 
zwischenzuspeichern. Sobald der GPS Empfänger viele kurze Zeilen auf 
eine lange Zeile folgen lässt UND zwischen den Zeilen kaum Sendepausen 
einbaut, geht das alles sowieso grauslich den Bach runter.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mir eine Analogie einfallen lassen :-)

Du kennst doch die amerikanischen Briefkästen. Die haben so ein Fähnchen 
an der Aussenseite. Kommt der Postler und legt was in den Briefkasten, 
dann klappt er das Fähnchen hoch.
                            |--+
                            |**|              <---- Fähnchen
                            |--+
                          +-o--------+
                          |          |
                          |          |
                          |######### |        <---- Post
                          +----------+
                                |
                                |
                                |

Das Fähnchen sieht der Besitzer vom Haus aus und geht dann die Post 
holen. Hat er die Post geholt, dann klappt er das Fähnchen wieder 
runter. Wenn seine Frau dann am Nachmittag aus dem Fenster sieht, weiß 
sie, dass keine Post im Briefkasten liegt.
                            o----
                          +---|*|----+
                          |   |*|    |
                          |   +-+    |
                          |          |        <---- keine Post
                          +----------+
                                |
                                |
                                |

Man kann also sagen: Das Fähnchen ist ein Indikator, dass Post im 
Briefkasten ist.

Gut.
Jetzt folgende Reihenfolge der Ereignisse

Der Briefkasten sei leer
                            o----
                          +---|*|----+
                          |   |*|    |
                          |   +-+    |
                          |          |
                          +----------+
                                |
                                |
                                |

Der Postler kommt und legt Briefe hinein. Pflichtbewusst stellt er das 
Fähnchen hoch
                            |--+
                            |**|
                            |--+
                          +-o--------+
                          |          |
                          |          |
                          |######### |
                          +----------+
                                |
                                |
                                |

Jetzt kommt der Besitzer aus dem Haus und holt sich seine Post. Aber er 
nimmt sie nur aus dem Briefkasten heraus und beginnt sie zu bearbeiten, 
zu lesen!
Der Briefkasten ist also in diesem Zustand
                            |--+
                            |**|
                            |--+
                          +-o--------+
                          |          |
                          |          |
                          |          |
                          +----------+
                                |
                                |
                                |
normalerweise ist das auch kein Problem, denn bis der Postler erneut 
kommt, ist der Besitzer mit dem Lesen der Post längst fertig und ehe er 
ins Haus geht, klappt er dann auch noch das Fähnchen runter.

Doch heute ist es anders.
Während der Besitzer noch mit dem Lesen beschäftigt ist, kommt der 
Postler erneut, legt etwas in den Briefkasten und setzt das Fähnchen 
(welches schon gesetzt ist, aber das kümmert den Postler nicht, er 
handelt stur nach Vorschrift)
                            |--+
                            |**|
                            |--+
                          +-o--------+
                          |          |
                          |          |
                          |######### |
                          +----------+
                                |
                                |
                                |
Der Besitzer des Briefkastens war so beschäftigt, dass er gar nicht 
registriert hat, dass der Postler in der Zwischenzeit noch einmal da 
war. Irgendwann ist dann auch der Besitzer mit dem Lesen der Post fertig 
und wie es seine Gewohnheit ist, klappt er vor dem Zurückgehen ins Haus 
auch noch das Fähnchen runter
                            o----
                          +---|*|----+
                          |   |*|    |
                          |   +-+    |
                          |######### |
                          +----------+
                                |
                                |
                                |

und damit haben wir jetzt im Postkasten eine Fehlersituation: Im 
Briefkasten liegt Post aber das Fähnchen zeigt diesen Zustand nicht an.

Wie ist es dazu gekommen
* der Prozess des Bearbeitens hat länger gedauert als die Zeitabstände
  in der der Postler gekommen ist
* der Benutzer hat seine Bearbeitung begonnen, ehe er den Indikator
  zurückgesetzt hat. Würde er seine Gewohnheit ändern, und das Fähnchen
  zurücksetzen, ehe er die Post herausnimmt dann wäre zumindest dieser
  Fehler nicht aufgetreten. (Aber man kann dann andere Fehlersituationen
  konstruieren :-)

Autor: Markus B. (rusticus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen vielen Dank für die tolle Erklärung!

Jetzt ist mir das auch klar :)

Deine Ausführung hier erinnert mich ein bischen an einen Fifo-Buffer

Karl heinz Buchegger schrieb:
> Das ist eine ganz normale Race-Condition, wie sie in Multitasking
> Systemen immer wieder auftritt und die saubere Lösung dafür lautet:
> Nicht ein Flag setzen oder löschen, sondern mit einer Semphore einen
> Zähler einrichten. Hat der Empfangsthread eine Zeile fertig, erhöht er
> die Sempahore um 1. Hat der Sendethread eine Zeile fertig verschickt,
> erniedrigt er die Semaphore um 1. Damit stimmt dann der Zähler immer,
> indem ein Zählerstand > 1 anzeigt, dass es noch (mindestens) 1 Zeile
> gibt, die zwar schon vollständig empfangen, aber noch nicht verschickt
> wurde.

Wenn ich nun statt gesendet abfrage ob im Buffer was drin ist, kann ich 
dann damit Problemlos arbeiten?

Wenn ich was empfangen stopft er ja das Zeug in den Fifo und erhöht ne 
Variable, Index usw und wenn ich was raussende, muss ich halt dieses 
wieder erniedrigen bzw was anderes erhöhen und vergleichen, oder nicht?

Oder treten so auch wieder zu viele Fehler auf? Bzw können

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.