Guten Abend, Ich bin seit Kurzem dabei, mich mit den Programmieren von Atmels AVR µC zu beschäftigen. Nun habe ich ein Programm geschrieben, welches, ausgelöst über einen steigende-Flanke Interrupt INT0 den Zustand von PB2 toggelt. Beim Kompilieren sagt das Avr- Studio leider stets "illegal attempt to re-use "Int0" als label.(L.26) Ich denke, das Problem entsteht durch die im Interrupt verwendeten Unterprogrammaufrufe, kann mir da jemand helfen ? Anbei der Quellcode: ; Schaltet bei einem Low Pegel an PB0 ; den Zustand von PortB2 um. .include "tn13def.inc" .def temp= r16 .def Used= r17 rjmp Start .org 0x001 rjmp INT0 Start: ldi temp, RAMEND out SPL, temp ; Stackpointer initialisieren ldi temp, 0 out GIMSK, temp ; External Interrupt enable ldi temp,0b00110011 out MCUCR, temp ; Sleep und INTO steigende Flanke enable cbi Used, 0 ; Used muss auf 0 sein sbi PORTB, portb0 ; Pull- up aktivieren rjmp Main Main: SEI SLEEP rjmp Main INT0: ; 26 cpi Used, 0b00000000 breq An ; Wenn Used= 0, PortB2 = 1 cpi Used, 0b00000000 brne Aus ; Wenn Used= 1, PortB2 = 0 reti An: sbi PORTB, portb2 sbi Used ; Used beschreiben ret Aus: cbi PORTB, portb2 cbi Used, 0 ; Used löschen ret
Die Fehlermeldung kommt, weil INT0 schon einmal als Label in der Datei tn13def.inc definiert ist. Du musst Dir einen anderen Namen ausdenken. Folgendes ist auch nicht ok: Du kannst nicht aus der IR Routine in ein Unterprogramm springen und dort mit RET enden. Sleep (falls es Power down ist, ich habe keine Lust, das 0b00110011 auseinander zu klamüsern) geht nur mit Level Interrupt ( Taste auf 0 schalten) Table 24. Interrupt 0 Sense Control ISC01 ISC00 Description 0 0 The low level of INT0 generates an interrupt request. Du vergleichst USED immer mit 0 ? sbi Used ; Used beschreiben --- mit was? ... In der Interruptroutine muss das Statusregister gesichert werden ( und wieder hergestellt). >; Schaltet bei einem Low Pegel an PB0 >; den Zustand von PortB2 um. PB0 wird nicht abgefragt ? INT0 ist an PB1. Herrmueller
Hm, abgesehen von deinem merkwürdigen Programm: sbi/cbi funktionieren nur im I/O-Bereich. Gewöhn dir gleich an, zumindest das SREG bei Interrupt zu sichern und am Ende wieder herzustellen. .def sreg_bak r0 INT0: in sreg_bak, sreg . . . out sreg, sreg_bak reti Ein weiterer grober Fehler: die springst mit jmp an die Funktionen an und aus, beendest diese aber ret. Das ist sicher nicht das, was du willst. Würde nämlich bedeuten, zum Hauptprogramm zurückzukehren, ohne allerdings das I-flag zurückzusetzen (das passiert nur bei reti) Und zu deinem eigentlichen Programm - du kannst natürlich schon den Zustand des PORTB.2 als Variable benutzen, verzweigen mit den Befehlen sbic/sbis. Ansonsten eben ein Register. INT0: in sreg_bak, sreg sbis portb, 2 rjmp an aus: cbi portb, 2 rjmp end_int0 an: sbi portb, 2 end_int0: out sreg, sreg_bak reti Hoffentlich habe ich jetzt nicht selbst Fehler drin, lange nichts mehr mit Assembler gemacht :-)
crazy horse schrieb: > Hoffentlich habe ich jetzt nicht selbst Fehler drin, lange nichts mehr > mit Assembler gemacht :-) INT0 ist der Name von Bit 6 in GIMSK, geht also nicht als Label, ist bereits vergeben. Die SREG-Sicherung ist hier ausnahmsweise mal nicht nötig, da sbis, rjmp, cbi, sbi keine Flags beeinflussen. Trotzdem sollte man sich die SREG-Sicherung angewöhnen... ...
Guten Morgen, Erst einmal vielen Dank für die Hilfestellungen. Wenn ich das noch einmal kurz zusammenfasse, darf ich also die Interrupt Routine nicht INT0 nennen, der Name ist schon vergeben. Außerdem darf ich aus einem Interrupt hinaus keine Unterprogramme aufrufen und diese mit -ret beenden. Wenn ich mit dem Interrupt dennoch ein Programm, welches Unterprogramme verwendet, starten will, ginge das mit Interrupt: rjmp Programm Programm: SEI ... rcall Unterprogramm ... Unterprogramm: ... ret ? leo
Hannes Lux schrieb: > Die SREG-Sicherung ist hier ausnahmsweise mal nicht nötig, da sbis, > rjmp, cbi, sbi keine Flags beeinflussen. Trotzdem sollte man sich die > SREG-Sicherung angewöhnen... Die erste Instruktion der ISR ist aber:
1 | cpi Used, 0b00000000 |
und die verändert selbstverständlich die Flags. Die Sicherung ist dennoch ausnahmsweise nicht nötig, weil in der "Hauptschleife" des Programms keine Flags benutzt werden. Leo F. schrieb: > Wenn ich das noch einmal kurz zusammenfasse, darf ich also die Interrupt > Routine nicht INT0 nennen, der Name ist schon vergeben. Richtig. > Außerdem darf ich aus einem Interrupt hinaus keine Unterprogramme > aufrufen und diese mit -ret beenden. Doch, das darfst du schon. Nur tut dein Programm das nicht. Ein Unterprogramm ruft man mit rcall auf. Mit breq dagegen machst du nur einen Sprung. Du mußt dich entscheiden: Entweder sind An und Aus Unterprogramme, die du mit rcall aufrufst und mit ret wieder beendest, oder es sind nur Teile deiner ISR, an die du springst und die dann wahlweise wieder explizit zurückspringen oder halt die ISR mit reti beenden.
Rolf Magnus schrieb: > Die erste Instruktion der ISR ist aber: cpi Used, 0b00000000 Aber nicht im Code von crazy horse, auf den ich mich bezog. crazy horse schrieb: > INT0: > in sreg_bak, sreg > sbis portb, 2 > rjmp an > aus: > cbi portb, 2 > rjmp end_int0 > an: > sbi portb, 2 > end_int0: > out sreg, sreg_bak > reti ...
Guten Abend, Es ist zwar schon eine Weile her, aber ich habe nun vesucht, alle Ratschläge zu berücksichtigen, es tritt beim Assemblieren stets der Fehler: [line 37] : errror: invalid number Nimmt AVR Studio die 0 als Varible an, denn gegen das Setzen bzw. Ausführung des "sibis"- Befehls des 7. Bits im r17 spricht ja eigentlich nichts, oder ? Hier noch einmal der Code, auch angehängt: ;Durch ein Low Level an Pb1 wird Pb3 im 1Hz Takt im Verhältnis 998:2 ;ein-und ausgeschaltet, eine weiteres Low Level schaltet zurück in den Sleep Mode. .include "tn13def.inc" .def SREGbak = r15 .def temp = r16 .def Used = r17 rjmp Anfang .org 0x0001 rjmp Interrupt Anfang: ldi temp,RAMEND out SPL, temp ; Stack Pointer definieren ldi temp, 0b00000001 out ADCSRA, temp ; ADC ausschalten ldi temp, 0b10000000 out ACSR, temp ; AC ausschalten ldi temp, 0b00000000 out WDTCR, temp ; WDT ausschalten ldi temp, 0b01000000 out GIMSK, temp ; External Interrupt Enable ldi temp, 0b01110000 out MCUCR, temp ; Sleep enable, INTO steigende Flanke enable ldi Used, 0x00 ; Used muss auf 0 sein sbi PORTB, PORTB1 ; Pull- up aktivieren rjmp Main Main: SEI ; Interrupts global freigeben SLEEP ; Power Down Mode rjmp Main Interrupt: in SREGbak, SREG sbis Used, 7 ; >>>>>>>37<<<<<<< rcall Blink ; Wenn "Used" noch nicht beschrieben wurde, Blinken ldi Used, 0xFF rjmp IntEnd Blink: SEI ldi Used, 0xFF ; Used = 1 , zeigt, dass Routine aufgerufen wurde sbi DDRB, 3 ; PortB3 als Ausgang sbi PORTB, 3 WartenLow: ; PortB3 bleibt 998mS lang auf 0 ldi r18, 72 ; 1*1 Warten1: ldi r19, 73 ; 72*1 Warten2: dec r18 ; 72*73*1 brne Warten2 ; 72*73*2 dec r19 ; 72*1 = ca.1s brne Warten1 ; 72*2 sbi PORTB, 3 ldi r19, 32 WartenHigh: ; PortB3 2mS lang auf 1 dec r19 ; brne WartenHigh cbi PORTB, 3 rjmp Blink IntEnd: out SREG, SREGbak ; Alles wiederherstellen, LIFO beachtet reti Leo
Hi 'sbis' ist der Befehl für IO-Register. Für r0...r31 nimmt man 'sbrs'. MfG Spess
Kopf >>>>> Tisch Funktioniert wunderbar, noch einmal vielen Dank für die Hilfestellungen. MfG, leo
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.