PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ampelsteuerung, AVR AT90S8535 ,TimerOverflow Interrupt



gizzi
18.05.2006, 15:49
Hallo,

hab ein kleines "Problemchen" mit meinen kleinen Programm.
Es scheint so dass der TimerOverflow Interrupt nie ausgelöst wird und somit auch die Ampelphasen:

.include "8535def.inc"

.device AT90S8535

.def highB =r22 ; extra temps
.def lowB =r23
.def temp =r16
.def cnt =r17
.def temp2 =r18

AMPEL_TABELLE:
.db 0b00000010,0b11111111,0b10110110,0b10110011 ;1.BYTE: AMPEL HAUPTREICHTUNG
.db 0b10000000,0b11111111,0b01100010,0b11111000 ;2.BYTE: AMPEL FUSSGÄNGER
.db 0b01000000,0b11111111,0b01100010,0b11111000 ;3.BYTE: COUNTER HIGHBYTE
.db 0b00010000,0b11111111,0b10001000,0b11100001 ;4.BYTE: COUNTER LOWBYTE
.db 0b00001000,0b11111111,0b01100010,0b11111000
.db 0b00000100,0b11111111,0b01100010,0b11111000
.db 0b00000000,0b00000000,0b00000000,0b00000000


rjmp RESET ;POWER ON RESET
reti ; 2 Int0-Interrupt
reti ; 3 Int1-Interrupt
reti ; 4 TC2 Compare Match
reti ; 5 TC2 Overflow
reti ; 6 TC1 Capture
reti ; 7 TC1 Compare Match A
reti ; 8 TC1 Compare Match B
rjmp OVERFLOW ; 9 TC1 Overflow
reti ; 10 TC0 Overflow
reti ; 11 SPI, STC Serial Transfer Complete
reti ; 12 UART Rx Complete
reti ; 13 UART Data Register Empty
reti ; 14 UART Tx complete
reti ; 15 ADC Conversion Complete
reti ; 16 EEPROM Ready
reti ; 17 Analog Comparator
reti ; 18 TWI (I²C) Serial Interface
reti ; 19 St

RESET: ;initialize the machine

; stack pointer
ldi temp, low(RAMEND)
out SPL, temp
ldi temp, high(RAMEND)
out SPH, temp
ldi temp,0b00000100
out TIMSK,temp
ldi temp,0b00111111
out DDRB,temp
ldi temp,0b11111111
out DDRD,temp
ldi temp,0b00000101
out TCCR1B,temp
ldi lowB,0b11111000
ldi highB,0b11111111
out TCNT1H,highB
out TCNT1L,lowB
sei

START:

nop
rjmp START


OVERFLOW:

rcall OHNE_FUSS
ret

OHNE_FUSS:

lpm
tst R0 ;testet ob die letzte Ampelphase erreicht ist
breq RESET_AMPEL
mov temp2,R0
out PORTB,temp2
adiw ZL,1
lpm
mov temp2,R0
out PORTD,temp2
adiw ZL,1
lpm
mov temp2,R0
out TCNT1H,temp2
adiw ZL,1
lpm
mov temp2,R0
out TCNT1L,temp2
adiw ZL,1
ret

RESET_AMPEL:

ldi ZH,high(AMPEL_TABELLE*2) ; init Zldi
ldi ZL,low(AMPEL_TABELLE*2)
rjmp OHNE_FUSS


ich hoffe der Code ist einigermaßen verständlich.

Danke

izaseba
18.05.2006, 16:44
O weh,

Was ist das für eine ISR ????

OVERFLOW:

ist doch Deine ISR oder ?

1. an welcher Stelle sicherst Du SREG ?
2. den rcall OHNE_FUSS verstehe ich auch nicht wozu das ganze ?
3. schön daß Du ret benutzt, aber damit schaltest Du die Interrupts garnicht mehr an.
Ein reti wäre sinvoller gewesen :-)

Ich hoffe, daß ich helfen konnte, sonst müßen wir das in ruhe mal durchgehen.

Gruß Sebastian

P.S.
Was ich noch gerade sehe,
Die .db's gehören nicht am Anfang sondern am Schluß des Programms, sonst fangen sie bei 0x0000 an, wo normalerweise die Vektoren liegen.
Wenn Du die Tabelle am Anfang schreiben willst mußt Du die Vektoren so definieren :


.org 0x0000
rjmp reset
.org INT0addr
reti
...
...

gizzi
18.05.2006, 16:55
O weh,

Was ist das für eine ISR ????

OVERFLOW:

ist doch Deine ISR oder ?

1. an welcher Stelle sicherst Du SREG ?
2. den rcall OHNE_FUSS verstehe ich auch nicht wozu das ganze ?
3. schön daß Du ret benutzt, aber damit schaltest Du die Interrupts garnicht mehr an.
Ein reti wäre sinvoller gewesen :-)

Ich hoffe, daß ich helfen konnte, sonst müßen wir das in ruhe mal durchgehen.
Gruß Sebastian

Danke für deine Antwort , bin erst seit einer Woche an der Thematik dran *g*
Bitte um ein wenig Nachsicht :)

1. Muss ich das Status Register unbedingt sichern ? Wozu genau ?
2. der rcall in der ISR hat schon seinen Sinn , da kommen noch mehr rcall´s rein. Ist noch nicht ganz komplett das programm.
3. sorry kleiner Fehler beim abtippen, hab hier reti auch drin stehen.

Also wird wohl das SREG register schuld sein oder ?


EDIT: Ohh jee das mit der Tabelle hab ich total verplannt, klar müssen die Interruptvektoren am Anfang stehen *schäm*


Danke nochmal

izaseba
18.05.2006, 17:22
Bitte um ein wenig Nachsicht

Kein Problem, jeder hat mal igrendwann angefangen :wink:

Zum SREG, nein Du mußt Ihn nicht unbedingt sichern, wenn Deine Hauptschleife aus loop: rjmp loop besteht und/oder wenn Du in der ISR keine Operationen vornimmst, die den SREG verändern, ist es nicht notwendig SREG zu sichern.
Ich mache es persönlich immer, weil :
1. wenn mein Programm mit der Zeit wächst, kann ich es nicht mehr vergessen.
2. In jedem Programm mache ich irgendwas in der Hauptschleife....

zu 2.
Versuche es zu vermeiden rcalls in eine ISR zu benutzen, es geht fast immer anders, rcalls belasten den Stack, machen die ISR langsammer, und Dein Programm unübersichtilicher.
Setze lieber ein Flag in der ISR und prüfe Ihn in der Hauptschleife.

zu 3. :lol:

zu EDIT , ich hoffe daß wir damit den Wurm gefunden haben.

Gruß Sebastian

Hanni
18.05.2006, 18:17
Hallo,

vielleicht hilft es dir, wenn ich hier mal ein paar allgemeine Tips zur Programmierung von Mikrocontrollern in Assembler gebe.

Ich nutze dazu einmal deinen Code, um zu zeigen wie es besser geht.

1. geize nicht mit Kommentaren aber vermeide "sinnfreie" oder selbsterklärende Komentare.

Beispiel:

dein Code:

mov temp2,R0

besser:

mov temp2,R0 ; um dieses oder jenes zu erreichen

wesentlich schlechter:

mov temp2,R0 ; Inhalt von R0 -> temp2

2. vermeide wann immer es geht die binäre Schreibweise, da diese meistens ziemlich nichtssagend ist.

dein Code:

ldi temp,0b00000101
out TCCR1B,temp

besser:

ldi temp, (1<<CS12) | (1<<CS10)
out TCCR1B,temp

der Vorteil:
wenn man in einigen Wochen doch noch einmal in den Code schaut, wird es fast auf einen Blick klar, was dort nun in das entsprechende Register wandert (in dem Fall die Prescaler Einstellungen für den Timer Takt).

3. Sichere wann immer es geht das Statusregister, auch wenn du es im Moment nicht benötigst.

Der Vorteil: du vergisst es nicht, wenn du doch einmal dein Programm erweiterst und du es dann doch mal brauchst.

Beispiel:

: ------- irgendwo am Anfang:
.def sregsave = r3

; in der ISR
ISR:
in sregsave, SREG ; Statusregister sichern


out SREG, sregsave

reti

4. egal was du machst, vermeide lange ISR's (Interupt Service Routinen)

defakto ist es wesentlich besser und eleganter sich ein eigenes Statusregister zu definieren und anschließend dort ein Bit zu setzen als durch lange ISR's den controller zu blockieren.

Beispiel:


: ------- irgendwo am Anfang:
.def status = r17 ; statusregister
; 7 =
; 6 =
; 5 =
; 4 =
; 3 =
; 2 =
; 1 =
; 0 = Ampel aktuallisieren

; im Code
sbrc status, 0 ; ampel aktuallisieren ?
rcall ampel_update ; -> Ja

; restlicher Code


ampel_update:
andi status, 0b11111110 ; Ampel aktuallisieren Flag löschen

; Code

ret



; in der ISR
ISR:
in sregsave, SREG ; Statusregister sichern

ori status, 0b00000001 ; Ampel aktuallisieren Flag setzen

out SREG, sregsave

reti


So, ich hoffe dir damit ein klein wenig geholfen zu haben.

BTW: Der Wurm bei dir liegt nicht an der fehlenden Sicherung des Statusregisters, sondern an der etwas deplazierten Wertetabelle.

Hier noch einmal ein grober Strukturansatz:

1. nötiges Include File laden
2. Aliase für Register definieren
3. Aliase für speicheradressen definieren
4. Konstanten definieren
(danach nen .cseg & .org 0x00)
5. Interupt Vektoren
6. Reset Rioutine mit:
- Stack initialisieren
- Speicher leeren
- Peripherie initialisieren (Timer, Ports etc)
7. Main Loop
8. Sub Routinen
9. ISR Routinen
10. Diverse Datentabellen.


Grüße,

da Hanni.

gizzi
18.05.2006, 18:21
Hallo,

vielleicht hilft es dir, wenn ich hier mal ein paar allgemeine Tips zur Programmierung von Mikrocontrollern in Assembler gebe.

Ich nutze dazu einmal deinen Code, um zu zeigen wie es besser geht.

1. geize nicht mit Kommentaren aber vermeide "sinnfreie" oder selbsterklärende Komentare.

Beispiel:

dein Code:

mov temp2,R0

besser:

mov temp2,R0 ; um dieses oder jenes zu erreichen

wesentlich schlechter:

mov temp2,R0 ; Inhalt von R0 -> temp2

2. vermeide wann immer es geht die binäre Schreibweise, da diese meistens ziemlich nichtssagend ist.

dein Code:

ldi temp,0b00000101
out TCCR1B,temp

besser:

ldi temp, (1<<CS12) | (1<<CS10)
out TCCR1B,temp

der Vorteil:
wenn man in einigen Wochen doch noch einmal in den Code schaut, wird es fast auf einen Blick klar, was dort nun in das entsprechende Register wandert (in dem Fall die Prescaler Einstellungen für den Timer Takt).

3. Sichere wann immer es geht das Statusregister, auch wenn du es im Moment nicht benötigst.

Der Vorteil: du vergisst es nicht, wenn du doch einmal dein Programm erweiterst und du es dann doch mal brauchst.

Beispiel:

: ------- irgendwo am Anfang:
.def sregsave = r3

; in der ISR
ISR:
in sregsave, SREG ; Statusregister sichern


out SREG, sregsave

reti

4. egal was du machst, vermeide lange ISR's (Interupt Service Routinen)

defakto ist es wesentlich besser und eleganter sich ein eigenes Statusregister zu definieren und anschließend dort ein Bit zu setzen als durch lange ISR's den controller zu blockieren.

Beispiel:


: ------- irgendwo am Anfang:
.def status = r17 ; statusregister
; 7 =
; 6 =
; 5 =
; 4 =
; 3 =
; 2 =
; 1 =
; 0 = Ampel aktuallisieren

; im Code
sbrc status, 0 ; ampel aktuallisieren ?
rcall ampel_update ; -> Ja

; restlicher Code


ampel_update:
andi status, 0b11111110 ; Ampel aktuallisieren Flag löschen

; Code

ret



; in der ISR
ISR:
in sregsave, SREG ; Statusregister sichern

ori status, 0b00000001 ; Ampel aktuallisieren Flag setzen

out SREG, sregsave

reti


So, ich hoffe dir damit ein klein wenig geholfen zu haben.

BTW: Der Wurm bei dir liegt nicht an der fehlenden Sicherung des Statusregisters, sondern an der etwas deplazierten Wertetabelle.

Hier noch einmal ein grober Strukturansatz:

1. nötiges Include File laden
2. Aliase für Register definieren
3. Aliase für speicheradressen definieren
4. Konstanten definieren
(danach nen .cseg & .org 0x00)
5. Interupt Vektoren
6. Reset Rioutine mit:
- Stack initialisieren
- Speicher leeren
- Peripherie initialisieren (Timer, Ports etc)
7. Main Loop
8. Sub Routinen
9. ISR Routinen
10. Diverse Datentabellen.


Grüße,

da Hanni.

SUPER!!! vielen Dank für die Tipps :)

mfg

izaseba
18.05.2006, 18:31
Und wenn wir gerade bei den Tipps sind poste ich hiermit einen Link, den ich schon 300 mal gepostet habe, aber ich find Ihn soooooo gut, daß ich Ihn nochmal poste :-)

Wenn Du nach dieser (http://www.avr-asm-tutorial.net/avr_de/beginner/index.html)
Seite vorgehst, schreibst Du bald sehr gute Programme.
Es gab hier schonmal Stimmen wie :
"Das ist blöd, steht nichts zu Mega 32 drin", oder
"das ist zu schwer"
naja, die Stimmen haben sich nachhinein Bascom runtergeladen und sind jetzt auch zufrieden.

Gruß Sebastian

Hanni
18.05.2006, 18:38
SUPER!!! vielen Dank für die Tipps :)

mfg

Kein Problem, ich hab selbst mal von Null angefangen, und es hat ne ganze Weile gedauert, bis ich des Sinn oder Unsinn einer gewissen Struktur verstanden und eingesehen habe.

Ich übrigen, den Speicher könnte man z.B. wie folgt leeren (auf einen definierten zustand bringen)



clr temp ; Clear Mem Routine

ldi YH, high(RAMEND)
ldi YL, low(RAMEND)

ldi ZH, high(SRAM_START)
ldi ZL, low(SRAM_START)
clr_mem:
st Z+, temp
cp YL, ZL
cpc YH, ZH
brne clr_mem

st Z, temp

Vielleicht hilft dir das ja mal weiter.

@ izaseba:


Und wenn wir gerade bei den Tipps sind poste ich hiermit einen Link, den ich schon 300 mal gepostet habe, aber ich find Ihn soooooo gut, daß ich Ihn nochmal poste :-)

Wenn Du nach dieser (http://www.avr-asm-tutorial.net/avr_de/beginner/index.html)
Seite vorgehst, schreibst Du bald sehr gute Programme.

Sehr schöne Übersicht :D
Und ob du es glaubst oder nicht, ich hab sowas in der Art als PDF Datei bei mit aufm Rechner ...
und ob man es glaubt oder nicht, ich schau immer mal wieder rein ... insbesondere, wenn es um Flags geht (die sich bei diversen Befehlen verändern können)


Grüße,
da Hanni

izaseba
18.05.2006, 18:51
Und ob du es glaubst oder nicht,

Ich glaub es Dir gerne, die Seite ist bei mir ganz oben in der Lesezeichenliste.
In meinen Augen ist es die beste Seite, zum Thema.

In diesem Sinne gutes gelingen mit der Ampel !

Gruß Sebastian