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.
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.