Hey
Ich versuche gerade die Sprungtabellen aus dem Tutorium zu verstehen. Da
ich kein AVRStudio habe habe ich versucht mir ein programm zu schreiben
und das auf meinem Attiny13 laufen zu lassen. An PB1 hängt ein Taster
und am PB 0 eine LED. Jetzt sollte per Interrupt auf Tastendruck die LED
an und ausgeschaltet werden.
.include "tn13def.inc"
.def status =r16
.def temp =r17
.org 0x0000
rjmp main ; Reset Handler
.org 0x0001
rjmp int0_handler ; IRQ0 Handler
main:
ldi temp, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
out SPL, temp
ldi r16, 0b00011001 ; PB0, PB3 und PB4 sind Ausgänge PB1 ist Eingang
out DDRB, temp
ldi temp, (1<<ISC00) ; INT0 auf Low level konfigurieren
out MCUCR, temp ; und weg damit...
ldi temp, (1<<INT0) ; INT0 enablen
out GIMSK, temp ; und weg damit...
ldi r16, 0b00000000 ; Ertsmal alles aus
out PORTB, temp
sei
loop: rjmp loop ; Endlosschleife
int0_handler:
ldi ZL,low(Sprungtabelle) ; Tabellenzeiger laden, 16 Bit
ldi ZH,high(Sprungtabelle)
add ZL,status ; Index addieren, 16 Bit
ldi status,0
adc ZH,status
ijmp ; indirekter Sprung in
Sprungtabelle
Sprungtabelle:
rjmp Lichtan ; 1. Zustand
rjmp Lichtaus ; 2. Zustand
Lichtan: sbi PORTB, 0 ; set bit PB0 -> Licht an
reti
Lichtaus: cbi PORTB, 0 ; set bit PB0 -> Licht aus
reti
Was mach ich falsch ?
Hi
>Was mach ich falsch ?
Erstmal, entweder '.def status =r16' und dann nur status verwenden und
kein r16.
Du hast nirgends eine Stelle, in der du 'status' änderst. Was soll dann
deiner Meinung nach passieren?
MfG Spess
hier ist der Fehler:
falsch:
ldi ZL,low(Sprungtabelle) ; Tabellenzeiger laden, 16 Bit
ldi ZH,high(Sprungtabelle)
richtig:
ldi ZL,low(Sprungtabelle*2) ; Tabellenzeiger laden, 16 Bit
ldi ZH,high(Sprungtabelle*2)
FLASH ist beim AVR 16 Bit breit
Stimmt ist ja nen jump via ZH:ZL --> PC
Aber das mit dem Status ist schon richtig, wird weder initialisiert noch
bei jedem Interrupt zwischen 0 - 1 getoggelt ;)
hhm ok ich hab grad mal einige sachen ausprobiert aber ohne erfolg
steht das
1
ldi ZL,low(Sprungtabelle) ; Tabellenzeiger laden, 16 Bit
2
ldi ZH,high(Sprungtabelle)
an der richtigen Stelle oder sollte das besser in die main-Routine mit
rein?
ich kann den den status mit inc status ändern aber wie springt der dann
wieder zurück?
Jens schrieb:
>> ldi temp, (1<<ISC00) ; INT0 auf Low level konfigurieren> out MCUCR, temp ; und weg damit...
Low Level?
Dir ist bewusst, dass dein Interrupt damit ausgelöst wird, solange
deine Taste gedrückt wird. Denn solange die Taste gedrückt ist, hat der
Pin Low Level und damit wird ständig ein Interrupt ausgelöst.
Wenn du das willst ist es ok.
Wenn du aber einen Tastendruck auswerten willst, dann musst du die
Flanke detektieren ...
... wenn da nicht das Tastenprellen wäre. Generell sind Tasten an einem
Interrupt keine gute Idee. Mit einer Ausnahme: wenn die Taste den µC aus
dem Tiefschlaf aufwecken muss. Das geht nur über Interrupt.
>> ldi temp, (1<<INT0) ; INT0 enablen> out GIMSK, temp ; und weg damit...>> ldi r16, 0b00000000 ; Ertsmal alles aus> out PORTB, temp>> ldi ZL,low(Sprungtabelle*2) ; Tabellenzeiger laden, 16 Bit> ldi ZH,high(Sprungtabelle*2)
Wozu brauchst du jetzt noch die Sprungtabelle?
Du verwendest sie ja gar nicht mehr!
>> ldi status, 0 ; lade 0 ins statusregister>> sei>> loop: rjmp loop ; Endlosschleife>> int0_handler:> tst status ; teste status auf 0> breq Lichtan ; wenn 0 dann spring zu Lichtan> rjmp Lichtaus ; wenn nicht 0 dann Lichtaus>> Sprungtabelle:> .dw Lichtan, Lichtaus ; 1. und 2. Zustand>>> Lichtan: sbi PORTB, 0 ; set bit PB0 -> Licht an> ldi status, 1 ; set status = 1> reti>> Lichtaus: cbi PORTB, 0 ; set bit PB0 -> Licht aus> ldi status, 0 ; set status = 0> reti
Ob es schlau ist dem zum Interrupthandler gehörenden reti in 2 Pfaden zu
verstecken, wäre zumindest debatierbar. Grundsätzlich ist es von der
Logik her ok, aber so etwas artet ganz schnell zum Wartungs-Albtraum
aus.
Hinweis: mit einem XOR (im AVR Assembler heißt das dann: EOR) kann man
ganz einfach ein einzelnes Bit toggeln (also von 0 auf 1 und umgekehrt
schalten).
> ldi status, 1 ; set status = 1
Solche Kommentare kannst du dir schenken. Da steht im Kommentar genau
dasselbe wie im Code. Das hier status auf 1 gesetzt wird, sehe ich auch
im Code. Die Frage ist: warum wird hier status auf 1 gesetzt?
Kommentiere nicht das wie, sondern das warum ...
> Lichtaus: cbi PORTB, 0 ; set bit PB0 -> Licht aus
... und wenn du kommentierst (dieser Kommentar ist von der Sache her
ok), dann achte darauf, dass die Kommentare richtig sind. Hier wird PB0
nicht gesetzt, sondern gelöscht. -> hättest du das wie (setzen/löschen)
aus dem Kommentar heraus gelassen, wäre der Kommentar richtig.
> Lichtaus: cbi PORTB, 0 ; Licht aus
Hier erzählt mir der Kommentar warum etwas passiert: Die Anweisung ist
dazu da, um das Licht zu löschen. Die Anweisung selbst erzählt mir, wie
das gemacht wird: indem am Port B das Bit 0 gelöscht wird.
Hey Karl Heinz
>Dir ist bewusst, dass dein Interrupt damit ausgelöst wird, solange>deine Taste gedrückt wird. Denn solange die Taste gedrückt ist, hat der>Pin Low Level und damit wird ständig ein Interrupt ausgelöst.
Ja, ich dachte der Tiny hat ja nur INT0 daher der wahl zwischen
Low-level und "Jede änderung". (Für was hättest du dich entshieden?)
>Generell sind Tasten an einem>Interrupt keine gute Idee. Mit einer Ausnahme: wenn die Taste den µC aus>dem Tiefschlaf aufwecken muss. Das geht nur über Interrupt.
Sondern? was wird sonst allgemein für Tasten verwendet?
>Wozu brauchst du jetzt noch die Sprungtabelle?>Du verwendest sie ja gar nicht mehr!
Stimmt da hab ich mich selbst ausgetrickst, weil ich unbedingt die
Sprungtabellen verwenden/verstehen wollte.
Stimmt: Variable XOR mit 1 verknüpft negiert ja das Ergebniss.
Ich werd heut abend nochmal versuchen eine version mit Sprungtabellen zu
schreiben.
Jens schrieb:
> Ja, ich dachte der Tiny hat ja nur INT0 daher der wahl zwischen> Low-level und "Jede änderung". (Für was hättest du dich entshieden?)
Was sagt das Datenblatt.
Hab jetzt nicht nachgesehen, aber die Megas können auch auf
Flankenwechsel (also Übergang von 0 auf 1, bzw umgekehrt) mit einem
Interrupt reagieren.
>>>Generell sind Tasten an einem>>Interrupt keine gute Idee. Mit einer Ausnahme: wenn die Taste den µC aus>>dem Tiefschlaf aufwecken muss. Das geht nur über Interrupt.>> Sondern? was wird sonst allgemein für Tasten verwendet?
Portpin als ganz normaler Eingang und in regelmässigen Zeitabständen
nachsehen, ob sich der Pegel geändert hat.