Gut das Du das ansprichst, sorry, es muß wirklich so heißen,Da der Interrupt ausgelöst wird, wenn der Zähler auf 0 springt, muss es doch heissen.
.equ timer = 256 - 90
somit haben wir ein Takt mehr, also wieder ein paar µs gewonnen
Gruß Sebastian
Werbung
Gut das Du das ansprichst, sorry, es muß wirklich so heißen,Da der Interrupt ausgelöst wird, wenn der Zähler auf 0 springt, muss es doch heissen.
.equ timer = 256 - 90
somit haben wir ein Takt mehr, also wieder ein paar µs gewonnen
Gruß Sebastian
Hmm...die Aufgabe ist schon ziemlich schwer. Also die Interruptroutine ist doch eigentlich indirekt auch zeitum, zeitum1 und zeitum2, oder? Denn dort springt er ja in preufZaehler hin. Oder brauch ich zeitum, zeitum1 und zeitum2 gar nicht anrühren und nur pruefZaehler und die loop ändern?
Gruß
Thomas
alles was zwischen preufZaehler und reti steht, wird in dem interrupt abgearbeitet ja, nachdem Du Fertig bist soll dazwischen nur inc zahler und Timer neuladen stehen der rest im Hauptprogramm, komm das schafst Du.
Ich geh jetzt schlafen, wie gesagt lass Dir ruhig zeit damit,
Du weiß genug um das zu lösen.
Gruß Sebastian
Ok, dann hab ich ja richtig gedacht, also dann bis morgen, werd mal schaun, ob ichs heut noch hinbekomm.
Gruß
Thomas
Ging schneller, als ich gedacht hab![]()
Zu deinen Fragen:
1. Hmm...weil die Datei nun um 0,06kb kleiner geworden ist? *g* Ich weiß es nicht, hab auch deine Posts weiter oben gelesen, aber nichts brauchbares gefunden![]()
Vielleicht dient das auch der Geschwindigkeit des Programms. Denn wenn er schneller auf ein "reti" trifft, wird das Interrupt auch schneller wieder freigegeben. Ist aber nur reine Vermutung.Kann mir das leider nicht wirklich vorstellen. Hoffe, dassde nun nicht enttäuscht von mir bist, weil ich eine so leichte Frage nicht beantworten kann
![]()
2.Wenigstens hab ich die programmiertechnische Aufgabe gelöst, ich hoffe doch richtigCode:.include "m8def.inc" .equ time = 256-90 ;Damit wird der Timer vorgeladen .equ LED = PB2 ;LED an B.2 .def tmp = r16 ;Mein Universallregister .def zaehler = r18 ;Mein Zählregister .org 0x000 rjmp reset ;Interruptvektor "reset:" .org OVF0addr rjmp pruefZaehler ;Interruptvektor für Timer0 Überlauf, hier springt ;das Programm hin, wenn der Timer überläuft reset: ;Stack einrichten ldi tmp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse out SPH, tmp ldi tmp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse out SPL, tmp sbi DDRB, LED ;B.2 als Ausgang cbi PORTB, LED ;B.2 auf LOW stellen -> LED aus am Anfang ;Timer Register werden belegt, hier Timer 0 ldi tmp, (1<<CS02) | (1<<CS00) ;prescaler ist 1024 out TCCR0, tmp ;Register TCCR0 ist für den Prescaller zuständig ldi tmp, (1<<TOIE0) ;Hier werden Interrupts nach Timer0 Überlauf eingeschaltet out TIMSK, tmp ;Register TIMSK ist dafür zuständig ldi tmp, time ;Hier wird der Timmer vorgelaen und zwar mit 255-90 out TCNT0, tmp ;Er läuft 90 mal durch, bevor ein Interrupt auftritt sei ;Interrupts zulassen loop: cpi zaehler, 0b00101000 ;Wenn Zählregister = 14 ist breq zeitum ;dann spring zu "zeitum:" rjmp loop ;Immer wieder selbst aufrufen -> Endlosschleife zeitum: clr zaehler ;Zählregister auf 0 setzen sbic PINB, LED ;überspringe, wenn B.2 = 0 ist (LED aus?) rjmp zeitum1 ;wenn B.2 = 1, dann spring zu "zeitum1:" zeitum0: sbi PORTB, LED ;B.2 = 1 setzen -> LED an rjmp loop ;wieder zur loop springen zeitum1: cbi PORTB, LED ;B.2 auf 0 setzen -> LED aus rjmp loop ;wieder zur loop springen pruefZaehler: inc zaehler ;Zählregister um 1 erhöhen ldi tmp, time ;Hier wird der Timer vorgelaen und zwar mit 255-90 out TCNT0, tmp ;Er läuft 90 mal durch, bevor ein Interrupt auftritt reti ;wieder zurück, wo du hergekommen bist![]()
Gruß
Thomas
Achja, stimmt der Kommentar bei dieser Zeile?![]()
out TCNT0, tmp ;Er läuft 90 mal durch, bevor ein Interrupt auftritt
Eine teufliche Fußangel hast du noch drin.
Da ist zunächst deine Hauptschleife:Das sieht ganz unschuldig aus.Code:loop: cpi zaehler, 0b00101000 ;Wenn Zählregister = 14 ist breq zeitum ;dann spring zu "zeitum:" rjmp loop ;Immer wieder selbst aufrufen -> Endlosschleife
Jetzt stell dir vor, nach dem cpi gibt es einen IRQ (Interrupt ReQuest), daß also eine Interrupt Anforderung vorliegt.
Mit cpi hast du das SREG (Status Register) verändert.
Es hat verschiedene Flags, die das Ergebnis des Vergleiches darstellen wie 'größer als', 'gleich', etc.
Danach testest du mit breq das Z-Flag (Zero). Es ist gesetzt, wenn zahler-0b00101000 gleich 0 ist. In diesem Falle springst du nach zeitum.
Aber erst kommt deine Interrupt Service Routine (ISR) zum Zug:Das inc erhöht zaehler um 1 und setzt u.a. das Z-Flag:Code:pruefZaehler: inc zaehler ;Zählregister um 1 erhöhen ldi tmp, time ;Hier wird der Timer vorgelaen und zwar mit 255-90 out TCNT0, tmp ;Er läuft 90 mal durch, bevor ein Interrupt auftritt reti ;wieder zurück, wo du hergekommen bist
Z=1, falls das Ergebnis=0 ist; Z=0 sonst.
Die darauf folgenden Befehle tasten das Z nicht mehr an, und nach dem reti landest du beim breq von loop.
Das breq wird also dann verzweigen, wenn
- zaehler=0b00101000 (=0x28 = 40) ist, und es nach den cpi kein IRQ gibt oder
- zaehler=0b11111111 ist in loop, und es nach dem cpi ein IRQ gibt.
Auf das SREG kannst du mit in und out zugreifen, da fällt dir bestimmt was ein...
Gruß, Georg-Johann
Disclaimer: none. Sue me.
Da hast du was verwechselt.
SREG ist ein Hardware-Register, das alle AVRs haben. Wenn du zB ein sei Befehl machst, setzt du dadurch das I-Bit im SREG.
Andere Hard-Register sind zB PORTB, SPL, SPH, ...
Schau mal in das Kurzdatenblatt zum Mega8. SREG ist das erste Register im IO-Bereich ("Register Summary").
Welche Flags im SREG durch einen Maschinenbefehl verändert werden, steht in der Tabelle zu "Instruction Set Summary" in der Spalte "Flags".
Disclaimer: none. Sue me.
Axo, hab nu auch deinen Post verstanden. Also du meinst, direkt nach dem Befehl cpi, wenn dort die Interrupt-Routine aufgerufen wird? Nun hab ich das dann so geändert, bin mir aber nicht sicher, ob das so richtig ist. Die LED blinkt aber immer noch im 1 Sekundentakt.
GrußCode:.include "m8def.inc" .equ time = 256-90 ;Damit wird der Timer vorgeladen .equ LED = PB2 ;LED an B.2 .def tmp = r16 ;Mein Universallregister .def statusreg = r17 ;Mein Statusregister .def zaehler = r18 ;Mein Zählregister .org 0x000 rjmp reset ;Interruptvektor "reset:" .org OVF0addr rjmp pruefZaehler ;Interruptvektor für Timer0 Überlauf, hier springt ;das Programm hin, wenn der Timer überläuft reset: ;Stack einrichten ldi tmp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse out SPH, tmp ldi tmp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse out SPL, tmp sbi DDRB, LED ;B.2 als Ausgang cbi PORTB, LED ;B.2 auf LOW stellen -> LED aus am Anfang ;Timer Register werden belegt, hier Timer 0 ldi tmp, (1<<CS02) | (1<<CS00) ;prescaler ist 1024 out TCCR0, tmp ;Register TCCR0 ist für den Prescaller zuständig ldi tmp, (1<<TOIE0) ;Hier werden Interrupts nach Timer0 Überlauf eingeschaltet out TIMSK, tmp ;Register TIMSK ist dafür zuständig ldi tmp, time ;Hier wird der Timmer vorgelaen und zwar mit 255-90 out TCNT0, tmp ;Er läuft 90 mal durch, bevor ein Interrupt auftritt sei ;Interrupts zulassen loop: in statusreg, SREG ;SREG sichern cpi zaehler, 0b00101000 ;Wenn Zählregister = 14 ist breq zeitum ;dann spring zu "zeitum:" rjmp loop ;Immer wieder selbst aufrufen -> Endlosschleife zeitum: clr zaehler ;Zählregister auf 0 setzen sbic PINB, LED ;überspringe, wenn B.2 = 0 ist (LED aus?) rjmp zeitum1 ;wenn B.2 = 1, dann spring zu "zeitum1:" zeitum0: sbi PORTB, LED ;B.2 = 1 setzen -> LED an rjmp loop ;wieder zur loop springen zeitum1: cbi PORTB, LED ;B.2 auf 0 setzen -> LED aus rjmp loop ;wieder zur loop springen pruefZaehler: inc zaehler ;Zählregister um 1 erhöhen ldi tmp, time ;Hier wird der Timer vorgelaen und zwar mit 255-90 out TCNT0, tmp ;Er läuft 90 mal durch, bevor ein Interrupt auftritt out SREG, statusreg SREG wiederholen reti ;wieder zurück, wo du hergekommen bist
Thomas
[-X Daß die LED im Sekundentakt blinkt, bedeutet nicht, daß das Programm korrekt ist! Du weisst nur, daß das Programm nicht korrekt ist, wenn die LED nicht blinkt wie sie soll...Zitat von toeoe
In deinem Prog tauchen Interrupts nicht allzu oft auf. Timer0 muss überlaufen (90 Takte) und hat einen Prescaler von 1024.
Nen Timer0 IRQ gibt's also nur alle 92160 Takte. Und falls er nicht nach dem cpi ausgelöst wird, stört er auch nicht.
Das fiese an Fehlern in der Interrupt-Programmierung ist, daß diese Fehler oft nur sporadisch zuschlagen.
Es ist auch denkbar, daß die Ausführungszeit deines Hauptprogramms eine gerade Anzahl von Takten braucht und dadurch nie ein IRQ direkt nach dem cpi entsteht.
Wenn du aber irgendwo in deinem Prog eine Kleinigkeit änderst, geht es womöglich nicht mehr, weil sich dadurch die Laufzeit minimal verschiebt und dann die IRQ eben doch nach dem cpi ausgelöst wird.
Dann wirst du dir nen Wolf suchen, weil dein Programm vorher ja "korrekt" war und du denkst, der Fehler liegt an deiner kleinen Änderung.![]()
Disclaimer: none. Sue me.
Lesezeichen