Hallo, Es gibt hier zwei ältere Threads u.z GPS - MOUSE - MINI- NAVIGATOR (Assembler) ATmega8 und SD-Karte Initialisierung Read Write FAT ATmega8 (Assembler), beide von Bernhard S. Da ich mir mit Assembler wesentlich leichter tue, versuche ich nun schon geraume Zeit aus diesen beiden Codes einen GPS-Tracker zu stricken. Ich kann inzwischen SD-Karten beschreiben und auch über den UART Daten in das Programm einlesen. Es werden aber immer nur die ersten 3 und das letzte Byte übernommen. Auf der SD-Karte kommt dabei gar nichts an. Hat jemand Lust mir auf die Sprünge zu helfen?? Ich weiß natürlich, daß es im Forum eine Reihe von fertigen C-Programmen dazu gibt, aber ich möchte es ja verstehen. Gruß Bruno
Wie soll jemand helfen, wenn man so was bekommt: "Ich hab da was, das geht nicht, ich lass es euch nicht angucken, helft mir"
Hallo Detlev, vorab danke für die Reaktion!! Es war mir schon klar, daß ich auf meine Anfrage noch keine konkrete Hilfe erwarten konnte. Mir reicht aber auch schon die grundsätzliche Bereitschaft in mein Problem einzusteigen, dann kommen natürlich auch die etwas umfangreichen Details. Im Moment geht es um den USART und die Speicherung der empfangenen Daten. Der Ablauf ist eigentlich ganz normal, d.h. bei vollem RXC wird ein Interrupt ausgelöst der auf folgende Routine zeigt:
1 | |
2 | ZEICHEN_EINLESEN: |
3 | ; GPS STRING einlesen |
4 | rcall GPS_STRING_EINLESEN |
5 | ; IST GPS-STRING komplett ? |
6 | LDS temp, (adr_GPS_DATEN_STRING_KOMPLETT) ; adr_GPS_DATEN_STRING_KOMPLETT=1 |
7 | tst temp |
8 | breq ZEICHEN_EINLESEN_FERTIG |
9 | ; AUSWERTUNG der einzelnen STRINGS |
10 | rcall GPRMC_AUSWERTEN |
11 | rcall GPGGA_AUSWERTEN |
12 | rcall GPGSV_X_1 |
13 | rcall GPGSV_X_2 |
14 | rcall GPGSV_X_3 |
15 | ; STRING clear |
16 | rcall GPS_CLEAR_START |
17 | ZEICHEN_EINLESEN_FERTIG: |
18 | reti |
19 | ;************************************************************** |
20 | ; Einen STRING einlesen. Er beginnt mit einem "$" und endet mit chr(10) |
21 | ;maximal 255 ZEICHEN |
22 | ; $GP...chr(13) chr(10) |
23 | GPS_STRING_EINLESEN: |
24 | ;einlesen |
25 | in GPS_EMPFANGSZEICHEN, UDR |
26 | ; aktuelle Anzahl der eingelesenen Zeichen |
27 | LDS temp,(adr_GPS_DATEN_ZEICHEN_ANZAHL) ; aus SRAM einlesen |
28 | inc temp ; +1 |
29 | STS (adr_GPS_DATEN_ZEICHEN_ANZAHL),temp ; in SRAM ablegen |
30 | ; GPS-EMPFANGS-ZEICHEN an neuer SCHREIBPOSITION schreiben |
31 | LDS XL,(adr_GPS_DATEN_SCHREIB_POSITION_L) ; aus SRAM laden |
32 | LDS XH,(adr_GPS_DATEN_SCHREIB_POSITION_H) ; aus SRAM laden |
33 | ST X+, GPS_EMPFANGSZEICHEN ; schreiben und x+1 |
34 | ; neue SCHREIBPOSITION schreiben |
35 | STS (adr_GPS_DATEN_SCHREIB_POSITION_L),XL ; in SRAM speichern |
36 | STS (adr_GPS_DATEN_SCHREIB_POSITION_H),XH ; in SRAM speichern |
37 | ; Fehlerprüfung 1.Zeichen "$" |
38 | cpi temp,1 |
39 | brne GPS_STRING_EINLESEN_2 |
40 | ldi temp, '$' |
41 | cp GPS_EMPFANGSZEICHEN,temp ; vergleich |
42 | brne GPS_STRING_EINLESEN_FEHLER ; ungleich ==> FEHLER |
43 | ret |
44 | ; Fehlerprüfung 2.Zeichen "G" |
45 | GPS_STRING_EINLESEN_2: |
46 | cpi temp,2 |
47 | brne GPS_STRING_EINLESEN_3 |
48 | ldi temp, 'G' |
49 | cp GPS_EMPFANGSZEICHEN,temp ; vergleich |
50 | brne GPS_STRING_EINLESEN_FEHLER ; ungleich ==> FEHLER |
51 | ret |
52 | ; Fehlerprüfung 3.Zeichen "P" |
53 | GPS_STRING_EINLESEN_3: |
54 | cpi temp,3 |
55 | brne GPS_STRING_EINLESEN_255 |
56 | ldi temp, 'P' |
57 | cp GPS_EMPFANGSZEICHEN,temp ; vergleich |
58 | brne GPS_STRING_EINLESEN_FEHLER ; ungleich ==> FEHLER |
59 | ret |
60 | ; Fehlerprüfung bei 255 Zeichen ==>Fehler |
61 | GPS_STRING_EINLESEN_255: |
62 | LDS temp1,(adr_GPS_DATEN_ZEICHEN_ANZAHL) ; aus SRAM einlesen |
63 | cpi temp1,255 ; vergleich |
64 | brne GPS_STRING_EINLESEN_ENDE |
65 | breq GPS_STRING_EINLESEN_FEHLER |
66 | ; ENDE des GPS-STRINGS ermitteln chr(10) |
67 | GPS_STRING_EINLESEN_ENDE: |
68 | ldi temp, 10 |
69 | cp GPS_EMPFANGSZEICHEN,temp ; vergleich |
70 | breq GPS_STRING_EINLESEN_KOMPLETT |
71 | ret |
72 | ; STRING wurde komplett eingelesen |
73 | GPS_STRING_EINLESEN_KOMPLETT: |
74 | ldi temp,1 |
75 | STS (adr_GPS_DATEN_STRING_KOMPLETT),temp ; adr_GPS_DATEN_STRING_KOMPLETT=1 |
76 | |
77 | ret |
78 | ; ---------------------------------------------- |
79 | GPS_STRING_EINLESEN_FEHLER: |
80 | rcall GPS_CLEAR_START |
81 | |
82 | ret |
Der Ablauf ist also, wenn ich es richtig verstanden habe wie folgt: Bei vollem Empfangspuffer wird der Interrupt ausgelöst und in "GPS_STRING_EINLESEN" eingelesen. Dann wird geprüft ob es sich um einen gültigen "$GP..." String handelt und wenn ja wird der ganze String eingelesen. Wie funktioniert das aber mit dem Interrupt? Das erste Byte ist OK. Bis "reti" kann aber doch kein weiterer Interrupt ausgelöst werden. Das würde aber bedeuten, daß die Einleseroutine komplett durchläuft und mit "GPS_CLEAR_START" alles wieder auf null gesetzt wird. Damit würde man aber nie über das erste Byte hinauskommen???? Wo stehe ich da auf der Leitung?
erster "Fehler": Der ganze "Auswertungsmist" gehört nicht in die Interruptroutine. Interrupts sind, wie der Name schon sagt, Unterbrechungen des Hauptprogrammes um irgendwas wichtiges ganz schnell zu erledigen, zB. ein Byte vom USART abholen. ok, ist hier nicht so schlimm, weil nur wenig gemacht wird und tehoretisch viel Zeit zwischen den einzelnen Byte liegt (ca. 1ms@9600Bd). zweiter echter Fehler: Du tust nirgendwo dein Statusregister sichern. Da wird dein Hauptprogramm sicher irgendwann drüber stolpern, wenn irgend eine Bedingung abgefragt wird, oder irgendwas mit Carry rechnet wird, und der Interrupt hat mitten drin die Flags verändert. Absolut doppelplusungut. :) Wie schnell ist dein ATmega getaktet? Weil, Du hast eventuell nur 2ms (zwei Byte bei angenommenen 9600Bd) Zeit um dein String im Interrupt auszuwerten. >Wie funktioniert das aber mit dem Interrupt? Das erste Byte ist OK. Bis >"reti" kann aber doch kein weiterer Interrupt ausgelöst werden. Das >würde aber bedeuten, daß die Einleseroutine komplett durchläuft und mit >"GPS_CLEAR_START" alles wieder auf null gesetzt wird. Damit würde man >aber nie über das erste Byte hinauskommen???? Wenn ein Byte vom USART abgeholt wurde und kein Fehler auftrat und kein Endzeichen erkannt wurde, dann wird der Interrupt einfach beendet und es wird auf das nächste Zeichen gewartet. Trat ein Fehler auf, wird GPS_CLEAR_START aufgerufen und der Interrupt verlassen. Wurde ein Endzeichen erkannt, dann wird der String ausgewertet, dann GPS_CLEAR_START aufgerufen und zum Schluß der Interrupt verlassen.
:
Bearbeitet durch User
Detlef Kunz schrieb: > erster "Fehler": > Der ganze "Auswertungsmist" gehört nicht in die Interruptroutine. Da ich diesen Teil des Codes übernommen habe, kann ich nicht genau sagen, was der Autor bezweckt hat. Ich vermute aber, es geht um Speicherplatz. >zweiter echter Fehler: >Du tust nirgendwo dein Statusregister sichern. Da ich nicht alles zitieren wollte, habe ich diesen Teil unterschlagen. Komplette Sicherung ist aber vorhanden. >Wie schnell ist dein ATmega getaktet? 16MHz, Baudrate entsprechend NMEA 4800. >Wenn ein Byte vom USART abgeholt wurde und kein Fehler auftrat und kein >Endzeichen erkannt wurde, dann wird der Interrupt einfach beendet und es >wird auf das nächste Zeichen gewartet. Genau das verstehe ich nicht. Wenn die Auswertung beendet ist, kein Fehler oder Endbyte erkannt wurde, springt er aus "GPS_STRING_EINLESEN_ENDE" wieder zurück in die "ZEICHEN_EINLESEN" Schleife, wo aber am Ende der "rcall GPS_CLEAR_START" Befehl sitzt. Zur Sicherheit hänge ich auch noch diesen gesamten Teil (GPS_Interrupt.asm) dran.
Bruno M. schrieb: > Genau das verstehe ich nicht. Wenn die Auswertung beendet ist, kein > Fehler oder Endbyte erkannt wurde, springt er aus > "GPS_STRING_EINLESEN_ENDE" wieder zurück in die "ZEICHEN_EINLESEN" > Schleife, wo aber am Ende der "rcall GPS_CLEAR_START" Befehl sitzt. Wo soll das passieren? Ich sehe so ein Verhalten nicht im Code.
Hi Das Ganze wird über die Speicherstelle adr_GPS_DATEN_STRING_KOMPLETT gesteuert. Wenn in GPS_STRING_EINLESEN das Ende (ASCII 10) erkannt wird, wird diese Zelle auf eins gesetzt:
1 | GPS_STRING_EINLESEN_ENDE: |
2 | ldi temp, 10 |
3 | cp GPS_EMPFANGSZEICHEN,temp ; vergleich |
4 | breq GPS_STRING_EINLESEN_KOMPLETT |
5 | ret |
6 | ; STRING wurde komplett eingelesen |
7 | GPS_STRING_EINLESEN_KOMPLETT: |
8 | ldi temp,1 |
9 | STS (adr_GPS_DATEN_STRING_KOMPLETT),temp ; |
10 | ret |
Die Auswertung erfolgt erst, wenn die Speicherzelle eins ist. Anderen Falls wird die Interruptroutine ohne Auswertung verlassen.
1 | ; GPS STRING einlesen |
2 | rcall GPS_STRING_EINLESEN |
3 | ; IST GPS-STRING komplett ? |
4 | LDS temp,(adr_GPS_DATEN_STRING_KOMPLETT) |
5 | tst temp |
6 | breq ZEICHEN_EINLESEN_FERTIG |
7 | ; AUSWERTUNG der einzelnen STRINGS |
8 | rcall GPRMC_AUSWERTEN |
9 | ..... |
>> Der ganze "Auswertungsmist" gehört nicht in die Interruptroutine. >Da ich diesen Teil des Codes übernommen habe, kann ich nicht genau >sagen, was der Autor bezweckt hat. Ich vermute aber, es geht um >Speicherplatz. Hat mit Speicherplatz gar nichts zu tun. Die Auswertung kann genau so gut in der Hauptschleife erfolgen. Das Programm mag zwar funktionieren aber der Code ist eher suboptimal. MfG Spess
> Wo soll das passieren? > Ich sehe so ein Verhalten nicht im Code.
1 | ZEICHEN_EINLESEN: |
2 | ; GPS STRING einlesen |
3 | rcall GPS_STRING_EINLESEN |
4 | ; IST GPS-STRING komplett ? |
5 | LDS temp, (adr_GPS_DATEN_STRING_KOMPLETT) ; adr_GPS_DATEN_STRING_KOMPLETT=1 |
6 | tst temp |
7 | breq ZEICHEN_EINLESEN_FERTIG |
8 | ; AUSWERTUNG der einzelnen STRINGS |
9 | rcall GPRMC_AUSWERTEN |
10 | rcall GPGGA_AUSWERTEN |
11 | rcall GPGSV_X_1 |
12 | rcall GPGSV_X_2 |
13 | rcall GPGSV_X_3 |
14 | ; STRING clear |
15 | |
16 | rcall GPS_CLEAR_START |
17 | |
18 | ZEICHEN_EINLESEN_FERTIG: |
19 | reti |
20 | |
21 | ;************************************************************** |
22 | S_STRING_EINLESEN: |
23 | |
24 | ........... |
25 | |
26 | GPS_STRING_EINLESEN_255: |
27 | LDS temp1,(adr_GPS_DATEN_ZEICHEN_ANZAHL) ; aus SRAM einlesen |
28 | cpi temp1,255 ; vergleich |
29 | |
30 | brne GPS_STRING_EINLESEN_ENDE ;wenn keine 255 Zeichen, dann springen |
31 | |
32 | GPS_STRING_EINLESEN_ENDE: |
33 | ldi temp, 10 |
34 | cp GPS_EMPFANGSZEICHEN,temp ; vergleich |
35 | breq GPS_STRING_EINLESEN_KOMPLETT |
36 | |
37 | ret |
38 | |
39 | ....... |
Wenn in "GPS_STRING_EINLESEN_ENDE" kein Endzeichen gefunden wird, springt er mit return wieder in die "ZEICHEN_EINLESEN" Schleife und nach Auswertung aller Datensätze rcall GPRMC_AUSWERTEN rcall GPGGA_AUSWERTEN rcall GPGSV_X_1 rcall GPGSV_X_2 rcall GPGSV_X_3 ; STRING clear nach rcall GPS_CLEAR_START
das war der entscheidende Hinweis: spess53 schrieb: > Die Auswertung erfolgt erst, wenn die Speicherzelle eins ist. Anderen > Falls wird die Interruptroutine ohne Auswertung verlassen. Ich hatte es immer genau andersrum interpretiert! Herzlichen Dank für alle Kommentare! Gruß Bruno
>Da ich mir mit Assembler wesentlich leichter tue Ich hatte interpretiert Du kannst AVR-Assembler ;) So, und warum funktioniert dein Code nun nicht, wenn hier alles ok zu sein scheint?
> Ich hatte interpretiert Du kannst AVR-Assembler ;) von "können" bin ich noch meilenweit entfernt, aber zumindest habe ich damit schon einiges gemacht. Wie du siehst hindert das aber nicht daran mal richtig auf der Leitung zu stehen. > So, und warum funktioniert dein Code nun nicht, wenn hier alles ok zu > sein scheint? Dieser Teil des Codes hat immer funktioniert, aber ich habe ihn nicht richtig verstanden. Das führt dazu, daß man Probleme manchmal am völlig falschen Ort sucht. Inzwischen habe ich aber auch den Rest zum Laufen gebracht, d.h. ich kann vom PC per USART GPS-Signale senden und sie werden auf der SD-Karte richtig gespeichert.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.