Hallo Zusammen, ich soll mittels dem µC SAB80C517A ein Lauflicht im 1Sekunden-Takt in Assembler programmieren. für Timer0 Mode1 müssen TH0 und TH1 Werte gesetzt werden. Jedoch weiß ich noch nicht genau, wie ich diese berechne. für einen 10ms-Timer habe ich im Internet folgende Berechnung gefunden: 10ms= 10000µs 2^16= 65535 --> 65535 - 10000 = 55535 --> 0xD8EF --> TH0 = 0xD8 --> TLO = 0xEF Aber wie verhält es sich nun bei 1Sekunde? Wenn ich dieses Berechnungsschema analog für 1sekunde anwende, müsste ja folgendes rauskommen. 1s = 1000000µs -->65535 - 1000000 --> hier erhalte ich dann aber einen negativen Wert! und das kann ich mir nicht vorstellen. Kann mir jemand helfen??? Vielen Dank im Vorraus!
Amy18146 schrieb: > -->65535 - 1000000 --> hier erhalte ich dann aber einen negativen Wert! > und das kann ich mir nicht vorstellen. Kann mir jemand helfen??? Richtig, der Timer müsste mehr Zählen als reingeht. Du brauchst eine weitere Zählvariable. Bei jedem Timerüberlauf wird sie inkrementiert und vergrößert damit den Zählbereich.
hm...ok, aber ich verstehe dann noch nicht genau, wie ich die weitere zählvariable dann mit TH0 und TL0 in verbindung bringe.... jemand hatte mir gesagt gehabt, dass TH0 den Wert C0hex und TL0 den Wert 63hex hat. da verstehe ich die berechnung nicht, bzw. wie man auf die werte TH0 und TL0 kommt. TH0 * 256 + TL0 99*256=25344 + 192 = 25536 = 63C0hex weißt das einer vielleicht?
Amy18146 schrieb: > Aber wie verhält es sich nun bei 1Sekunde? Die Annahme ist wohl, daß dein 80517 mit einem Quarz 12MHz betrieben wird, und nicht im Slow-Down-Mode, der noch mal durch 8 teilen würde. Dann ergibt sich ein Maschinenzyklus von exakt 1µs. TH0 und TL0 ergeben zusammen das 16-bit-Register des Timer 0. Der Timer zählt nicht nur bis 65535, sondern mit Überlauf bis 65536. Diese Zahl muß man für die Berechnung der Zeiten verwenden. Also, für 10ms beispielsweise: T0 = 65536 - 10000 Leider kann der Timer alleine nur bis 65536µs zählen. Möchte man 1 Sekunde, muß man sich was ausdenken, z.B. eine weitere Zählvariable. Jetzt kann man schauen, wie man glatte Werte bekommt. Z.B. sind 1000000µs = 50000µs mal 20. Also: Timerwert 50ms berechnen: T0 = 65536 - 50000. Jedes mal, wenn der Timer jetzt überläuft, eine Zählvariable um 1 hoch zählen, und zwar bis 20. So erhält man die Sekunde. Der Assembler hat spezielle Anweisungen, um den berechneten 16-bit-Wert in zwei 8-bit-Werte zu splitten: High und Low. Das muß man der Anleitung des Assemblers entnehmen, wie es genau funktioniert. Evtl. gehts auch mit Shift-Befehlen und Ausmaskierung der benötigten bits. Es ist von Assembler zu Assembler unterschiedlich. Natürlich programmiert man für den Timer einen Interrupt, denn der Timer soll ja endlos durch laufen, und immer wieder mit dem berechneten Wert nachgeladen werden. Das ist beim Timer 0 noch mal etwas trickreich. Es gibt 2 Möglichkeiten, ihn nachzuladen. Entweder on-the fly, oder man stoppt ihn, subtrahiert die Stopzeit vom berechneten Wert, und startet ihn wieder. In diesem Interrupt zählt man die Zählvariable bis 20 hoch, und stellt sie dann wieder auf 0. Der 80517 hat sicher auch einen anderen Timer mit Auto-Reload. Das müßte ich aber nachschauen, Timer 2 könnte das sein. Mit dem 80C517A arbeite ich gelegentlich auch noch. Er ist zwar uralt, aber für eine Menge Spielereien reicht er immer noch. Kürzlich spielte ich noch mit einem Lauflicht an der PWM, damit kann man die LEDs dann auch sanft ein- und ausschalten. Ist aber etwas mehr Programmieraufwand.
ok, vielen dank für deine ausführliche antwort. nun habe ich es verstanden. folglich müsste mein code auch funktionieren: ; -------------------------------------------------------------------- ; ; Lauflicht im Sekundentakt mittels Timer 0 Mode 1 ; ; -------------------------------------------------------------------- $INCLUDE (REG517A.inc) ; Konstanten definieren MODE EQU 01H ; Timer 0 Mode 1 Low EQU B0H ; Timerwert für 50ms berechnen: HIGH EQU 3CH ; --> 65536 -50000 = 15536 ; TH0 + TL0 = 15536 = 3CB0hex ; --> Zusätzliche Zählvariabel "ZAEHL", ; die bei jedem Timerüberlauf um 1 ; erhöht (bis 20) ZAEHL EQU 20 ; Zählvariable mit Startwert 20dez (20 * ; 50 ms = 1 sekunde) CSEG at 00h ; legt Codesegment auf 00hex fest LJMP INIT ; Sprung zu Initialisierung ORG 000Bh ; Sprungmarke zur ISR für Timer0 LJMP START ; Sprung zu Start ; Initialisierungen INIT: MOVE A,#00h ; Akku löschen MOV P4, #00h ; Port 4 mit 00hex setzen MOV TMOD, #MODE ; Timer 0 Mode 1 MOV TH0, #HIGH ; schreibe in TH0 den Wert von HIGH MOV TL0, #LOW ; schreibe in TL0 den Wert von LOW MOV R2, #ZAEHL ; R2 ist Zählvariable MOV TF0, #00h ; Überlaufflag des Timers auf Null setzen ; Hauptprogramm START: MOV TH0, #HIGH ; schreibe in TH0 den Wert von HIGH MOV TL0, #LOW ; schreibe in TL0 den Wert von LOW SETB EAL ; allgem. Interruptsperre aufgehoben SETB ET0 ; externen Interrupt (Timer0) freigeben SETB TR0 ; Timer0 starten DJNZ R2,START ; erhöhe R2 um "1" und springe zu START ; wenn ungleich 0 MOV R2, #ZAEHL ; R2 ist Zählvariable = 20 INC A; ; Akku incrementieren MOV P4, A ; Akkuinhaltausgabe auf Ports (LEDs) LJMP INIT ; Sprung zu Start --> Lauflicht beginnt ; von vorne END
eine frage habe ich noch: wenn ich timer0 mode 2 benutzen möchte, wie berechne ich den nachladewert für TH0? vielen dank.
schaust Du hier: 8051http://www.ne555.at/8051-mikrocontrollertechnik/343-timer-programmierbeispiele.html
Amy18146 schrieb: > eine frage habe ich noch: > > wenn ich timer0 mode 2 benutzen möchte, wie berechne ich den > nachladewert für TH0? > > vielen dank. Bei einem Timerinterrupt für Timer 0 im 16-bit-Mode kann ich dir helfen, daß der Timer im Interrupt wirklich absolut exakt nachgeladen wird:
1 | FREQUENCY EQU 18000/8 ; Quarz in kHz /8 = Slow-Down-Mode |
2 | RELOAD EQU 0 - FREQUENCY/3*5 + 7 |
3 | |
4 | für einen Interrupt alle 20ms |
5 | |
6 | CLR EAL |
7 | CLR TR0 ;Berechnung des tatsaechlichen |
8 | MOV A,#LOW(RELOAD) ;neuen Start-Wertes fuer den Timer |
9 | ADD A,TL0 ;praeziser Abstand msec |
10 | MOV TL0,A ;der Interrupt-Signale |
11 | MOV A,#HIGH(RELOAD) |
12 | ADDC A,TH0 |
13 | MOV TH0,A |
14 | SETB TR0 ;Timer nach dem Laden erneut starten |
15 | SETB EAL |
Hier wird der Timer in jedem Interrupt gestoppt, nachgeladen, und wieder gestartet. Die 7 sind die 7 Takte, in denen der Timer gestoppt ist, und nachgeladen wird. Ich hatte diese Befehlssequenz jahrelang in einer DCF77-Uhr, lief gut. Die Ersetzung RELOAD ist ein 16-bit-Wert, der irgendwo mit Defines definiert wird. Das ist aber bei jedem Assembler anders. Auch auf einem C-Compiler geht die Nachladung nur exakt so. Ich habe in den 8051-Projekten deshalb immer noch ein Assembler-File drin, oder Inline-Code.
hm...so ganz ist mir das nicht klar... also ich dachte jetzt erkannt zu haben, dass die berechnung des reloadwertes folgendermaßen aussieht: Reloadwert: 2^8=256, da nur TH0 benutzt wird. TL0 ist im mode2 nur zum Wert halten da. f-osz 0= 12MHz f-osz/12= 10000/ 256= 39,0625 (=rund 40) 10000/40= 250, daraus ergibt sich folgendes: 256-250 = 6 dez (Reloadwert) oder habe ich da etwas falsch verstanden????
Was willst du mit dem Mode 2? Eine sehr hohe Interruptfrequenz, die das ganze Programm ausbremst? Schau dir die von mir gepostete Nachladesequenz an. Die geht bei 12MHz für eine 1ms, 5ms, 10ms, glatte Werte.
Hallo, das Lauflicht soll auch mit Timer0 Mode2 realisiert werden. Das ist ein Teil einer Aufgabe!!! Die Berechnung für Mode2 ist so richtig oder? Vielen Dank.
Amy18146 schrieb: > Die Berechnung für Mode2 ist so richtig oder? Jep, sieht gut aus. Mit dem Wert 6 bekommst du 250µs-Intervalle. Da fehlt dann in der Interruptroutine nur noch eine Zählvariable, mit der man die längeren Zeiten realisiert.
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.