Forum: Mikrocontroller und Digitale Elektronik 8051 - Timerwert einstellen bei 20MHz anstatt 16MHz


von Arno (Gast)


Lesenswert?

Hallo,

ich habe eine kleine Aufgabe von meinem Dozenten bekommen und hatte 
diese meines Wissen richtig gelöst.
Allerdings, als ich die Aufgabe zurück bekam, war diese leider doch 
nicht richtig. :(
Vom Dozenten bekam ich auch nicht die Auflösung, das wird nach den 
Ferien in der Klasse besprochen.
Aber bevor ich ganz dumm dastehe, frage ich euch mal:

Es geht um den 8051er, immer mit 16MHz verwendet und dem Timer0 als 
16bit-Zeitgeber.
Für diese Aufgabe wird aber die Frequenz von 20MHz verwendet.
Die Frage lautet: "Wie lauten die Werte für TL0 und TH0 bei 20MHz, damit 
der 16bit Timer0 auf 28µs eingestellt wird?".

Hier meine Berechnung erstmal für 16MHz:
1
// T0 auf 28µs einstellen: 65536 - 28 = 65508
2
TH0 = 65508 / 256;   // 0xFF
3
TL0 = 65508 % 256;   // 0xE4
Das war laut Dozent richtig.

Nun mein Versuch mit 20MHz:
(20MHz / 12) = 1,67MHZ = 600ns
16bit -> (65536 * 600ns) = 39321µs (ungefähr)
1
// T0 auf 28µs einstellen: 39321 - 28 = 39293
2
TH0 = 39293 / 256;   // 0x99
3
TL0 = 39293 % 256;   // 0x7D
Dieser Code für 20MHz ist falsch.

Kann mir bitte jemand erklären, wie man das richtig rechnet?

Danke,
Arno

von R. W. (quakeman)


Lesenswert?

Also bei einem ursprünglichen 8051 wird der Takt durch 12 geteilt.

Somit wird der Timer bei 16MHz mit 16MHz/12=1,333MHz getaktet. Dies 
entspricht pro Takt genau 1/16MHz*12=750ns

Somit ist deine erste Rechnung für 16MHz auch schon falsch. Der Timer 
bekommt alle 750ns einen Takt. Du willst 28µs erreichen. Dann teilst du 
28µs/750ns und erhälst 37,333 Takte. Gerundet sind das dann 37 Takte und 
der Reloadwert ist dann 65535-37=65498.
Bei 37 Takten erhälst du genau 27,75µs, was die beste Näherung ist.

Deine Rechnung bei 16MHz ging von 1µs pro Takt aus, was aber nur bei 
12MHz und nicht 16MHz der Fall gewesen wäre.

Bei 20MHz dementsprechend 1/20MHz*12=600ns (wie du auch richtig 
ausgerechnet hattest). Nun berechnest du die Anzahl Takte indem du 
28µs/600ns=46,666 Takte berechnest. Gerundet also 47 Takte womit der 
Reloadwert 65536-47=65489 lautet.
Mit 47 Takten erhälst du genau 28,2µs, was ebenfalls die beste Näherung 
ist.

Ich hoffe, du hast das Prinzip jetzt verstanden. :)

Ciao,
     Rainer

von Wilhelm F. (Gast)


Lesenswert?

Du subtrahierst µSekunden von Timertakten. Das geht natürlich nicht.

Um den Nachladewert zu berechnen, mache ich es wie folgt:

16MHz/12 ergibt eine Taktfrequenz von 1,333333MHz.

Daraus ermittelt man die Überlaufrate pro Sekunde:

Taktfrequenz/Überlaufrate = Timertakte:
1,333333MHz/(1/28µs) = 37,333 Takte.

65536-37=65499.



Gesamtformel aus obiger Rechnung wäre also:

Timerwert = 65536 - Quarzfrequenz/12 * Überlaufzeit



Der gerade errechnete Wert ist etwas anders als der richtige Wert deines 
Dozenten. Aber ich arbeite schon lange exakt genau mit diesen µC.

In manchen Datenblättern von 8051-ern sind die Berechnungen der 
Timerwerte, Baudraten, etc., auch drin.

von Arno (Gast)


Lesenswert?

Ich Idiot...

Na klar, so wirds gemacht!
Wenn man sich erst einmal im Matsch festgefahren hat, ist es alleine 
sehr schwierig, wieder auf die Straße zu kommen!
Dank euch beide fahre ich wieder auf der neu geteerten Straße! :)

Danke,
Arno

von Peter D. (peda)


Lesenswert?

Arno schrieb:
> Kann mir bitte jemand erklären, wie man das richtig rechnet?

Man läßt einfach den Compiler die Konstanten ausrechnen:
1
#define F_CPU     20e6
2
#define INTERVAL  28e-6
3
#define RELOAD_VAL (unsigned int)(F_CPU / 12.0 * INTERVAL + 0.5)
4
#define HIGH(x)  (x >> 8)
5
#define LOW(x)   (x & 0xFF)
6
7
TH0 = HIGH(-RELOAD_VAL);
8
TL0 = LOW(-RELOAD_VAL);

Anbei das Listing für 20 und 16MHz


Peter

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Hier nun das Listing.


Peter

von Wilhelm F. (Gast)


Lesenswert?

Arno schrieb:

> Dank euch beide fahre ich wieder auf der neu geteerten Straße! :)

Soweit zumindest die Theorie.

In Wahrheit kann man den Timer 0 im Interrupt natürlich nicht so einfach 
mit diesem errechneten Wert nachladen, sondern weiß da an der Stelle 
nicht genau, wie weit der Timer schon hinter dem Überlauf weiter gezählt 
hat. Diesen neuen Wert muß man auf den errechneten Wert aufaddieren, und 
auch die Zyklen für diese Addition noch mal hinzu addieren.

Für einen einmaligen Timerüberlauf mit Interruptauslösung oder 
Interruptflagsetzung würde es auf die einfache Art aber reichen.

Aber das Thema kommt dann bei euch sicherlich noch dran.

von Arno (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Anbei das Listing für 20 und 16MHz

Super, vielen Dank für die Mühe!
Das vereinfacht so einiges, wenn man den Compiler zum Ausrechnen der 
Konstanten benutzt.
Das +0.5 verwendest du zum "clever runden"?!
Darauf kann ich aufbauen und werde noch so einige Timerversuche in den 
Ferien starten.

Außerdem habe ich den Fehler gemacht (ist mir bei den tollen Antworten 
aufgefallen), dass der 16 Bit-Timer IMMER bis zum Überlauf 65535->0 (als 
bis 0x10000) zählt, egal bei welcher Quarzfrequenz, darum darf man 
absolut nicht so wie ich (39321 - 28 = 39293) rechnen!

Wilhelm Ferkes schrieb:
> Für einen einmaligen Timerüberlauf mit Interruptauslösung oder
> Interruptflagsetzung würde es auf die einfache Art aber reichen.
> Aber das Thema kommt dann bei euch sicherlich noch dran.
Interrupts haben wir noch nicht gehabt, wir fragen derzeit nur das 
Überlaufbit des Timers ab und und setzen es per Hand wieder zurück.
Interrupts sollen irgendwann nach den Ferien drankommen.

Ich denke, ich habe dank euch in diesem Fall die Basics kapiert!

Vielen Dank!!!
Arno

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
Noch kein Account? Hier anmelden.