Interrupt?!?!

Gast #28777
Lesenswert?

Hallo!!

Habe gerade neu mit Assembler angefangen und habe mir ein Programm 
schreiben wollen: Ich habe nur den Anfang programmiert und wollte es mit 
AVRStudio 4 simulieren. Leider gibt es immer einen Interrupt, wenn ich 
gar keinen erwarte: Hier der Code und wo der Interrupt kommt:

.include "m8def.inc"
.def temp=r16
.org 0x000
rjmp reset
reti
rjmp extint
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
rjmp adcfertig
reti
reti
reti
reti
reti
reset:
ldi temp, LOW(RAMEND)  ;LOW-Byte der obersten RAM-Adresse
out SPL, temp
ldi temp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, temp
ldi temp,0b00001010             ;ext int bei steigender Flanke
out mcucr,temp
sei
**ldi temp,0b11000000    ;Beide ext int aktivieren
out gicr,temp
ldi temp,0b01000000             ;Admux auf Eingang 0 stellen out 
admux,temp
ldi temp,0b11000111    ;ADC aktivieren, und starten
out adcsr,temp
rjmp reset
extint:
nop
ret
adcfertig:

Dort wo ** gibt es einen Interrupt. Ich weiss, der Fehler ist 
wahrscheinlich doof, aber ich bin noch doofer und kann ihn nicht finden!

Danke für eure Hilfe
Gast #28780
Lesenswert?

Hey!

Also bin auch noch nicht lange dabei, aber ich frag mich wieso du 
soviele Reti-anweisungen am anfang hast, obwohl ich glaube, daß es nur 
14 gibt, außerdem muß es in deiner Interrupt-Marke extint: RETI heißen 
statt ret.

Außerdem glaube ich, dass deine ADCfertig anweisung zwei Zeilen höher 
stehen mußte!

Gruß Dennis
Gast #28782
Lesenswert?

Also Reti ist eigentlich die richtige Anweisung, bei Rücksprüngen aus 
Interrupts.
Wie simulierst du denn die Interrupts?
Oder läßt du alles so wie es ist, startest und dann kommt Murks raus!
Ich würde in einzelschritten durchs ganze Programm gehen und mir die 
Register anschauen. Der Computer ist ja immer nur genauso schlau wie 
sein Programmierer.
Gast #28783
Lesenswert?

Hi Pfi!

Wenn ich es richtig sehe, solltest Du kein rjmp reset machen. Dadurch 
wird in jedem Durchlauf die Initialisierung neu gemacht. Da der 
AD-Wandler schon läuft, gibt es einen Interrupt, wenn sei ausgeführt 
wird.

Stattdessen eine Endlosschleife am Ende. Und die Interrupt-Routinen mit 
reti verlassen, dass ist schon richtig, funktioniert nur wegen Deinem 
rjmp reset nicht.

Sven

reset:
ldi temp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, temp
ldi temp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, temp
ldi temp,0b00001010 ;ext int bei steigender Flanke
out mcucr,temp
sei
**ldi temp,0b11000000 ;Beide ext int aktivieren
out gicr,temp
ldi temp,0b01000000 ;Admux auf Eingang 0 stellen out admux,temp
ldi temp,0b11000111 ;ADC aktivieren, und starten
out adcsr,temp

wait_loop:
  ;Endlosschleife
rjmp wait_loop

extint:
nop
reti

adcfertig:
  ;Anweisung
  ;event. ADC neu starten
reti
Gast #28785
Lesenswert?

Habs trotzdem grad probiert: Nun kommt es noch einwenig anders heraus, 
hab den Code von Sven genommen (nach dem Interrupthandler am Anfang des 
Programms) nun kommt es bis "ldi temp,0b01000000" in zeile 33, dann 
springt es zum Externen Interrupt Zeile 6, dann zum Unterprogramm das 
aufgerufen wurde und dann bei reti am Schluss des Unterprogramms wieder 
auf Zeile 34, das könnte man ja noch akzeptieren, aber ab da wird 
anscheinend jeder Takt ein Interrupt ausgelöst. Muss man, wenn ein 
Interrupt ausgelöst wurde diesen zuerst deaktivieren? gerade wenn das 
Unterprogramm aufgerufen wurde??? Sollte doch nicht so sein?? Oder liegt 
es am AVRStudio 4?
Gast #28788
Lesenswert?

Also, normalerweise wird beim Auftreten eines Interrupt-Ereignisses und 
wenn der entsprechende Interrupt enabled ist, ein spezifisches Flag in 
einem Register gesetzt. Darauf wird dann bei der nächsten passenden 
Gelegenheit, z.B. nach einem sei oder auch sofort der Interrupt 
ausgeführt. Das Flag wird mitunter beim Aufruf des Interrupts (Timer) 
zurückgesetzt, mitunter beim Abrufen eines bestimmten Registers (Ich 
glaube, beim UART ist das so), mitunter muß es auch "per Hand" 
zurückgesetzt werden. Dateils dazu sollten bei der Beschreibung der 
Interrupts stehen. Ich habe zum Mega8 leider kein Datenblatt.

Schau Dir doch mal im Simulator die entsprechenden Register an, die zum 
ADC / ext. Interrupt gehören.

Sven
Gast #28789
Lesenswert?

Hab nochmals nachgeschaut, und habe gesehen, dass man etwas ins GIFR 
(Bit 7 und Bit 6) schreiben muss, habe ich auch gemacht, ohne Erfolg, 
beim Simulieren kamen keine Häkchen Bei den oben genannten Bits, das 
finde ich sehr merkwürdig.
Hat jemand ein Programm in ASM, dass Interrupts verwendet (am liebsten 
auch den Externen) dann könnte ich mir das mal anschauen, vielleicht 
fällt mir was auf!

Grüsse
Pfi
Gast #28790
Lesenswert?

Hi!
Normalerweise muss es so gehen, versuche es doch mal direkt auf dem uC. 
Ich trau dem AVR-Studio nicht über den Weg.

für den Rest deines Progr.kannst du die Zeilen

ldi temp,0b00001010 ;ext int bei steigender Flanke
out mcucr,temp

totlegen.

"sei" solltest du erst schreiben wenn alle Setup's gemacht sind.

Nochwas Wichtiges: wenn in deinen ISR's Befehle verwendet werden die 
Flag's verändern, musst du das SREG sichern und und vor "reti" 
zurückschreiben!

ISR:
in r16,SREG
.
TST......
.
out SREG,r16
reti

und nochwas:
**ldi temp,0b11000000 ;Beide ext int aktivieren

stimmt denn da die INT-Tabelle(Einsprung in ISR,sehe nur einen Ext INT 
!)????

viel Erfolg Uwe
Gast #28792
Lesenswert?

SREG ist das Status-Register, es enthält Flags, die bei Operationen 
gesetzt werden. Zum Beispiel für Verweigungen

cp r17,r18
breq ist_gleich

cp vergleicht r17 mit r18 und setzt das Zero-Flag, wenn gleich. breq 
verzweigt dann nach ist_gleich:, wenn das Zero-Flag gesetzt ist. Wird 
jetzt bei breq der Interrupt aufgerufen und im Interrupt das Zero-Flag 
verändert, zum Beispiel durch eine arithmetische Operation, wird das 
breq nicht ausgeführt. Dummerweise muß man das SREG immer erst in ein 
Arbeitsregister laden, um damit arbeiten zu können.

ISR:
in r16,SREG  ;lade Status-Register in r16
push r16  ;r16 auf Stack
          ;damit r16 wieder frei
.
TST......
.
pop r16  ;hole Status-Register aus Stack in r16
out SREG,r16  ;Status-Register wieder herstellen
reti  ;Interrupt beenden

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren