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
Hi
>hier ist der Fehler:
Nein. Da verwechselst du etwas. Das ist kein LPM.
MfG Spess
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?
Das wahr gestern abend wohl schon zu spät.
1 | .include "tn13def.inc" |
2 | |
3 | .def status =r16 |
4 | .def temp =r17 |
5 | |
6 | .org 0x0000 |
7 | rjmp main ; Reset Handler |
8 | .org 0x0001 |
9 | rjmp int0_handler ; IRQ0 Handler |
10 | |
11 | main: |
12 | ldi temp, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse |
13 | out SPL, temp |
14 | |
15 | ldi r16, 0b00011001 ; PB0, PB3 und PB4 sind Ausgänge PB1 ist Eingang |
16 | out DDRB, temp |
17 | |
18 | ldi temp, (1<<ISC00) ; INT0 auf Low level konfigurieren |
19 | out MCUCR, temp ; und weg damit... |
20 | |
21 | ldi temp, (1<<INT0) ; INT0 enablen |
22 | out GIMSK, temp ; und weg damit... |
23 | |
24 | ldi r16, 0b00000000 ; Ertsmal alles aus |
25 | out PORTB, temp |
26 | |
27 | ldi ZL,low(Sprungtabelle*2) ; Tabellenzeiger laden, 16 Bit |
28 | ldi ZH,high(Sprungtabelle*2) |
29 | |
30 | ldi status, 0 ; lade 0 ins statusregister |
31 | |
32 | sei |
33 | |
34 | loop: rjmp loop ; Endlosschleife |
35 | |
36 | int0_handler: |
37 | tst status ; teste status auf 0 |
38 | breq Lichtan ; wenn 0 dann spring zu Lichtan |
39 | rjmp Lichtaus ; wenn nicht 0 dann Lichtaus |
40 | |
41 | Sprungtabelle: |
42 | .dw Lichtan, Lichtaus ; 1. und 2. Zustand |
43 | |
44 | |
45 | Lichtan: sbi PORTB, 0 ; set bit PB0 -> Licht an |
46 | ldi status, 1 ; set status = 1 |
47 | reti |
48 | |
49 | Lichtaus: cbi PORTB, 0 ; set bit PB0 -> Licht aus |
50 | ldi status, 0 ; set status = 0 |
51 | reti |
Der Code funktioniert jetzt. Könnt ihr mal drüber schauer und kritik äußern?
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.
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.