Verständnisfrage zur USART

Gast #2324640
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
#2324662
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 ;)
Gast #2324671
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
Gast #2324678
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
Gast #2324681
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.
#2324683
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.
#2324693
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... :-)
#2324829
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren