Timerproblem 89C5131A-UM

OP #1918587
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
Gast #1918624
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
Gast #1918636
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.
Gast #1918647
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.
OP #1918649
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 ;)
Gast #1918681
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.
Gast #1918683
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.
OP #1918712
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?
OP #1918749
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?
Gast #1918777
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
Gast #1918798
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!
OP #1918823
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.
Gast #1918847
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. ;-)
#1958067
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 16 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.