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:
Genau das sehe ich auch, wenn ich folgendes Programm auf den AVR
schreibe und mir anschaue was der AVR sendet:
1
#define F_CPU 7372800UL
2
3
#include<avr/io.h>
4
#include<avr/interrupt.h>
5
#include"uart.c"
6
7
uint8_tmain(void)
8
{
9
while(1)
10
{
11
}
12
}
13
14
ISR(USART_RX_vect)
15
{
16
unsignedcharcharacter;
17
character=UDR0;
18
uart_putc(character);
19
}
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:
1
#define F_CPU 7372800UL
2
3
#include<avr/io.h>
4
#include<avr/interrupt.h>
5
#include"uart.c"
6
7
volatileuint8_tstring_received=0;
8
volatileuint8_ti=0;
9
charbuffer[100]={0};
10
11
uint8_tmain(void)
12
{
13
while(1)
14
{
15
if(string_received==1)
16
{
17
uart_puts(buffer);
18
string_received=0;
19
}
20
}
21
}
22
23
ISR(USART_RX_vect)
24
{
25
unsignedcharcharacter;
26
character=UDR0;
27
28
if(character=='\n'||i==99)
29
{
30
buffer[i]='\0';
31
i=0;
32
string_received=1;
33
}
34
else
35
{
36
buffer[i]=character;
37
i++;
38
}
39
}
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:
1
while(1)
2
{
3
if(string_received==1)
4
{
5
uart_putc(buffer[3]);
6
string_received=0;
7
}
8
}
Mit diesem Code sehe ich das hier im Terminal:
1
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
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.
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.
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
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.
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.
1
|--+
2
|**| <---- Fähnchen
3
|--+
4
+-o--------+
5
| |
6
| |
7
|######### | <---- Post
8
+----------+
9
|
10
|
11
|
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.
1
o----
2
+---|*|----+
3
| |*| |
4
| +-+ |
5
| | <---- keine Post
6
+----------+
7
|
8
|
9
|
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
1
o----
2
+---|*|----+
3
| |*| |
4
| +-+ |
5
| |
6
+----------+
7
|
8
|
9
|
Der Postler kommt und legt Briefe hinein. Pflichtbewusst stellt er das
Fähnchen hoch
1
|--+
2
|**|
3
|--+
4
+-o--------+
5
| |
6
| |
7
|######### |
8
+----------+
9
|
10
|
11
|
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
1
|--+
2
|**|
3
|--+
4
+-o--------+
5
| |
6
| |
7
| |
8
+----------+
9
|
10
|
11
|
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)
1
|--+
2
|**|
3
|--+
4
+-o--------+
5
| |
6
| |
7
|######### |
8
+----------+
9
|
10
|
11
|
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
1
o----
2
+---|*|----+
3
| |*| |
4
| +-+ |
5
|######### |
6
+----------+
7
|
8
|
9
|
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 :-)
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