Forum: Mikrocontroller und Digitale Elektronik Timerproblem 89C5131A-UM


von M. D. (derdiek)


Lesenswert?

Hallo,
ich hab versucht mich mit dem Datenblatt ins Thema Timer einzulesen, 
aber komme nicht so recht weiter.

Also ich habe einen Controller: AT89C5131A-UM.
Ich will eine Baudrate generieren für die serielle Schnittstelle.
Das Quartz ist ein 12 Mhz, da ich dieses für die integrierte 
USB-Schnittstelle zum flashen brauche.

Was ich jetzt nicht verstehe, ist ob man weiterhin Timer0 und Timer1 
benutzen kann, wie beim 89C51CC03, den ich von der Schule bekommen habe, 
oder ob man das jetzt alles mit dem Timer2 realisieren muss, weil im 
Datenblatt nichts mehr von Timer0/1 beschrieben ist.
Zudem sind für Timer2 mehrere Formeln angebenen, einmal in der Sektion 
Serial I/O Port, und in Timer2. Da steig ich momentan nicht richtig 
durch.

Wie muss ich da jetzt allgemein vorgehen wenn ich eine Baudrate von 9600 
haben möchte?
Meine momentane Initialisierung ist folgende:
1
SCON=0x50;
2
BDRCON &= 0xEC //BRR=0, SRC=0
3
BDRCON |= 0x0E //TBCK=1, RBCK=1, SPD=1
4
BRL= 0xF9 //Wert vom Keil-Rechner, Teiler fragwürdig
5
ES=1
6
BDRCON |= 0x10 //starten

Gruß derdiek

von 5131benutzer (Gast)


Lesenswert?

sieht eigentlich ok aus
ich würde klare Verhältnisse schaffen mit
BDRCON = 0x0E

also
BDRCON = 0x0E ; stop baudrateclock
SCON = 0x50
BRL = 217 ; 256-39 = 9600 baud @ 12 MHz, SMOD1 = 0
ES = 1
BDRCON |= 0x10


für polling statt interrupt setze ich
SCON = 0x52

von 5131benutzer (Gast)


Lesenswert?

sri, natürlich // statt ;
bin mehr der Assembler-Freak ;-)

von 5131benutzer (Gast)


Lesenswert?

Timer1 und 0 kann man weiterhin benutzen.
Deren Dokumentation hat Atmel in ein allgemeines
8051-PDF verschoben.
Auch Timer 2 kann man unabhängig von dem Baudraten-
Generator benutzen, wenn Du den gesonderten Baudraten-
takt (BRR) benutzt, wie Du es oben codiert hast.
Es stehen also alle drei Timer 0, 1 und 2 frei zur
Verfügung.

von 5131benutzer (Gast)


Lesenswert?

Die Beschreibung zu Timer 0 und 1 und weitere 8051-
Architektur-Details hat Atmel in folgendes Dokument
verschoben:
doc4316.pdf

Eine Beschreibung des Befehlssatzes zu 8051 findet
man in:
doc0509.pdf
Für Dich als C-Programmierer weniger interessant,
aber es lesen hier vielleicht noch Andere mit.

von M. D. (derdiek)


Lesenswert?

Alles klar, besten Dank für die Hinweise.

Werd mich da mal durch lesen. Mit dem BRL-Wert 217 funktioniert es 
leider noch nicht, evtl hab ich da auch was anderes falsch gemacht.
Es kommt nur Quatsch im Terminal an momentan ;)

von 5131benutzer (Gast)


Lesenswert?

SMOD1 in SCON ist 0 ?

von M. D. (derdiek)


Lesenswert?

Das ist doch nach dem Reset automatisch 0 oder?
Sonst setz ich das nochmal direkt auf 0.

von 5131benutzer (Gast)


Lesenswert?

Ein wenig mehr source-code wäre hilfreich...
Insbesondere, was die Interrupt-Behandlung
der TX-Routine betrifft.
Das TI-Flag ist eine beliebte Falle.

Vielleicht eine wiederkehrende Sequenz schicken,
z.B. 0x55. Dann mit hterm das empfangene Bit-
Muster analysieren.

von 5131benutzer (Gast)


Lesenswert?

Ja, SMOD1 ist default 0, aber ich sehe ja nicht den
ganzen source-code. Wer weiß, ob da nicht irgendwo
SMOD1 = 1 steht? ;-)
Ich setze z.B. SMOD1 immer auf 1, aber das braucht
es in diesem Falle nicht.

von M. D. (derdiek)


Lesenswert?

Moment ich schließ mal mein Scope an und versuch die Baudrate zu messen.
Meld mich gleich nochmal.

von M. D. (derdiek)


Lesenswert?

Im restlichen Code wird nichts mehr mit den Registern gemacht, nur noch 
SBUF. Das was ich gepostet hab steht in der Serial_Init und die wird nur 
einmal aufgerufen.

Hab das Scope mal angeschlossen, wenn ich 0x55 in einer Schleife 
schicke, sind die Flanken 190uS auseinander, 1/0,00019 = 5263,16
Also fallende Flanke 1 -> steigende Flanke 1. |_|

1/9600 = 104,2 uS..
Dann müsste ich also den Reloadwert größer machen damit der Timer nicht 
so lange läuft oder?

von 5131benutzer (Gast)


Lesenswert?

füge bei der Baudraten-Einstellung ein
PCON |= (1<<SMOD1)

oder

PCON |= 0x80

von 5131benutzer (Gast)


Lesenswert?

Ich denke mal, die Formel im Datenblatt stimmt bezüglich
SMOD1 nicht.

Sollte wohl besser 2^(1-SMOD1)
statt 2^SMOD1
lauten...

von M. D. (derdiek)


Lesenswert?

Komisch ist eigentlich das selbst wenn ich per Scope die Baudrate auf 
ca. 100uS einstelle nur Quatsch ankommt..

Du meinst also SMOD = 1, und dann

BDRCON = 0x0E ; stop baudrateclock
SCON = 0x50
BRL = 217 ; 256-39 = 9600 baud @ 12 MHz, SMOD1 = 0
ES = 1
BDRCON |= 0x10

?
Dann müsst ich ja bei über 10k Baud liegen oder nicht?

von M. D. (derdiek)


Lesenswert?

Hmm.. Weiß zwar nicht wieso aber jetzt gehts ;)
Habs jetzt so gemacht, Smod=1 und restliche Einstellungen wie von dir 
gepostet.

Besten Dank :)

von 5131benutzer (Gast)


Lesenswert?

ok, also das mit SMOD1 in der Formel passt schon. ;-)

Ich hatte übersehen, dass ich meine 5131-CPU mit X2 = 1
betreibe, also im 6-clock-Modus.
Damit verdoppelt sich die Taktfrequenz für den Bauraten-
Generator.
Für die Einstellung der richtigen Baudrate sind also
nicht nur BRL, SPD und SMOD1 zu beachten, sondern auch
X2 (in CKCON0).

Mit
X2 = 0 (default)
SMOD1 = 0 (default)
SPD = 0 (default)
BRL = 253 // 256-3
für 9600 Baud zu setzen

Ich würde bevorzugen
X2 = 1
SMOD1 = 1
SPD = 1
BRL = 178 // 256-78
ebenfalls für 9600 Baud

von 5131benutzer (Gast)


Lesenswert?

Also um das abzuschließen - es geht ja jetzt -
in meinem ersten Beispiel hatte ich meine X2 = 1
unterschlagen, womit bei Dir mit X2 = 0 dann
natürlich nicht 9600 Baud, sondern 4800 Baud
erzeugt wurde. Das passt zu Deiner Messung von
ca. 190 us pro Bit - genau wären es 208 us für
4800 Baud gewesen.

Die beste Näherung an die 9600 Baud bekommst Du
mit den Einstellungen
X2 = 1
SMOD1 = 1
SPD = 1 // steckt in dem BDRCON = 0x0E drin
BRL = 178 // 256-78

die Variante
X2 = 0
SMOD = 0
SPD = 0
BRL = 253 // 256-3
liefert 10416 Baud als Näherung an 9600 Baud
und verbietet sich eigentlich wegen der über
8% Abweichung.

Womit auch klar wird, warum ich gerne SMOD = 1
setze.
Und X2 = 1 verdoppelt die Leistungsfähigkeit
Deiner CPU.

Viel Spaß mit dem AT89C5131!

von 5131benutzer (Gast)


Lesenswert?

ersetze SMOD durch SMOD1 oben. ;-)

von M. D. (derdiek)


Lesenswert?

Jo supi, das mal ne gute Erklärung.
Danke für deine Hilfe!

Ich versteh nur noch nicht, wie du auf die BRL-Werte kommst.
also die 256-78, bzw die 256-3.

Aber dafür hab ich glaub noch zu wenig Hintergrundwissen.

von 5131benutzer (Gast)


Lesenswert?

für die 256-78:
12 MHz  16  9600 = 78,125 Hz, näherungsweise 78 Hz
Also ist der Teiler 78, um aus 12 MHz die 9600 Baud
zu gewinnen.

Der Baudratenteiler ist aber ein Aufwärtszähler, d.h.
er wird immer beim Überlauf 255->256 neu gesetzt.
Um einen Teiler durch 78 zu erhalten, muss der Teiler
mit 256 minus 78 vorbelegt werden, damit er nach 78 Takten
"überläuft" und BRL als Startwert neu nach BRH geladen
wird.
256-78 = 178 als Startwert.
178..179..180.. usw. 255..256(=0) peng! neu laden mit
178..179.. usw.

mit 256-3 das Gleiche, der Zähler wird aber nicht mit
12 MHz gefüttert, sondern mit 12 MHz /12 /6 und danach
noch einmal /2 (SMOD1).
12 MHz /2 /6 2  16 / 9600 = 3,255 Hz, näherungsweise 3 Hz
aber viel weiter weg als 78,125 zu 78...
Der Teiler wäre daher 3, bzw. da ein Aufwärtszähler
253..254..255..256(=0), durch 253 ersetzt

Die Gurus und Egonamen in disem Forum mögen meine
unprofessionelle Zusammenfassung verzeihen...
Andere können das natürlich viel besser erklären. ;-)

von 5131benutzer (Gast)


Lesenswert?

da gingen ein paar / verloren ;-)
einfügen, wo passend erscheint

von M. D. (derdiek)


Lesenswert?

Ah naja aber hast es gut genug erklärt, habs zumindest soweit verstanden 
das ich auch von alleine auf den Wert kommen kann jetzt ;)

Hast mir sehr weiter geholfen :)

von Bernhard S. (b_spitzer)


Lesenswert?

Noch ein Tip zur Nutzung der seriellen Schnittstelle in C.
Wenn man sich von der Assembler-SBUF-Fummelei löst und auf Standard-C 
Funktionen aus der stdio.h zurückgreift wird ein Programm leichter 
portierbar. Mit printf("Hallo"); wird z.B. direkt auf die serielle 
Schnittstelle gesendet. Zeichen=getch(); oder putch(Zeichen); 
funktionieren auch ganz nett. getch() macht dabei automatisch ein Echo 
(mit putch).

Nun aber zur Falle dabei: printf() und putch() prüfen das TI-Falg VOR 
dem Versenden eines Zeichens und sparen damit evtl. die Wartezeit, wenn 
der UART eh frei war. Dabei muss man aber das TI-Flag bei der 
Initialisierung einmal setzen, sonst hängt das Programm nach printf.
Also SCON = 0x52; schreiben.
(zumindest gilt das für uVision und RIDE. Beim SDCC ist putch() leer und 
muss selber programmiert werden, da hat man dann das TI-Flag selber wie 
gewünscht zu behandeln.)

tschuessle
B.

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.