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
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
Wenn ich reti schreibe, dann spielt es total verrückt, springt wie wild
umher....
wegen der Interrupts, ich verwende einen AtMega8, der hat 19
Interruptquellen
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.
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
@Sven: Danke klingt logisch, werde es aber erst später versuchen!
@Dennis: Ich lasse bei den Interrupts alles so wies ist (ausser das was
im Code an den Einstellungen geändert wird!) Ich mache auch immer
Einzelschritt, aber er "biegt" eben immer so komisch ab....
Danke für die Hilfe
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?
Oder muß man eventuell das entsprechende Interrupt-Flag wieder löschen?
Manchmal durch Reinschreiben einer 1, logischerweise ;-)
Schau mal, welche Flags gesetzt werden und wo diese wieder gelöscht
werden, oder auch nicht.
Sven
Hallo!!
Bin nach längerer Suche nicht fündig geworden: Habe nirgends gelesen,
dass ich etwas wieder zurückstellen muss, oder kann mir jemand was
anderes sagen? ich wäre wirklich froh um jeden Ratschlag!!
Grüsse
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
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
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
Dank Uwe, es hat daran gelegen, dass beide Ext interrupt aktiviert
wurden, mit einem gehts jetzt!
Was meinst du mit dem SREG sichern? Das habe ich noch nie gehört, was
macht das für einen Sinn??
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