Forum: Mikrocontroller und Digitale Elektronik Hilfe bei ASM-Codes von Bernhard S.


von Bruno M. (brumay)


Lesenswert?

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

von Bruno M. (brumay)


Lesenswert?

Möchte keiner helfen??

von Detlef K. (adenin)


Lesenswert?

Wie soll jemand helfen, wenn man so was bekommt: "Ich hab da was, das 
geht nicht, ich lass es euch nicht angucken, helft mir"

von Bruno M. (brumay)


Lesenswert?

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?

von Detlef K. (adenin)


Lesenswert?

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
von Bruno M. (brumay)


Angehängte Dateien:

Lesenswert?

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.

von Detlef K. (adenin)


Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

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

von Bruno M. (brumay)


Lesenswert?

> 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

von Bruno M. (brumay)


Lesenswert?

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

von Detlef K. (adenin)


Lesenswert?

>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?

von Bruno M. (brumay)


Lesenswert?

> 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
Noch kein Account? Hier anmelden.