Hallo,
ich habe ein GPS-Modul welches brav und schön sauber Daten an das
Hyperterminal sendet.
Diese Daten möchte ich mit meinem PIC auswerten.
Habe zuerst einmal ein ganz simples Programm geschrieben, welches Daten
ab dem $-Zeichen in einen String kopiert, bis zu dem *-Zeichen.
Das Programm funktioniert im Debugger, sprich alle vorgegebenen Zeichen
im RCREG1-Register werden in den String, Register für Register
beschrieben.
Bei dem *-Zeichen wird die Schleife verlassen.
Jedoch funktioniert die Zeichenausgabe nur im Debugger.
In der Hardware wird nur der erste Buchstabe, ab zu zu mal richtig
angezeigt (NMEA Protokoll ist das ein 'G').
Ich vermute, dass es letztendlich an der Baudrate hängt, jedoch wird ein
Baudratenfehler von 0.17% von meinem Compiler ausgespuckt.
Bin einen kleinen Schritt weitergekommen.
Und zwar hab ich gemerkt, dass ca. ab dem String[80] die Daten stimmen.
Was hat das zu bedeuten? Kann das sein, dass das UART-Modul vom PIC ab
da erst richtig arbeitet? Schon drei Tage versuch ichs und bin mit
meinem Latein am Ende.
Übrigens, arbeitet der PIC mit 10Mhz, Baud 4800 und im Baud Rate
Generator Register steht .33
Möchte noch eine Frage hinzufügen: Brauch ich unbedingt die
Handshake-Leitungen (weiß nicht ob das Modul sie hat, hab ich aus einem
Navi ausgebaut).
Oder hab ich einen Fehler in meinem Code:
1
charuart_rd;
2
char*zeigerZeichen=&uart_rd;
3
charstring[200];
4
unsignedshorti=0;
5
6
voidmain(){
7
8
ADCON1|=0x0F;// Configure AN pins as digital
9
CMCON|=7;// Disable comparators
10
TRISB=0;
11
PORTB=0;
12
13
14
UART1_Init(4800);// Initialize UART module at 4800 bps
15
Delay_ms(100);// Wait for UART module to stabilize
Hallo,
danke für die Hilfe. Leider funktioniert es nicht. Plötzlich wird sogar
garnichts in die Register geschrieben. Obwohl der Code von dir richtig
aussieht.
Trotzdem noch was generelles. Wie war das mit dem Handshake und Pull-Ups
oder Downs?
Ich hab es hinbekommen, dass wieder Daten ins String-Feld geschrieben
werden.
Jedoch verändert sich jedesmal der gespeicherte Wert im String[1].
Statt SLEEP hab ich jetzt eine Schleife eingebaut.
Noch eine Idee?
MfG Frank
Frank schrieb:> Ich hab es hinbekommen, dass wieder Daten ins String-Feld geschrieben> werden.
Das sieht jetzt wie aus?
> Jedoch verändert sich jedesmal der gespeicherte Wert im String[1].
Wie ist das zu verstehen?
Wann genau verändert sich der Wert?
Edit:
Achte auch darauf, dass dein i an einer sinnvollen Stelle wieder auf 0
zurückgestellt wird, damit der nächste GPS String auch wieder vom Anfang
des Buffers aus abgelegt wird.
Hallo,
mit jetzt funktioniert es wieder hab ich gemeint, dass die Spannung am
Netzteil etwas zu niedrig war.
Mit dem i zurücksetzen, hab mir da erst gar keine Gedanken gemacht. Was
passiert wenn ich es nicht tue? i zählt bis 255 und beginnt von neu und
verändert den String wieder von [0] an. Aber nur dann wenn sich die
Daten an der selben Stelle im NMEA-Protokoll verändern, richtig?
Ich lass mir die Bits an 8 LEDs anzeigen (Ich hab das BIGPI4, falls
bekannt)
und da verändern sie sich, aller ca. 3sek. Das dürfte ja theoretisch
garnicht passieren, weil sich der String[2] z.B. garnicht ändert (sehe
das NMEA-Prot. im Hyperterminal).
1
$GPVTG,,T,,M,,N,,K*4E
2
$GPGGA,003732.861,,,,,0,00,50.0,,M,,,,0000*24
3
$GPRMC,003732.861,V,,,,,,,020504,,*26
4
$GPVTG,,T,,M,,N,,K*4E
5
$GPGGA,003733.861,,,,,0,00,50.0,,M,,,,0000*25
6
$GPRMC,003733.861,V,,,,,,,020504,,*27
7
$GPVTG,,T,,M,,N,,K*4E
8
$GPGGA,003734.861,,,,,0,00,50.0,,M,,,,0000*22
9
$GPRMC,003734.861,V,,,,,,,020504,,*20
10
$GPVTG,,T,,M,,N,,K*4E
11
$GPGGA,003735.861,,,,,0,00,50.0,,M,,,,0000*23
12
$GPRMC,003735.861,V,,,,,,,020504,,*21
13
$GPVTG,,T,,M,,N,,K*4E
Habe meinen Code ein bisschen geändert, möchte nur GPRMC rausfiltern.
Dann müsste mir String[2] die "0" ausgeben. Das geschieh auch, jedoch
nur beim ersten mal und dann ändert er sich laufend.
Hier noch mein Code, geht das auch schöner?
1
unsignedcharuart_rd;
2
charstring[200];
3
unsignedshorti=0;
4
unsignedcharscratch;
5
6
voidmain()
7
{
8
9
ADCON1|=0x0F;// Configure AN pins as digital
10
CMCON|=7;// Disable comparators
11
TRISB=0x00;
12
PORTB=0x00;
13
TRISE=0x00;
14
PORTE=0x00;
15
TRISC=0x80;
16
PORTC=0x02;
17
18
19
UART1_Init(4800);// Initialize UART module at 4800 bps
20
Delay_ms(100);// Wait for UART module to stabilize
21
22
while(1)
23
{
24
25
scratch=RCREG1;// reset PIR1.RC1IF
26
27
28
while(1)
29
{// Endless loop
30
while(PIR1.RC1IF==0);// wait for char
31
scratch=RCREG1;// read receive register and reset PIR1.RC1IF
Frank Müller schrieb:> Mit dem i zurücksetzen, hab mir da erst gar keine Gedanken gemacht. Was> passiert wenn ich es nicht tue? i zählt bis 255 und beginnt von neu und> verändert den String wieder von [0] an. Aber nur dann wenn sich die> Daten an der selben Stelle im NMEA-Protokoll verändern, richtig?
Da dein String Array in erster Linie nur 200 Zeichen gross ist, passiert
dann alles mögliche
> Hier noch mein Code, geht das auch schöner?
Sicher.
Wenn du dir angewöhnen würdest nicht dem schnellen Hack
hinterherzulaufen, sondern wenigstens halbwegs vernünftiges
Softwaredesign betreiben würdest.
Dazu gehört auch, dass man sich Übersicht schafft, indem man
Funktionalität in Funktionen auslagert. Dazu gehört auch, dass man sich
die vom Programm zu leistende Arbeit in logisch zusammengehörende
Baugruppen einteilt.
Dein Hauptprogramm sollte so aussehen
1
voidmain()
2
{
3
4
ADCON1|=0x0F;// Configure AN pins as digital
5
CMCON|=7;// Disable comparators
6
TRISB=0x00;
7
PORTB=0x00;
8
TRISE=0x00;
9
PORTE=0x00;
10
TRISC=0x80;
11
PORTC=0x02;
12
13
14
UART1_Init(4800);// Initialize UART module at 4800 bps
15
Delay_ms(100);// Wait for UART module to stabilize
16
17
while(1)
18
{
19
receiveGPSString();
20
21
uart_rd=string[1];
22
PORTB=uart_rd;
23
}
24
}
Jetzt bist du am Zug die Funktion receiveGPSString zu schreiben, die
eine komplette Zeile vom GPS einliest. Nicht mehr und nicht weniger. Sie
soll auch nichts weiter tun, als eine komplette Zeile einzulesen - nicht
mehr und nicht weniger.
Hinweis 2:
Eine Funktion
1
charwaitForChar()
2
{
3
while(PIR1.RC1IF==0)
4
;
5
returnRCREG1;
6
}
abstrahiert schon mal einiges an Komplexität von den verwendenden
Stellen weg, indem dort dann einfach nur noch steht
1
scratch=waitForChar();
und das ist dann schon leichter zu lesen und zu verstehen als wie wenn
da jedesmal die ganzen Details die zum einlesen eines Zeichens notwendig
sind, aufgeführt werden.
Ja hast recht.
Sollte schnell gehen und wurde dann, wie es einige auch sehen werden,
eben schlampig.
Wenn es klappt, dann werde ich es natürlich "verschönern"
Trotzdem danke.
Frank Müller schrieb:> Ja hast recht.> Sollte schnell gehen
Genau da liegt der Trugschluss.
Mit derartigen Hacks ist man nie schneller, als wie wenn man es von
Anfang an gleich einigermassen vernünftig macht.
Zuersteinmal vielen Dank für die Mühe.
So, ich hab mal den Code eins zu eins übernommen.
Du wolltest sie doch mit ; abschließen
while( c != '$' ); , oder?
Es funktioniert einigermaßen ohne zu kritisieren.
Manchmal wenn ich den PIC resete, dann wird nichts eingelesen.
Muss ich das in der Software so schreiben, das wenn er nichts einliest,
dass er dann das UART-Modul neue startet?
Dann noch eine Frage: Wo liegt der funktionelle Unterschied in unseren
beiden Codes?
Sorry, hab da was falsch verstanden.
while( c != '$' ) -> ist schon richtig. Hab mir nochmal den Code genau
angeschaut. Bin noch nicht so fit drin.
1
while(c!='*'&&i<sizeof(string)-1){
2
string[i++]=c;
3
c=waitForChar();
4
}
5
6
// sicher ist sicher. wir wollen einen schoenen C String haben
7
string[i]='\0';
Kannst du mir bitte sagen was da passiert: sizeof(string) - 1 und
string[i] = '\0'. Weiß der Compiler dass das eine Nullterminierung vom
kompletten String[i] ist?
Trotzdem wo liegt der Unterschied zwischen deinem und meinem Code (klar
professioneller geschieben)?
Ich muss wissen wo mein Denkfehler ist.
sizeof(string) - 1 -> verstehe ich jetzt.
Ich freu mich, dass es funktioniert. Wär nur schöner gewesen, wenn es
auf meinem Misst gewachsen wäre :-)
Trotzdem wo liegt der Unterschied zwischen deinem und meinem Code (klar
professioneller geschieben)?
Ich muss wissen wo mein Denkfehler ist.