Hallo, Ich bin dabei gerade einen kleines Programm zu schreiben, und verwende hierzu den Assembler. Ich habe Interupt-Vektoren vergeben, die einen Timer den Compare-Wert übergeben sollen, um eine Frequenz zu generiern. Jedoch kommt mit steigender Frequenz der Timer-Interupt so oft, das er sobald er fertig ist schon wieder aufgerufen wird. In der Routine steht nur ein Befehl: Lad: out OCR1AL,temp reti Dabei wird das restlich Programm garnichtmehr abgearbeitet und er bleibt quasi in dieser Schleife hängen. Was kann ich dagegen tun, daß das Programm nicht wegschmiert? Könnt Ihr mir vielleicht helfen? Liebe Grüsse Alex
Für was brauchst du beim Timer Compare einen Interrupt ? Es geht doch auch ohne, mit Pin Toggle.
Hallo, ich möchte immer wenn der Timer ( im CTC-Mode ) seinen Compare-Match ausführt, also Rückgesetzt wird, einen OCR-Wert neu setzten. Ich kenne leider PIN-Toggle nicht? Muss ich Pin-toggle mit sbis abfragen? Ich dachte mit nem Interupt sei es am besten, aber nun macht das solche Probleme :-(
Wie oft muß denn tatsächlich der OCR-Wert aktualisiert werden? Wenn der Interrupt wirklich so oft ausgeführt wird, muß der Wert im temp-Register ja äußerst klein sein. Möglichkeit 1: Aktualisierung des OCR im Hauptprogramm. Dann aber muß der Zugriff synchronisiert werden, weil sonst der Timer "hustet". Ist für sehr hohe Frequenzen nicht geeignet, da das Hauptprogramm auch zu langsam ist. Möglichkeit 2: Den Wert in "temp" begrenzen, so daß er einen bestimmten Wert nicht unterschreitet.
> Ich dachte mit nem Interupt sei es am besten, aber nun macht das > solche Probleme :-( Nun, dein Prozessor hat eben eine betrenzte Rechengeschwindigkeit. Daran kann auch die Verwendung von Interrupts nichts ändern. Sie verschlimmert das Problem eher noch ein wenig, da die Ausführung einer Interrupt-Routine selbst noch einen gewissen Overhead hat. Was mir hier so einfällt sind nur die offensichtlichen Sachen (keine so hohen Frequenzen erzeugen oder Prozessortakt erhöhen).
disable doch einfach den interrupt, wärend die interrupt rutine läuft... damit übersiehst du zwar einige intrrupts, doch scheller als der prozzi ist kann er nicht rechnen...
Hi, Poste doch mal deinen Code, vieleicht ist ja was verkehrt. Hast du den Stackpointer richtig Initialisiert, sonst kann es auch passieren, das das Programm nach der Interruproutine nicht richtig weiter macht.
Hallo, erstmal danke für Eure Antworten. Der Timer ist mit clk 1 (no prescaling) eingestellt, wobei der Interne-Controller-Oszi auf 4MHz steht. Der kleinste Compare-Wert sollte bei 50 liegen, da so eine Freqeunz von ca. 40kHz entsteht, die ich brauche. Ich möchte den OCR-Wert halt immer zum bestimmten Zeitpunkt laden, nämlich dann, wenn der Timer gerade rückgesetzt geworden ist. Da sonst ein "überzählen" des Timers vorkommen könnte. Der Wert für den OCR wird dabei in einem zweiten Timer (T0) von 255 runtergezählt, sodaß eine definiert ansteigende Frequenz entsteht. Es wäre aber egal wenn der OCR-Wert ein paar Matches (Toggles) später aktualisiert wird, hauptsache er wird nach dem Rücksetzen gleich geladen (wegen dem überzählen). Vieln Dank nochmals Alex
Hast du dein Programm mal im Simulator vom AVR-Studio laufen lassen? Wenn nicht, dann mach das mal, da wirst du genau sehen wo er sich verrennt. Die ganzen "reti's" die du am Anfang hast sollte man so auch nicht schreiben, wenn überhaupt, dann ein reti pro Interrupt und jedes Interrupt am besten mit .org [Interruptadresse]. Nochwas, was mir grad aufgefallen ist, ein "ret" oder "reti" funktioniert nur mit "rcall" nicht mit "rjmp"
Natürlich debugge ich es, jedoch ist es aufgrund der vielen Zählerei mit den Timern sehr sehr aufwendig Schritt für Schritt das Programm zu analysieren. Ich habe deswegen an allen Interrupt-Vektoren Breakpoints gesetzt, an denen ich erkennen kann wo er hinspringen will. Doch wenn ich feststelle, daß er zu Reset will, weiß ich aber nicht wo er herkommt. @Pöschi: Deine Aussage mit den Retis an den Interruptadressen verwirrt mich. Ich habe mehrfach gelesen, dases so gemacht werden soll. Ich habe lediglich die nichtgebrauchten Interrupts mit reti versehen. Und pro Interruptadresse habe ich auch jeweils nur ein Reti gesetzt. Die Retis die im Programm auftauchen habe ich als Rücksprung für die Interrups gedacht. Da ich beim Interrupt in ein Unterprogramm springe, dort durch einen Vergleich zweier Werte eine Verzweigung kommt, dann jenachdem also ein anderes Unterprogramm mit rjmp oder branch..... angesprungen wird, und wenn dieses durchgearbeitet ist kommt reti. Ich will hiermit lediglich meine Auffassung darlegen um korrigiert werden zu können. Bitte tut das auch wenn ich falsch liege ! Grüße Alex
Die Ablaufstruktur deines Programms ist ziemlich konfus. So wird z.B. deine Hauptschleife, die eigentlich ja schon nach der Initialisierung anläuft, vom Timer1-Overflow immer wieder neu aufgerufen. Dann gibt's rjmp und rcall kreuz und quer durch den Code, und es gibt kein einziges ret im ganzen Programm.
Hi, braucht der Mega32 nicht jmp-Befehle anstatt rjmp Befehle bei den Interrupts? Ich schreibe immer für alle Interrupts einen jmp Befehl. Für die nicht verwendeten definiere ich ein Label WrongInterupt, das dann irgendwas macht (meistens einen RESET). Gruss Andreas
Hi, Mal kurz ne erläuterung: jmp: Sprung zur Adresse (belibige Adresse) rjmp: Sprung relativ zur gegenwärtigen Adresse (+-2k Worte entfernt) rcall: Aufruf eines Unterprogramms relativ zur gegenwärtigen Adresse (auch +-2k Worte entfernt) vorherige Programmadresse wird auf dem Stack abgelegt ret: Rücksprung vom Unterprogramm auf die Adresse im Stack (adresse wo der rcall Befehl stand) reti: Rücksprung vom Interrupt und löschen des Interrupt Flag im Status Register (Bei diesem Befehl wir normalerweise an die Stelle zurückgesprungen wo der Interrupt ausgelöst wurde Hier mal ein Beispie wie sowas bei mir aussieht ;Start .CSEG .ORG 0x00 rjmp init .ORG $016 rjmp rs232 ;RS232 Interupt .ORG $022 rjmp twi init: ;Stack init ldi temp,LOW(RAMEND) out SPL,temp ldi temp,HIGH(RAMEND) out SPH,temp . . . rs232: ;Code reti Funktioniert einwandfrei auf diese Art. Die Interrupts die ich nicht benötige lasse ich einfach weg, du kannst sowieso jedes Interrupt in den jeweiligen Registern ein und aus schalten.
Schau dir einfach mal im Datenblatt des Mega32 (und als Vergleich auch in dem des Mega8535) die Interrupt-Vektortabelle an. Aus Unterprogrammen springt man übrigens nicht mit reti zurück sondern mit ret. ...
Hi, das mit org und rjmp funktioniert sicher, solange die Interruptroutine im rjmp Sprungbreich liegt. Ich gebe alle Interrupts an, damit ich eine definierte Reaktion bei fälschlicherweise auftretenden Interrupts habe. Gruss Andreas
Bei mir sind noch keine falschen Interrupts aufgetreten, man schaltet ja eigentlich nur die Interrupts ein, die man benötigt :-) Ich würd das Programm trozdem mal durch den Simulator laufen lassen, auch wenn es eine mühselige Arbeit ist.
mal 'ne dumme Frage: löscht der Mega das Anforderungsflag beim Interrupteintritt?
Hi Deine Interruptvektoren am Programmanfang sinf falsch. Wenn du es schon so machen willst muss es so aussehen: .org 0x0 rjmp Reset nop reti nop reti nop ... ist aber die unsaubere Variante. Wenn du sicher gehen willst übenimm den Aufbau aus dem Datenblatt. MfG HG
"Ich gebe alle Interrupts an, damit ich eine definierte Reaktion bei fälschlicherweise auftretenden Interrupts habe." Die Reaktion ist dann aber, daß Programmierfehler verschleiert werden. Mit etwas Pech fallen sie erst dann auf, wenn schon viele Geräte beim Kunden sind und zurückgerufen werden müssen. Wenn Du einen definierte Reaktion haben willst, dann nimm eine, die möglichst auffällig ist, z.B. eine Endlosschleife, die alle LEDs blinken läßt. Peter
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.