Ich sitze hier am AVR Studio 7 und möchte eine USART-Ausgabe
programmieren. Zum ersten Test soll in einer Testschleife nur ein
Zeichen (z.B. 0x10101010 ) ausgegeben werden.
Ich habe einen neuen Atmega328p per debugwire angeschlossen, das
debugging funktioniert. Die fuses hatte ich zuvor auf externen Quarz
„full swing“ progammiert und am Prozessor sehe das Clocksignal an Pin 10
mit 16 Mhz in Full Swing.
Die Ausgabe beobachte ich mit dem Realterm und einem 60 Mhz – Oszi. Ich
sehe auf den Geräten auch ein Zeichen pro Ausgabe. Leider aber stimmt
Folgendes nicht:
Der Zeicheninhalt sieht am Oszi etwa aus wie (...Startbit), 00001000, (2
Stopbits...) und die Zeichenzeit ist viel zu lang: Am Oszi gemessen=
1,4 ms, sie müsste dagegen
Char.-Zeit = 11Bit * 1/Baud = 11*(1/57600) = 0,19 ms betragen.
Das Realterm zeigt auch nur falsche Zeichen an.
Mein Code liegt in der Anlage "Listing_UART-Problem.txt"
Wer kann mir sagen, was ich falsch mache oder wie ich den Fehler weiter
eingrenzen kann?
@P. F. (funkpurzel)
>Stopbits...) und die Zeichenzeit ist viel zu lang: Am Oszi gemessen=>1,4 ms, sie müsste dagegen>Char.-Zeit = 11Bit * 1/Baud = 11*(1/57600) = 0,19 ms betragen.
Das klingt nach ~ Faktor 8. Wahrscheinlich hast du die CLK-DIV8 Fuse
noch gesetzt.
Danke für die schnelle Antwort, Falk.
Ich habe eine Fuse namens LOW.CKDIV8 gefunden, den Haken gelöscht und
die Fuses programmiert. Ohne ein neuses Build hat sich die Chr.-Zeit
sofort geändert auf grob 0,15 ms, sie könnte jetzt also stimmen. Aber
leider ist der Zeicheninghalt unverändert, auch nach einem neuen Build.
Immerhin bin ich einen Schritt weiter.
Nico W. schrieb:> 0x10101010 sind 4 Bytes. Das ist dir bewusst?
Genau, ändere das mal in 0b10101010...
Und sind im RS-Empfänger die (unüblichen) 2-StopBits eingestellt?
Hallo,
ich habe da noch einen Tipp.
M. K. schrieb:> #define UBRR_VAL (F_CPU+baudRate*8)/(baudRate*16)-1
Die Berechnung mit Rundung ist korrekt, aber man kann die Formel aus dem
Datenblatt Table 20-1. auch übersichtlicher schreiben:
Sein Hauptproblem ist, wie Jim Beam schreibt:
Jim Beam schrieb:> Nico W. schrieb:>> 0x10101010 sind 4 Bytes. Das ist dir bewusst?>> Genau, ändere das mal in 0b10101010...> Und sind im RS-Empfänger die (unüblichen) 2-StopBits eingestellt?
Solange
UDR0 = 0X10101010;
besteht, ist das gleichbedeutend mit UDR0= 0x10 = 0b10000000. Hier ist
dann genau ein einzelnes Bit gesetzt welches er auch auf dem Oszi sieht
!
Karl M. schrieb:> Hallo,>> ich habe da noch einen Tipp.> M. K. schrieb:>> #define UBRR_VAL (F_CPU+baudRate*8)/(baudRate*16)-1>> Die Berechnung mit Rundung ist korrekt, aber man kann die Formel aus dem> Datenblatt Table 20-1. auch übersichtlicher schreiben:>
M. K. schrieb:> Und ne Floatrechnung draus stricken? Warum sollte man das tun? Klar,> geht auch.
Nein, da in der Berechnung nur Konstanten vorkommen, berechnet der
Compiler bereits das Ergebnis. Zur Laufzeit ist dann bereits der feste
Wert bekannt.
C.K. schrieb:> Nein, da in der Berechnung nur Konstanten vorkommen, berechnet der> Compiler bereits das Ergebnis. Zur Laufzeit ist dann bereits der feste> Wert bekannt.
Und er rechnet es dennoch als float, dann castet er es in ne 32 bit
Interger um das Ergebnis letztendlich in ein 16 bit Register zu
schreiben. Ich finde: Schön ist anders. Und damit bin ich nicht alleine
denn auch, aber nicht nur, hier im Artikel zum UART wird die
Festkommaarithmetik verwendet zur Berechnung des UBRR-Wertes.
Seite 185 des aktuellen Datenblattes zum Atmega328P (2018, DS40002016A)
zeigt auch nur Festkommaarithmetik:
1
#define MYUBRR FOSC/16/BAUD-1
Und Table 20-1 zeigt auch keine Gleitkomma-Arithemtik.
Nico W. schrieb:> Ralph S. schrieb:>> Solange>>>> UDR0 = 0X10101010;>> besteht, ist das gleichbedeutend mit UDR0= 0x10 = 0b10000000.>> Nein. 0x10 == 0b00010000.
gleichbedeutend != genau oder gleich
Ralph meinte, es ist egal ob man 0x10 oder 0b10000000 schreibt, in
beiden Fällen ist in dem Byte nur ein Bit gesetzt und alle anderen sind
0 und damit hat er völlig recht.
Du hast natürlich auch recht: 0x10 == 0b00010000 aber das ist ein klein
wenig was anderes, was Ralph meinte ;)
M. K. schrieb:> Und er rechnet es dennoch als float, dann castet er es in ne 32 bit> Interger um das Ergebnis letztendlich in ein 16 bit Register zu> schreiben. Ich finde: Schön ist anders. Und damit bin ich nicht alleine
Doch, damit bist du ganz alleine. Wen interessiert es, wie das auf dem
PC ausgerechnet wird?
Thomas E. schrieb:> Doch, damit bist du ganz alleine. Wen interessiert es, wie das auf dem> PC ausgerechnet wird?
Anbei ein Screenshot aus dem aktuellen Datenblatt. Ich sehe keine
Gleitkomma-Berechnung, was also erzählt ihr für einen Scheiß?
M. K. schrieb:> Ich sehe keine> Gleitkomma-Berechnung, was also erzählt ihr für einen Scheiß?
Warum regst du dich so enorm auf?
Was spielt das für eine Rolle?
Wenn der PC mit dem Präprozessor vor dem Compilieren einmalig eine µs
länger braucht, merkst du das garantiert nicht, oder doch?
Also reg' dich wieder ab und wisch dir den Schaum vom Mund :-)
Hallo,
was M. K.immer noch nicht verstanden hat, ist die von ihm gezeigte
Berechnung rundet ab und das von mir verwende vorgehen rundet auf.
D.h. man addiert noch 0,5 zur Rechnung dazu.
Und es ist, wie schon geschrieben UBRR_VAL wird als Konstante im
Comilerlauf erzeugt und nicht per Programmcode im AVR berechnet.
M. K. schrieb:> Thomas E. schrieb:>> Doch, damit bist du ganz alleine. Wen interessiert es, wie das auf dem>> PC ausgerechnet wird?>> Anbei ein Screenshot aus dem aktuellen Datenblatt. Ich sehe keine> Gleitkomma-Berechnung, was also erzählt ihr für einen Scheiß?M. K. schrieb:> Thomas E. schrieb:>> Doch, damit bist du ganz alleine. Wen interessiert es, wie das auf dem>> PC ausgerechnet wird?>> Anbei ein Screenshot aus dem aktuellen Datenblatt. Ich sehe keine> Gleitkomma-Berechnung, was also erzählt ihr für einen Scheiß?
Warum auch sollte man das sehen?
Die Formel rechnet mit reellen Zahlen, da können auch Nachkommastellen
entstehen!
Erst in der Implementierung im eigentlichen Atmel AVR Code muss man sich
entscheiden, wie man die Berechnung im Zahlenraum N/ oder Z/ durchführt.
Alles klar?
Karl M. schrieb:> was M. K.immer noch nicht verstanden hat, ist die von ihm gezeigte> Berechnung rundet ab und das von mir verwende vorgehen rundet auf.
1. Wie kommst du denn zur der Erkenntnis, dass ich das nicht verstanden
habe?
2. Warum sollte das Abrunden schlecht sein?
3. Was ist an deiner Lösung übersichtlicher als an meiner?
4. Warum castest du auf uint32_t wo doch ein uint16_t sinnvoller ist?
M. K. schrieb:> 2. Warum sollte das Abrunden schlecht sein?
da im Mittel bei 50% aller Fälle der Fehler um Eins zu klein ist.
Es werden bei Runden mit +0,5 alle Rechnungen mit Nachkommastelle im
Bereich von [0..0,5) auf 0 und [0,5..1) auf +1 gerundet.
Beispiel:
Gegeben: F=8Mhz, Teiler(Prescaler)=1/16, Baudrate=57600
A) Rechnung mit Abrunden (trunc):
UBBR = (uint32_t)(8Mhz/16/57600-1) = (uint32_t)(7,6806) = 7
Reale Baudrate = 8MHz/16/(7+1) = 62500 [Bit/s]
Fehler Berechnung: error = 62500/57600-1 = +8,50%
B) Rechnung mit Runden +0,5:
UBBR = (uint32_t)(8Mhz/16/57600+0,5-1) = (uint32_t)(8Mhz/16/57600-0,5) =
(uint32_t)(8,1806) = 8
Reale Baudrate = 8MHz/16/(8+1) = 55555,6 [Bit/s]
Fehler Berechnung: error = 55555,6/57600-1 = -3,55%
Ups ist ja besser!
Die reale Baudrate ist nicht gut (err >1%) aber es zeigt den Rechenweg!
> 4. Warum castest du auf uint32_t wo doch ein uint16_t sinnvoller ist?
Warum sollte das so sein - bei einer Konstanten?
Wenn man einen (16Bit) Bereichsüberlauf feststellen wollte, wie könnte
man das machen?
Karl M. schrieb:> da im Mittel bei 50% aller Fälle der Fehler um Eins zu klein ist.
Du hast dir also meine Rechnung überhaupt nicht angeschaut. Sonst
wüsstest du, dass mit meiner Lösung genau das Selbe herauskommt wie mit
deiner Lösung.
Karl M. schrieb:> Ups ist ja besser!> Die reale Baudrate ist nicht gut (err >1%) aber es zeigt den Rechenweg!
Ja, es zeigt den Rechnenweg. Aber dann rechne doch bei dem
Abrunden-Beispiel auch bitte mit meiner Lösung:
Ups, da kommt ja genau das Selbe raus wie bei deiner Lösung. Hättest du
dir meine Lösung genauer angesehen hättest du gesehen, dass auch meine
Gleichung 0.5 dazu addiert. ;)
Und da in der Gleichung nur Integer-Werte stehen wird der Compiler auch
direkt das Ganze als Integer-Rechnung behandeln, der Typcast entfällt
hier völlig.
Karl M. schrieb:> Warum sollte das so sein - bei einer Konstanten?
Weil du ein '(uint32_t)' davor schreibst. Das ist in diesem Falle nicht
sinnvoll, damit zwingst du den Compiler, auch bei einer Konstante, den
Wert als 32-bit Integer zu behandeln. Und das bei einem Wert der bei
weitem nicht mal 16 Bit groß wird und der nur in ein 16 Bit Register
rein soll.
Karl M. schrieb:> Wenn man einen (16Bit) Bereichsüberlauf feststellen wollte, wie könnte> man das machen?
Na die Kombination aus Taktrate und Baudrate, die durchaus Sinn machen
sollte, will ich mal sehen, die die 0xffff reisst. Die meisten,
sinnvollen, Kombinationen reissen ja nicht mal die 0xff.
M. K. schrieb:> Ups, da kommt ja genau das Selbe raus wie bei deiner Lösung.
Und warum pochst du dann so dermaßen hartnäckig auf deine Lösung?
Nur, weil deine Lösung beim Compilieren eine µs schneller ist?
Spielt das eine Rolle?
Was kommt im Endeffekt raus?
> Ups, da kommt ja genau das Selbe raus wie bei deiner Lösung.
Wir drehen uns im Kreis, merkst du das?
Ich könnte dich verstehen, wenn die Berechnung zur Laufzeit ausgeführt
würde. Aber so wird sie nur ein einziges Mal ausgeführt. Und zwar VOR
dem Compilieren. Und außerdem vom PC.
Und jetzt hör doch bitte auf mit der Spiegelfechterei.
Was bringt das?
Erwin D. schrieb:> Und warum pochst du dann so dermaßen hartnäckig auf deine Lösung?
Weil Karl sagte, dass meine Lösung schlechter sei und das ist Quatsch.
Sie ist mindestens genauso gut wie seine Lösung. Ich halte es hier für
völlig legitim, dass ich meine Lösung verteidige.
M. K. schrieb:> Weil du ein '(uint32_t)' davor schreibst. Das ist in diesem Falle nicht> sinnvoll, damit zwingst du den Compiler, auch bei einer Konstante, den> Wert als 32-bit Integer zu behandeln. Und das bei einem Wert der bei> weitem nicht mal 16 Bit groß wird und der nur in ein 16 Bit Register> rein soll.
Was regst du dich eigentlich so künstlich auf? Du lässt selbst doch auch
mit 32Bit rechnen. Davor bewahrt dich auch nicht, daß du nicht weißt,
was du da tust.
Der Präprozessor und nicht der Compiler, rechnet per default mit 16Bit.
Es sei denn, in der Rechnung befindet sich ein 32Bit-Wert. Was mit F_CPU
der Fall ist. Dann kommt der Präprozessor von selbst drauf, das mit
32Bit zu rechnen.
M. K. schrieb:> Weil Karl sagte, dass meine Lösung schlechter sei und das ist Quatsch.> Sie ist mindestens genauso gut wie seine Lösung.
Also ist deine Lösung besser. "Mindestens genauso gut" drückt
schließlich genau das aus. Da sie das gleiche Ergebnis liefert, ist sie
aber maximal gleichwertig.
> Ich halte es hier für völlig legitim, dass ich meine Lösung verteidige.
Jaja.