Hallo, wie kann ich für einen Timer interrupt die konkrete Zeit ausrechnen? Normal ist das ja Dauer eines Zykluses = 12 / Taktfrequenz => 12 / 11059200 = 1,085µs Dauer des Timers bis zum Überlauf = 65536 * 1,085µs = 71,11ms und dann will ich halt, das der Interrupt in 2 Sekunden ausgelöst wird: also: 2000ms * 10³ / 1,08506944µs = 1843200 und das in Hex sind ja 1C20 also TH0 = 1C und TL0 = 20 aber das passt ja nicht oder? Wenn man das wieder in Dauer des Timers bis zum Überlauf einsetzt, dann komme ich auf 1,20s also 65536 * 1843200 oder habe ich da irgendeinen Denkfehler? Naja, ich kann ja auch mal was zu meinem Ziel sagen, was vielleicht eher an den Anfang gehört aber naja. Eine LED soll bei einem Druck auf einen Taster leuchten, die eingeschaltete LED soll dann für 2 Sekunden leuchten und dann ausgeschaltet werden und dafür eine andere ein. Wenn während dieses Zeitraums der Taster nochmal gedrückt wird, dann soll das Zählen von vorne beginnen.
Für 2 Sekunden mußt du in den Timerinterrupt noch mal eine Variable als Zähler einbauen, denn der Timer 16 bit schafft die 2 Sekunden von alleine gar nicht. Mit dem 11MHz-Quarz schafft man ungefähr maximal 70ms, wenn der Timer von Null an immer auf 10000h über läuft, also wieder auf Null.
also eine Variable? Wie kriege ich das denn hin die Variable immer eins hochzuzählen, wenn der Timer voll gelaufen ist, bzw. wenn ein Zyklus durch ist? Ich will ja wie gesagt nach 2 Sekunden eine LED ausschalten und davor soll diese angeschaltet sein, also soll die ISR Für den Timer erst anlaufen, wenn 28 mal der Timer voll gelaufen ist? Ich weiß echt nicht, wie ich das realisieren soll ... Hättest du mal ein Beispiel oder jemand anders?
> ... 1843200 und das in Hex sind ja 1C20 ...
Das sind 1C2000.
Du lässt den Timer z.B. alle 0,1 Sekunden überlaufen. Diese Überläufe
zählst du dann mit und kommst damit auf längere Zeiten.
Gerade sehe ich, dass 0,1 Sekundenüberläufe nicht gehen, also nimmst du z. B. 50 Millisekunden.
Tobias J. schrieb: > Hättest du mal ein Beispiel oder jemand anders? Mit welcher Programmiersprache arbeitest du? Assembler oder C vielleicht? Den Timer 0 muß man beim 8051 im Interrupt selbst mit einem errechneten Wert nach laden, und das ist etwas kniffelig, weil er ja weiter läuft und auf den Takt genau 100%-ig präzise sein soll. Leichter wäre es, den Timer 2 zu benutzen, weil der Autoreload hat. Aber das hilft ja nicht, wenn man Timer 2 für was anderes braucht. Ich benutze aber den Timer 0 selbst immer als Zeitgeber. Ein 8051 hat auch gar keinen Timer 2, erst der 8052. Es gab noch einen Timer-Mode für Timer 0 und 1 mit Autoreload im 8 bit Mode, die machen aber eine sehr hohe Interruptbelastung, weil 8 bit sehr schnell über laufen, und verwendete diesen Mode deswegen nach Möglichkeit nie. Die Timer-ISR ist aber schon vorhanden, oder? Könntest du da Inline-Assemblercode einfügen? Als Zusatzzähler nimmt man ein Byte aus dem RAM.
So, ich hab mal etwas gerechnet, um einen Timerinterrupt in genau 50ms zu bekommen. Dafür muß man den Timer im Interrupt stets mit dem Wert 65536-46080 laden. 46080 Schritte braucht er für 50ms. Das wäre der hexadezimale Wert von 4C00h. Den muß man im Interrupt irgend wie immer neu in den Timer hinein bekommen. Da zählst du mit einer Variablen dann für 2 Sekunden die 50ms-Schritte, und es sind derer 40. Bei 40 führt man seine Aktion aus, z.B. LED blinken, und setzt die Variable wieder auf 0 zurück. Also mach am Anfang der Interruptroutine mal sowas wie z.B.: TL0 = 00h TH0 = 4Ch Dann gehts mal grob ungefähr. Wie es dann fein geht, da hab ich bestimmt auch noch was parat. Da der Nachladewert für TL0 hier zufällig Null ist, gibt es vielleicht noch einen kleinen Trick, und man lädt nur TH0 nach. TL0 steht ja beim Interrupteinsprung schon irgend wo, zählt weiter, vielleicht auf 3 oder 4. In diesem Fall kann man das auch rein nur in C machen, und braucht keinen Assembler mit genauer Berechnung.
Naja, ich mache das ganze in C und derzeit sieht das so aus: Die Taster und die LED's sind übrigens Low-aktiv #include <stdio.h> #include <reg52.h> #include <irq52.h> void timer_isr(void) interrupt; near int counter = 0; near int presscounter = 0; IRQ_VECTOR(timer_isr, TIMER0) void timer_isr(void) interrupt { TH0 = 4C; if(counter < 40) { P3_B4 = 1; // Ist eine LED P3_B6 = 0; } counter++; } void main(void) { TMOD = 0x01; TF0 = 0; // Überlaufflag löschen TR0 = 1; // Timer 0 starten ET0 = 1; // Interrupt für Timer 0 freigeben EA = 1; // alle Interrupts freigeben P3_B3 = 0; // Ebenfalls LED if(P3_B2 == 0) { P3_B3 = 1; P3_B4 = 0; presscounter++; if(presscounter == 2) { counter = 0; presscounter = 0; } } while(1); } So ist das doch dann sowet richtig oder ? Wenn 40 Überläufe fertig sind, dann sind das 2 Sekunden oder? 50ms * 40 = 2000ms = 2 Sekunden So ist das doch richtig oder? P3_B2 wird beim Start eingeschaltet. Wenn der Taster P3_B2 betätigt wird, dann geht die LED P3_B4 an und wenn dann 2 Sekunden vorbei sind, dann geht die LED P3_B4 an und die LED P3_B6 leuchtet.
naja, ich habe mich ja noch einmal korrigiert. Eigentlich müsste es ja 40 sein, weil 50 * 20 erst 2 Sekunden machen, bzw. 2000ms => 2sek Du hast auch übrigens Recht, ja es müsste >= sein. Sonst ist das ganze aber doch jetzt richtig oder? Wenn 2 sekunden um sind, dann geht die eine LED aus und die andere an und wenn währenddessen der Taster gedrückt wird, wie setze ich dann beginnt das ganze ja auch von vorne oder muss ich dafür auch TL0 und TH0 = 00 setzen?
Tobias J. schrieb: > So ist das doch richtig oder? Was sagt denn der Test? Tobias J. schrieb: > Du hast auch übrigens Recht, ja es müsste >= sein. Nein, ich war mir nicht ganz sicher, und habe darum wieder meinen Beitrag gelöscht. Du machtest es etwas anders, als ich selbst es gemacht hätte. Aber das ist ja egal, viele Wege führen nach Rom.
Was ist eigentlich mit der Main-Schleife while(1)? Sollte nicht dort der if-Block hinein?
Also die Vorgehensweise wäre ja grundsätzlich: In Main die gedrückte Taste erkennen. Von Entprellung muß man da bei 2 Sekunden auch gar nicht groß reden. Entweder setzt man dann in Main ein Flag, was dem Interrupt mit teilt, daß jetzt eine Taste gedrückt wurde. Von da ab zählt der Zähler im Interrupt bis 40 hoch. Wenn er diese erreicht hat, wird er wieder gelöscht, und auch das Flag, und die LED betätigt. Oder wenn man es genauer haben möchte, gibt man bei erkannter Taste erst den Timer frei, und hat den Timer schon mit dem Nachladewert vor geladen. Beim Endwert 40 löscht der Interrupt die LED wieder, und sperrt auch den Interrupt und stoppt den Timer. Also es gibt da hunderttausend Varianten. Zur absolut exakten Tastendruckerkennung müßte diese auch einen externen Interrupt auslösen, und in diesem Interrupt erst die Zählung initialisiert werden.
Sooo .. ich habe das ganze noch einmal überarbeitet aber muss der Timer dann erst beim Tastendrücken gestartet werden, wenn ich das erst haben will, das die 2 Sekunden erst beim Drück gezählt werden soll? So sieht das ganze jetzt aus. #include <stdio.h> #include <reg52.h> #include <irq52.h> void timer_isr(void) interrupt; near int counter = 0; near int presscounter = 0; IRQ_VECTOR(timer_isr, TIMER0) void timer_isr(void) interrupt { TH0 = 4C; if(counter >= 40) { P3_B4 = 1; // Ist eine LED P3_B6 = 0; } counter++; } void main(void) { TMOD = 0x01; TF0 = 0; // Überlaufflag löschen ET0 = 1; // Interrupt für Timer 0 freigeben EA = 1; // alle Interrupts freigeben P3_B3 = 0; // Ebenfalls LED while(1) { if(P3_B2 == 0) { P3_B3 = 1; P3_B4 = 0; if(presscounter == 1) { TR0 = 1; // Timer 0 starten } else if(presscounter == 2) { counter = 0; presscounter = 0; TF0 = 0; } presscounter++; } _wait_ms(1); // wegen Tastenprellen } } bzw. mit ^= kann man ja invertieren aber das nützt ja nichts? (also bei TR0 invertieren?)
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.