Forum: Mikrocontroller und Digitale Elektronik GPS Empfänger an ATmega8


von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Hallo,
habe will einen von den GPS- Empfängern aus diesem Thread hier 
(Beitrag "GPS - Empfänger günstig bei Ebay")
an einen ATmega8 anschliessen, und erstmal die aktuelle Geschwindigkeit 
auf einem LCD ausgeben.
Ich habe die lcd-lib hier aus dem Forum, und die UART-lib von Peter 
Fleury verwendet. Das LCD funktioniert, und das GPS- Modul ist korrekt 
an RX und TX angeschlossen.
Allerdings empfange ich keine Daten von GPS- Modul.....(oder vielleicht 
doch, aber sie werden nicht auf dem LCD ausgegeben?)

Hier mal mein Sourcecode, der übrigends bis auf 7 Warnings fehlerfrei 
erstellt wird:
1
#include <avr/io.h>
2
#define F_CPU 4000000
3
#include <util/delay.h>
4
#include <stdlib.h>
5
#include <avr/interrupt.h>
6
7
#include "lcd-routines.h"
8
#include <uart.h>
9
10
#define UART_BAUD_RATE  9600   
11
12
13
int main(void)
14
{
15
unsigned char empfangen[5],nmea[3] ="",kmh_string[4],temp;
16
float kmh,nurzumrechnen;
17
18
//Uart und LCD initialisieren
19
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
20
lcd_init();
21
lcd_string("Start!");
22
23
24
while(1)
25
{
26
27
temp = uart_getc();
28
//Zum Überprüfen
29
lcd_string(temp);
30
31
32
if(temp == '$')
33
{
34
//zwei Zeichen nach $ verwerfen
35
temp = uart_getc();
36
temp = uart_getc();
37
//Variablen zum Testen, ob RMC
38
nmea[0] = uart_getc();
39
//jeweils zum Test auf Display ausgeben
40
lcd_string(nmea[0]);
41
nmea[1] = uart_getc();
42
lcd_string(nmea[1]);
43
nmea[2] = uart_getc();
44
lcd_string(nmea[2]);
45
}
46
47
//Nach "E," kommt Geschwindigkeit in Knoten
48
if(temp == 'E')
49
{
50
//Nur RMC auslesen, denn nur dort ist Geschwindigkeit (in Knoten)
51
if(uart_getc() == ',' && nmea[0] == 'R' && nmea[1] == 'M' && nmea[2] == 'C') 
52
{
53
lcd_string("Fix gefunden!");
54
55
//Geschwindigkeit enpfangen
56
empfangen[0] = uart_getc();  
57
empfangen[1] = uart_getc();
58
empfangen[2] = uart_getc();
59
empfangen[3] = uart_getc();
60
empfangen[4] = uart_getc();
61
62
//Wenn Geschwindigkeit noch 2-stellig vor dem Komma, 2. Stelle hinter dem Komma = 0
63
}
64
if(empfangen[2] == '.')
65
{
66
empfangen[4] = '0';
67
}
68
//Den String "empfangen" in float umwandeln, zum Rechnen
69
nurzumrechnen=atof(empfangen);
70
//Knoten in kmh umrechnen
71
kmh = nurzumrechnen * 1.852;
72
//float wieder in String umwandeln, zum auf LCD ausgeben
73
itoa(kmh,kmh_string,10);
74
//kmh auf LCD ausgeben
75
lcd_string(kmh_string);
76
}
77
}
78
}

Vielleicht fällt ja jemandem etwas auf, was ich noch verbessern kann.
Wie man das GPS- Modul auf 9600 Baud einstellen kann, weiß ich nicht 
genau, ich hab einfach mit SIRFDemo das NMEA- Protokoll eingestellt, und 
dabei auch 9600 Baud. Allerdings weiß ich nicht, ob die Einstellungen 
gespeichert werden, oder ob ich das über den µC jedesmal neu 
konfigurieren muss.

Vielen Dank schon einmal im Voraus.
Gruß, Steffen

von holger (Gast)


Lesenswert?

Wie wäre es mit einem sei(); vor while(1) ?

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ok, werd ich einfügen. Ist das für die UART-lib, oder?

Gruß, Steffen

von holger (Gast)


Lesenswert?

>Ok, werd ich einfügen. Ist das für die UART-lib, oder?

Ja.

Wird aber auch nicht funktionieren weil uart_getc()
nicht auf ein Zeichen wartet.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Aha, muss ich dann noch eine Funktion machen, die solange wartet, bis 
ein Zeichen da ist, also z.B. so:
1
void getchar()
2
{
3
unsigned char zeichen[1];
4
5
do
6
{
7
zeichen=uart_getc();
8
} while (zeichen=="Wie schreiben, dass zeichen nichts enthält??")
9
10
return zeichen[0];
11
}

Würde das so funktionieren? Wie kann ich schreiben, dass die Variable 
"zeichen" nichts enthält?

Gruß, Steffen

von Teplotaxl X. (t3plot4x1)


Lesenswert?

zeichen==0
Wie wärs damit?

von holger (Gast)


Lesenswert?

>Aha, muss ich dann noch eine Funktion machen, die solange wartet, bis
>ein Zeichen da ist, also z.B. so:

Gute Idee.

>void getchar()

void ist aber nicht gut wenn man einen Wert zurückgeben will ;)

Und unsigned char zeichen[1]; kann man auf char zeichen, reduzieren.

Aber damit bist du immer noch nicht am Ziel.

>Wie kann ich schreiben, dass die Variable
>"zeichen" nichts enthält?

uart_getc() gibt einen bestimmten Wert zurück wenn
noch kein Zeichen da ist. Einfach mal in den Beispielcode schauen?
Der Wert ist ein unsigned int und kein char.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Sir alan Teplotaxl wrote:
>zeichen==0
>Wie wärs damit?

Aber wenn uart_getc() noch  nchts empfängt, dann steht doch in der 
Variable zeichen gar nichts, auch keine 0, oder?


holger wrote:
>>Aha, muss ich dann noch eine Funktion machen, die solange wartet, bis
>>ein Zeichen da ist, also z.B. so:
>
> Gute Idee.
>
>>void getchar()
>
> void ist aber nicht gut wenn man einen Wert zurückgeben will ;)

Ja, ich werde dann int verwenden ;-).

> Und unsigned char zeichen[1]; kann man auf char zeichen, reduzieren.

Ok, mach ich auch.

> Aber damit bist du immer noch nicht am Ziel.

>>Wie kann ich schreiben, dass die Variable
>>"zeichen" nichts enthält?
>
> uart_getc() gibt einen bestimmten Wert zurück wenn
> noch kein Zeichen da ist. Einfach mal in den Beispielcode schauen?
> Der Wert ist ein unsigned int und kein char.

Im Beispiel von Peter Fleury wird das so gemacht:
1
unsigned int c;
2
....
3
c= uart_getc();
4
        if ( c & UART_NO_DATA )
5
        {
6
            /* 
7
             * no data available from UART 
8
             */
9
        }
10
        else
11
        {
12
            /*
13
             * new data available from UART
14
             * check for Frame or Overrun error
15
             */
16
            if ( c & UART_FRAME_ERROR )
17
            {
18
                /* Framing Error detected, i.e no stop bit detected */
19
                uart_puts_P("UART Frame Error: ");
20
            }
21
            if ( c & UART_OVERRUN_ERROR )
22
            {
23
                /* 
24
                 * Overrun, a character already present in the UART UDR register was 
25
                 * not read by the interrupt handler before the next character arrived,
26
                 * one or more received characters have been dropped
27
                 */
28
                uart_puts_P("UART Overrun Error: ");
29
            }
30
            if ( c & UART_BUFFER_OVERFLOW )
31
            {
32
                /* 
33
                 * We are not reading the receive buffer fast enough,
34
                 * one or more received character have been dropped 
35
                 */
36
                uart_puts_P("Buffer overflow error: ");
37
            }
38
            /* 
39
             * send received character back
40
             */
41
            uart_putc( (unsigned char)c );
42
        }

Soll ich einfach das alles in die Funktion getchar() packen?

Gruß, Steffen

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ich hab die Funktion getchar() nun mal so gemacht:
1
int getchar()
2
{
3
unsigned int c;
4
do
5
{
6
c = uart_getc();
7
        
8
    if ( c & UART_NO_DATA )
9
        {
10
            /* 
11
             * no data available from UART 
12
             */
13
        }
14
        else
15
        {
16
            /*
17
             * new data available from UART
18
             * check for Frame or Overrun error
19
             */
20
            if ( c & UART_FRAME_ERROR )
21
            {
22
                /* Framing Error detected, i.e no stop bit detected */
23
                lcd_string("UART Frame Error: ");
24
            }
25
            if ( c & UART_OVERRUN_ERROR )
26
            {
27
                /* 
28
                 * Overrun, a character already present in the UART UDR register was 
29
                 * not read by the interrupt handler before the next character arrived,
30
                 * one or more received characters have been dropped
31
                 */
32
                lcd_string("UART Overrun Error: ");
33
            }
34
            if ( c & UART_BUFFER_OVERFLOW )
35
            {
36
                /* 
37
                 * We are not reading the receive buffer fast enough,
38
                 * one or more received character have been dropped 
39
                 */
40
                lcd_string("Buffer overflow error: ");
41
            }
42
      }
43
      }while(c==0);
44
      
45
      return( (unsigned char) c);
46
}

Laut Bsp. müsste das doch richtig sein, oder?

Gruß, Steffen

von holger (Gast)


Lesenswert?

>      }while(c==0);

Das ist noch falsch. UART_NO_DATA?

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

OK, ich hab nun die Austrittsbedingung so gemacht:
}while(UART_NO_DATA)

Muss ich da nicht schauen, ob die Variable c Daten enthält? Weil so 
überprüfe ich ja nochmal den UART, aber da wurden die Daten ja schon 
abgeholt.
Wie überprüfe ich, ob die Variable c irgendeinen Inhalt hat?

Gruß, Steffen

von holger (Gast)


Lesenswert?

}while(c==UART_NO_DATA);

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ok, hab ich nun so gemacht. Allerdings kommen immernoch keine Daten vom 
GPS-Modul an. Ich glaub ich muss echt noch eine Baudrateneinstellung 
beim GPS-Modul machen.
Kommt eigentlich bei jeder Baudrate was an, wenn es die falsche ist, 
eben nur Unsinn?

Gruß, Steffen

von holger (Gast)


Lesenswert?

>Kommt eigentlich bei jeder Baudrate was an, wenn es die falsche ist,
>eben nur Unsinn?

In der Regel ja. Hast du vieleicht RxD und TxD vertauscht? GND 
angeschlossen?
Wie sieht deine Schaltung aus?

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

GND is angeschlossen, und RX und TX sind eigentlich auch nicht 
vertauscht. Wenn ich die beiden mal vertausche, dann kommen auf dem LCD 
zig Zeichen, die aber alle keinen Sinn ergeben.

Die Schaltung hab ich auf einem BReadboard von Reichelt aufgebaut, kann 
es sein, dass deswegen die 9600 Baud nicht klappen?

Gruß, Steffen

von holger (Gast)


Lesenswert?

>Wenn ich die beiden mal vertausche, dann kommen auf dem LCD
>zig Zeichen, die aber alle keinen Sinn ergeben.

Ja, ja, ja ...... dann ist es richtig rum !
Stell mal die Baudrate auf 4800 Baud.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ok, ich hab nun die Baudrate bei 4800 Baud, aber da kommt beim 
Einschalten gleich mal UART Frame Error, und irgendwann dann auch noch 
ein Buffer Overflow :-(.

Also kann die Einstellung irgendwie nicht stimmen, oder?
Vielleicht muss ich noch beim Modul die Baudrate einstellen....

Gruß, Steffen

von holger (Gast)


Lesenswert?

Vieleicht brauchst du einen MAX232 am ATMega?

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

holger wrote:
> Vieleicht brauchst du einen MAX232 am ATMega?
Quatsch! Hab das Modul auch an nem Mega16 hängen ohne alles.... Versuch 
mal 38400baud, das ist die Standardeinstellung des Moduls.
Ich hab das zu debugging zwechen so gemacht das ich RX des Megas 
zusätzlich an eine MAX232 und an die Serielle des PCs dann sieht man 
alles was der µC empfangen sollte nochmal auf dem PC und kann dann 
leichter verifizieren was überhaupt ankommt.
Ich würde an deiner Stelle erstmal so anfange, das du alle Empfangenen 
Zeichen bis zum \r\n auf dem LCD darstellst so das du siehst ob der 
String überhaupt korrekt ankommt.

Ich mache das folgendermaßen: (Pseudocode!)
1
Buffer[100]
2
counter = 0;
3
while(1) {
4
 c = getChar();
5
 if (c == '$') {
6
  counter = 0;
7
 }
8
 if(c == '\n') {
9
  break;
10
 }
11
 Buffer[counter++] = c;
12
}
13
toLCD(Buffer);
Danach kannst du den String in Ruhe zerlegen :)

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Ok, ich werd dann morgen mal meinen PC parallel dazu dranhängen, dann 
sieht man was ankommt, bzw. sollte.
Ich hab nun mal 38400 Baud eingestellt, dann kommt nach dem Einschalten 
UART Frame Error, und danach beide Zeilen des Dislays voll mit X und 
einem Strich jeweils darüber.
Kann es auch sein, dass es nicht klappt, weil die Leitungen des 
Breadboards bei 38400 Baud irgendwie nicht mehr mitspielen?

Hast du auch die rote Leitung an RX, und die weiße an TX?

Ich hab nun mal deine Funktion verwendet, aber ich bekomme weiterhin 
einen UART Frame Error, nun eben nicht mit den X und den Strichen 
drüber....


Vielen Dank schon einmal im Voraus.
Gruß, Steffen

von spess53 (Gast)


Lesenswert?

Hi

Was benutzt du als Takt?

MfG Spess

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Einen 4Mhz Quarzoszillator an XTAL1 angeschlossen, und den Controller 
auf external clock gefused.
Meinst du ich soll einen Baudratenqurz verwenden?
Ich hab mit dem 4Mhz Oszillator auch schon mit dem PC kommuniziert, usw.

Gruß, Steffen

von spess53 (Gast)


Lesenswert?

Hi

Zumindest wollte ich erst mal sicherstellen, das kein RC-oszillator im 
Spiel ist.

Welche Teile deines Programms hast du schon einzeln getestet, und bist 
sicher das die funktionieren. Nur als Hintergrund: Schaltung aufbauen, 
Programm schreiben und geht, läuft selten.

Mein persönlicher Ansatz wäre einen kompletten NMEA-Sring in einen 
Puffer einlesen, und dann in Ruhe auswerten

MfG Spess

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Teste erstmal mit dem PC. Da kannst du auch sehen ob die Baudrate 
stimmt, ohne richtige Baudrate kommt nur mist raus. ;)

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

So, nun hab ich den Empfänger an den Mega8 angeschlossen, und dazwischen 
einen Pegelwandel, der an den PC mit nem Terminalprogramm angeschlossen 
ist.
Der GPS-Empfänger sendet brav seinen NMEA Datensatz, bei 9600 Baud, wie 
ich es eingestellt hatte. Am Terminalprogramm kann ich alle Strings gut 
lesen, und es sind keine falschen Zeichen dabei.

Also liegt es definitiv am µC, bzw. der Software. Ich poste hier nochmal 
meinen kompletten Code, der eigentlich bei 4Mhz funktionieren sollte, 
vielleicht wisst ihr ja noch was.
1
#include<avr/io.h>
2
#define F_CPU 4000000
3
#include<util/delay.h>
4
#include <stdlib.h>
5
#include <avr/interrupt.h>
6
7
#include "lcd-routines.h"
8
#include <uart.h>
9
10
#define UART_BAUD_RATE   9600
11
12
int getchar()
13
{
14
unsigned int c;
15
do
16
{
17
c = uart_getc();
18
        
19
    if ( c & UART_NO_DATA )
20
        {
21
            /* 
22
             * no data available from UART 
23
             */
24
        }
25
        else
26
        {
27
            /*
28
             * new data available from UART
29
             * check for Frame or Overrun error
30
             */
31
            if ( c & UART_FRAME_ERROR )
32
            {
33
                /* Framing Error detected, i.e no stop bit detected */
34
                lcd_string("UART Frame Error: ");
35
            }
36
            if ( c & UART_OVERRUN_ERROR )
37
            {
38
                /* 
39
                 * Overrun, a character already present in the UART UDR register was 
40
                 * not read by the interrupt handler before the next character arrived,
41
                 * one or more received characters have been dropped
42
                 */
43
                lcd_string("UART Overrun Error: ");
44
            }
45
            if ( c & UART_BUFFER_OVERFLOW )
46
            {
47
                /* 
48
                 * We are not reading the receive buffer fast enough,
49
                 * one or more received character have been dropped 
50
                 */
51
                lcd_string("Buffer overflow error: ");
52
            }
53
      }
54
      }while(c==UART_NO_DATA);
55
      
56
      return( (unsigned char) c);
57
}
58
59
int main(void)
60
{
61
unsigned char empfangen[5],nmea[3] ="",kmh_string[4],temp,Buffer[100];
62
float kmh,nurzumrechnen;
63
int counter,c;
64
65
//Uart und LCD initialisieren
66
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
67
lcd_init();
68
lcd_string("Start!");
69
_delay_ms(1000);
70
lcd_clear();
71
72
sei();
73
74
75
while(1)
76
{
77
78
temp = getchar();
79
//Zum Überprüfen
80
lcd_string(temp);
81
82
83
if(temp == '$')
84
{
85
//zwei Zeichen nach $ verwerfen
86
temp = getchar();
87
temp = getchar();
88
//Variablen zum Testen, ob RMC
89
nmea[0] = getchar();
90
//jeweils zum Test auf Display ausgeben
91
lcd_string(nmea[0]);
92
nmea[1] = getchar();
93
lcd_string(nmea[1]);
94
nmea[2] = getchar();
95
lcd_string(nmea[2]);
96
}
97
98
//Nach "E," kommt Geschwindigkeit in Knoten
99
if(temp == 'E')
100
{
101
//Nur RMC auslesen, denn nur dort ist Geschwindigkeit (in Knoten)
102
if(getchar() == ',' && nmea[0] == 'R' && nmea[1] == 'M' && nmea[2] == 'C') 
103
{
104
lcd_string("Fix gefunden!");
105
106
//Geschwindigkeit enpfangen
107
empfangen[0] = getchar();  
108
empfangen[1] = getchar();
109
empfangen[2] = getchar();
110
empfangen[3] = getchar();
111
empfangen[4] = getchar();
112
113
//Wenn Geschwindigkeit noch 2-stellig vor dem Komma, 2. Stelle hinter dem Komma = 0
114
}
115
if(empfangen[2] == '.')
116
{
117
empfangen[4] = '0';
118
}
119
//Den String "empfangen" in float umwandeln, zum Rechnen
120
nurzumrechnen=atof(empfangen);
121
//Knoten in kmh umrechnen
122
kmh = nurzumrechnen * 1.852;
123
//float wieder in String umwandeln, zum auf LCD ausgeben
124
itoa(kmh,kmh_string,10);
125
//kmh auf LCD ausgeben
126
lcd_string(kmh_string);
127
}
128
}
129
}

Auf dem Display erscheinen, wenn ich alles angeschlossen habe 
irgendwelche Zeichen, in !beiden! Zeilen, und irgendwo dazwischen kommen 
mal Bruchstücke von Overflow Error, usw..
Irgendwann kommt auch mal ein Teil von "Fix gefunden".....

Ich bin echt scheon ein wenig verzweifelt, weil ich nicht weiß, woran es 
liegt, und es partout nicht klappen will :-(.
Ich hoffe, jemand weiß noch Rat....

Vielen Dank schon einmal im Voraus.
Gruß, Steffen

von holger (Gast)


Lesenswert?

>lcd_string(temp);
>lcd_string(nmea[0]);

temp ist kein String. nmea[0] ist auch kein String.
Wenn du lcd_string() nur ein char übergibst jagt es
quer durch den Speicher und gibt alles aus was nicht 0 ist.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Also soll ich dann "temp" mit unsigned char temp[1] initialisieren, und 
immer wenn es gebraucht wird eben temp[0] schreiben?
Und bei der Ausgabe mit lcd_string nicht einen einzelnen Wert (temp[0]), 
sondern einfach lcd_string(temp) ?

Wenn dann alles ausgegeben wird, was nicht 0 ist, würde das erklären, 
warum da überall irgendwelche Zeichen auf dem Display erscheinen.
Ich werde es mal versuchen.

Gruß, Steffen

von Stefan E. (sternst)


Lesenswert?

Nein, du solltest eine LCD-Funktion benutzen, die keinen String ausgibt, 
sondern nur ein einzelnes Zeichen, wie auch immer die bei der LCD-Lib 
heißen mag (geben tut es sie bestimmt, vielleicht lcd_putc?).

von holger (Gast)


Lesenswert?

Gibt es ein lcd_char() oder lcd_byte() in deiner LIB?
Dann nimm das.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Nein, in meiner lib gibt es lcd_data, ich glaub mit dem gibt man immer 
nur ein Zeichen aus. Ganz sicher bin ich mir aber nicht, ich werde es 
schnell mal nachprüfen. Wenn es das richtige sein sollte, einfach alle 
lcd_string durch lcd_data ersetzen?

Gruß, Steffen

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

Bei lcd_data steht: Sendet ein Datenbyte an das LCD
Das wird dann das richtige sein, oder?

Gruß, Steffen

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

So, hab nun mal alle lcd_string durch lcd_data ersetzt, nun komt nach 
dem Einschalten UART Frame Error (die Meldung kommt eigentlich jedesmal, 
egal was ich am Code veränder!), und dann nur noch das Zeichen E, in 
beiden Zeilen.

Gruß, Steffen

von holger (Gast)


Lesenswert?

>So, hab nun mal alle lcd_string durch lcd_data

Nein ! Ich dreh durch :( Doch nicht ALLE.
Nur die wo nur EIN Zeichen übergeben wird.

von Steffen O. (derelektroniker) Benutzerseite


Lesenswert?

holger wrote:
>>So, hab nun mal alle lcd_string durch lcd_data
>
> Nein ! Ich dreh durch :( Doch nicht ALLE.
> Nur die wo nur EIN Zeichen übergeben wird.

Ja, ich hab natürlich nur die geändert, wo ein Zeichen übergeben wird, 
bei denen, wo ein String übergeben wird, steht natürlich noch 
lcd_string.

Gruß, Steffen

von Claudio (Gast)


Lesenswert?

Hallo Steffan

Wo hast du deinen GPS Empfänger her?
Weiss jemand wo man günstig GPS Empfänger herbekommt?

Ich bräuchte auch ein paar... so günstig wie möglich... :)

Liebe Grüsse
Claudio

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.