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
Hast du dir schon das Tutorial für Interrupts hier auf der Webseite ddurchgelesen?
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
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.