Forum: Mikrocontroller und Digitale Elektronik Verständnisfrage zur USART


von Älex (Gast)


Lesenswert?

Hallo zusammen,
in manchen Bibliotheken sehe ich öfter folgendes :

In der Headerdatei:

#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden

In der C Datei folgendes:


    UBRR0H = (unsigned char)(UBRR_VAL>>8);  // Baudrate einstellen
    UBRR0L = (unsigned char)(UBRR_VAL);


Ich frage mich gerade was da wieso die das so Programmieren. Hat jemand 
ne Ahnung?

Grüße
Alex

von Joachim (Gast)


Lesenswert?

Also dir zu helfen ist gerade nicht ganz einfach. Wenn man einfach auf 
deine Frage antwortet

Älex schrieb:
> Hat jemand ne Ahnung?

käme wohl "ja" als Antwort. Verstehst du was an dem Code nicht? Und wenn 
nein: was?

Gruß

von M. K. (sylaina)


Lesenswert?

Älex schrieb:
> Ich frage mich gerade was da wieso die das so Programmieren. Hat jemand
> ne Ahnung?

Warum die was Programmieren? Meinst du warum man erst UBRR_VAL im Header 
ausrechnet und nicht direkt in die C-Datei einsetzt? Ganz einfach: Nicht 
jeder µC wird mit der gleichen Frequenz( und Baud-Rate) betrieben. So 
wie hier gezeigt wird der UBRR_VAL immer von der vorgegebenen Frequenz 
(und Baud-Rate) abhängen was wiederum bedeutet dass man immer den 
gleichen Code verwenden kann und nur die Freuquenz( und Baudrate) 
richtig einstellen muss. Arbeitserleichterung nennt man das auch ;)

von Älex (Gast)


Lesenswert?

Entschuldigt ich habe glaube ich die Frage falsch gestellt :). Ich meine 
warum die diese Formel für UBRR_VAL verwenden. Im Datenblatt steht ja 
UBRRn = (fCLKio / 16BAUD) - 1


das entspricht ja nicht   ((F_CPU+BAUD*8)/(BAUD*16)-1)



Warum also der Umweg. Danke euch schon mal für eure Antworten.

Grüße
Alex

von Joachim (Gast)


Lesenswert?

Watt? Vielleicht, weil dir Formel umgestellt wurde :) ?!

von Kali (Gast)


Lesenswert?

Der Kommentar muss mit berücksichtigt werden.
1
// clever runden


Der Rest ist Grundschulmathematik. Alles klar?

von Älex (Gast)


Lesenswert?

Ne leider ist nicht alles klar sonst würde ich nicht Fragen :).  Stimmt 
schon das da ähnlich Ergebnisse rauskommen beim nachrechnen. Die Frage 
ist halt warum das ganze? Kann man damit später besser shiften,etc? Aber 
danke für eure Antworten.

Grüße
Alex

von Stefan E. (sternst)


Lesenswert?

Älex schrieb:
> Die Frage
> ist halt warum das ganze? Kann man damit später besser shiften,etc?

Es ist eine Integer-Rundung. Wenn z.B. eigentlich 3,7 rauskommen würde, 
kommt mit der Originalformel 3 heraus, und mit der modifizierten 4.

von Kali (Gast)


Lesenswert?

>Stimmt schon das da ähnlich Ergebnisse rauskommen beim nachrechnen.

Nun. Nimm mal an, das der in dem Wort "ähnlich" enthaltende Unterschied 
der Ergebnisse hier relevant ist. Wieso ignorierst Du den? Deswegen auch 
der Hinweis auf den Kommentar.

von Karl H. (kbuchegg)


Lesenswert?

Älex schrieb:
> Entschuldigt ich habe glaube ich die Frage falsch gestellt :). Ich meine
> warum die diese Formel für UBRR_VAL verwenden. Im Datenblatt steht ja
> UBRRn = (fCLKio / 16BAUD) - 1
>
>
> das entspricht ja nicht   ((F_CPU+BAUD*8)/(BAUD*16)-1)


Na ja, aber fast

der einzige Unterschied besteht darin, dass zum Zähler noch mal die 
Hälfte des Nenners des Bruches dazugezählt wird.

Exkurs.

Was ergibt in C

     5 / 5

da beides ganze Zahlen sind, ist das eine Integerdivision und das 
Ergebnis ist 1

Was ergibt    6 / 5?          Die Antwort ist 1
              7 / 5                           1
              8 / 5                           1
              9 / 5                           1
             10 / 5                           2

findest du es nicht auch ein wenig unbefriedigend, wenn 9 / 5 den Wert 
von 1 ergibt? Immerhin, als Kommazahl gerechnet, wäre 9.0 / 5.0 ja 1.8 
and das liegt als Zahlenwert ja doch schon wesentich näher an 2 als es 
an 1 liegt.
Das man mit dieser Division 9 / 5 einen Fehler macht ist klar und 
unvermeidlich, denn 9 lässt sich nun mal nicht ganzzahlig durch 5 
teilen. Aber der Fehler zum 'mathematisch korrekten' Ergebnis ist 
kleiner, wenn man als Ergebnis 2 rausbekommen würde, als wie wenn man 1 
raus kriegt.

Und genau diesen Zweck erfüllt dieser zusätzliche Term. Er verursacht, 
dass in solchen Fällen dasjenige Ergebnis erhalten wird, welches den 
'kleineren Fehler' repräsentiert - den zur nächsten ganzen Zahl 
gerundeten Wert und nicht einfach nur den Wert, den man erhält wenn man 
Kommastellen ignoriert.

Einfach mal mit Zahlen durchprobieren (Ich nehm jetzt eine gerade Zahl 
als Divisor, damit die Hälfte klar definiert ist)

Original wäre es

    6 / 6                 1
    7 / 6                 1
    8 / 6                 1
    9 / 6                 1
   10 / 6                 1
   11 / 6                 2

mit der Modifikation

 6:   ( 6 + 3 ) / 6   =  9 / 6         1
 7:   ( 7 + 3 ) / 6   = 10 / 6         1
 8:   ( 8 + 3 ) / 6   = 11 / 6         1
 9:   ( 9 + 3 ) / 6   = 12 / 6         2
10:   ( 10 + 3 ) / 6  = 13 / 6         2
11:   ( 11 + 3 ) / 6  = 14 / 6         2
12:   ( 12 + 3 ) / 6  = 15 / 6         2

und hier sehen die Ergebnisse dann schon weit besser aus. Ab der 9 
aufwärts, wird das Divisionergebnis auf 2 aufgerundet, während es 
darunter zu 1 abgerundet wird.
1
  ( a + b/2 ) / b     ist also die gerundete Version  von  a / b

und das auf die im Datenblatt angegebene Formel angewendet .... ergibt 
genau das, was du im Code siehst.

von Simon H. (simi)


Lesenswert?

Wenn Du einfach

Clk/(16*Baud) rechnest, dann bekommst Du (weil Integer) die Ganzzahl, 
die am nächsten bei der theoretisch korrekten Zahl, aber kleiner ist.

Du willst aber runden, also 674.7 soll 675 geben, nicht 674.

Also musst Du eigentlich hinten noch ein +1/2 dranhängen. Das gibt's 
aber in Integer nicht. Der macht dann wieder 0 draus.

Also machst Du zuerst *8, und dann wieder /16. So errechnet der Compiler 
zuerst mal'ne ganz grosse Ganzzahl und teil die dann wieder durch 'ne 
ganz grosse Ganzzahl.

(clk + baud*8)/(baud*16) = clk/(baud*16) + 0.5. Mathematisch korrekt, 
aber das 0.5 kehrt der Compiler (oder preprozessor) unter den Teppich.

Aber:
Wenn er aber zuerst mal clk zu 8*baud addieren muss, darf er nichts 
unter den Teppich kehren. Und das dann halt entsprechend durch was 
grösseres dividieren, dann passt's wieder recht genau mit dem 0.5


Gruäss
Simon

ok, da waren andere schneller... :-)

von M. K. (sylaina)


Lesenswert?

Erklärung sind alle ganz nett aber ein wichtiges Detail wurde noch 
vergessen:

Die 1%-Grenze.
Deshalb macht man ja den ganzen Rundungskram, mal schaun ob ich es auf 
die Kette bekomme es halbwegs zu erklären:

Du möchtest mit einer bestimmten Baudrate Daten übertragen. Damit die 
Gegenstelle (z.B. PC) auch weiß, was da ankommt, sagt man ihr mit 
welcher Baudrate der µC senden (bzw. empfängt, das spar ich mir im 
folgenden aber). Nun gebietet es die Technik, dass die Baudrate, um hier 
die einzelnen Bits noch korrekt unterscheiden zu können, um maximal 1% 
schwanken darf. Und daher kommt die obige Formel. Je nach gewünschter 
Baudrate und verwendeter Frequenz passt mal die Gleichung im Datenblatt 
und mal die obige Gleichung. Ihr Sinn ist hier lediglich die Abweichung 
der "echten" Baudrate zur Ganzzahl-Baudrate auf unter 1% zu halten.
Ich hoffe dies ist verständlich, für Näheres google mal ein wenig mit 
den Worten "Baudrate, Abweichung, Fehler" zum Beispiel.

von Älex (Gast)


Lesenswert?

Danke euch für eure Hilfe. Jetzt ist es mir klarer :)

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.