Forum: Mikrocontroller und Digitale Elektronik USART für den Datenempfang initialisieren


von Christian Karle (Gast)


Lesenswert?

Sehr geehrte Community,

mein Name ist Christian und ich bin 16 Jahre alt.
Seit ca. 2 Wochen beschäftige ich mich mit dem ATmega8515 und der 
Programmierung des AVR's in C (benutze das AtmelStudio).

Beim Lernen und bei Problemen mit der Programmiersprache C hat mir 
dieses Forum und generell das Internet schon oft weitergeholfen.

Nun möchte ich versuchen ein DMX-Signal mit meinem AVR zu empfangen.
Das Protokoll von DMX ist mir bekannt.

Jedoch bin ich auf eine Initialisierung der USART gestoßen, die ich 
leider nicht durchschauen kann. Und bitte darum, um eine einfache 
Erklärung des Programmtextes (ich habe auch selbst schon im Internet 
gesucht, die Funktion des Programmblocks jedoch trotzdem nicht 
verstanden).

Vielen Dank im Voraus,

Christian.

Hier der Programmtext:

void init_USART()
{
  UBRRL  = 1;
  UBRRH  = 0;
  UCSRC  = (1<<URSEL)|(3<<UCSZ0);
  UDR    = 0;
  UCSRA  = 0;
  UCSRB  = (1<<RXCIE)|(1<<RXEN);
}

von innerand i. (innerand)


Lesenswert?

Hallo Christian,

Die Informationen die dir fehlen findest du im Datenblatt bzw. der Doku 
des µCs.
Diese Funktion setzt Bits in den UART-Registern über die der UART 
konfiguriert wird, welche Bedeutung diese Bits haben steht, wie gesagt, 
in der Doku. (Mit dem Lesen der Doku muss man sich ganz einfach 
anfreunden wenn man µCs programmieren will).

Vom Syntax er ist dir aber grundsätzlich klar was hier passiert 
(Bitshift, bitweises Oder und so), oder?

von spess53 (Gast)


Lesenswert?

Hi

>Jedoch bin ich auf eine Initialisierung der USART gestoßen, die ich
>leider nicht durchschauen kann. Und bitte darum, um eine einfache
>Erklärung des Programmtextes (ich habe auch selbst schon im Internet
>gesucht, die Funktion des Programmblocks jedoch trotzdem nicht
>verstanden).

Dir ist aber bekannt, das im Datenblatt vom ATMega8515 Codebeispiele zur 
Initialisierung und auch zum Senden und Empfangen sind?

MfG Spess

von Christian K. (christiankarle)


Lesenswert?

Vielen Dank für die schnellen Antworten.

Mir ist bewusst das ich die UART mittels dem Setzen eines Bits an einer 
bestimmten Stelle Konfigurieren kann.

Ich weis dass, das UBRR-Register aus 12-Bits besteht,
unterteilt in:
UBRRL (enthält die 8 unteren Bits)
UBRRH (enthält die 4 oberen Bits)

Zusatz:
(DMX-Baudrate=250000Bd)
(CPU Frequenz=8MHz mit externem Quarz)-> Fusebits sind richtig 
eingestellt.

Die Zahl die in dieses Register übertragen werden muss berechnet sich 
dann nach folgender Formel (CPU-Frequenz/(Baudrate*16-1))
in diesem Fall wäre das Ergebnis "2".

Im Quellcode steht nun:

UBRRL  = 1;  -> Bedeutet das bei UBRR1 ein Bit gesetzt wird ?
UBRRH  = 0;  -> Bedeutet dass, das gesamte Register 0 ist?

Somit würde das Register im Binärsystem so aussehen : 000000000010 = 
2(in Dezimal)

Habe ich das Alles richtig verstanden ?
Oder mache ich einen Denkfehler?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Christian Karle schrieb:
> Vielen Dank für die schnellen Antworten.
>
> Mir ist bewusst das ich die UART mittels dem Setzen eines Bits an einer
> bestimmten Stelle Konfigurieren kann.

Gut

>
> Ich weis das das UBRR-Register aus 12-Bits besteht,
> unterteilt in:
> UBRRL (enthält die 8 unteren Bits)
> UBRRH (enthält die 4 oberen Bits)

Ja, Diese Unterteilung ist aber ein technisches Detail.
Wichtig ist: es ist ein 12 Bit Wert.
Die eigentliche Frage ist: Was besagt der Wert, was macht er? wie wird 
er berechnet?

> Die Zahl die in dieses Register übertragen werden muss berechnet sich
> dann nach folgender Formel (CPU-Frequenz/(Baudrate*16-1))

SChau dir nochmal genau deine Vorlage an, von der du die Formel her 
hast. Wo genau stehen die -1?

Ist das
1
      CPU_Frequenz
2
   --------------------
3
    Baudrate * 16  -  1

oder steht dort
1
      CPU_Frequenz
2
   --------------------  - 1
3
    Baudrate * 16

Beides ist nicht dasselbe!

> UBRRL  = 1;  -> Bedeutet das bei UBRR1 ein Bit gesetzt wird
> UBRRH  = 0;

Nö, das bedeutet, dass da nicht 2, sondern 1 als Ergebnis der Berechnung 
in das UBRR Register geladen wird (sieh die beiden Einzelregister als 
notwendiges Übel an. Das UBRR Register ist die logische Zusammenfassung 
der beiden, so dass wir von einem 16 Bit Wert reden können, der in ein 
Register geladen wird. UBRR ist ein uint16_t, den du aber aus 
technischen Gründen in 2 Stück 8-Bit Happen beschreiben musst.)

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Die Zahl die in dieses Register übertragen werden muss berechnet sich
>dann nach folgender Formel (CPU-Frequenz/(Baudrate*16-1))
>in diesem Fall wäre das Ergebnis "2".

Deine Formel ist falsch. Richtig: CPU-Frequenz/(Baudrate*16)-1.
Und das ergibt für UBRR 1.

>UBRRL  = 1;  -> Bedeutet das bei UBRR1 ein Bit gesetzt wird

Ja, Bit0.

>Somit würde das Register im Binärsystem so aussehen : 000000000010 =
>2(in Dezimal)

Nein. wenn das Register 1 enthalten soll darf nur Bit0 gesetzt sein ->

0b000000000001.


MfG Spess

von Christian K. (christiankarle)


Lesenswert?

Also ich habe noch einmal nachgeschaut die Formel ist:


    CPU_Frequenz
 --------------------  - 1
    Baudrate * 16




Somit wäre das Ergebnis "1" Binär= 000000000001 = 1(in Dezimal)
Ok, den Teil mit dem UBRR-Register verstehe ich jetz.
Muss UBRRH unbedingt mit UBRRH=0; angegeben werden, oder darf dieser 
Teil auch einfach weggelassen werden und die Bits sind Automatisch "0"?

An nächster Stelle steht dann:

UCSRC  = (1<<URSEL)|(3<<UCSZ0);

Bedeutet das ein Bit bei URSEL gesetzt wird und die Zahl 
3(Dezimalsystem)= 11 im Binärsystem um 0 Stellen (also um UCSZ0(da 
erstes Bit)) verschoben wird. Somit ergibt sich eine Framerate von 
8-Bits(steht in der Tabelle im Datenblatt). Beide Werte werden danach 
per "oder" verknüpft und in das UCSRC-Register geschrieben.

Die Funktion von (1<<URSEL) verstehe ich jedoch nicht...
Im Datenblatt steht dazu:

Bit 7 – URSEL: Register Select
Diese Bit wählt zwischen einem Zugriff auf das UCSRC oder dass UBRRH 
Register aus. Es wird als 1 gelesen, wenn das UCSRC Register gelesen 
wird. Das URSEL Bit muss 1 sein, wenn in das UCSRC Register geschrieben 
wird.


Hier im Forum gibt es wirklich tolle Leute :)
Vielen, vielen Dank das Ihr mich so toll unterstützt :)

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Christian Karle schrieb:

> Ok, den Teil mit dem UBRR-Register verstehe ich jetz.
> Muss UBRRH unbedingt mit UBRRH=0; angegeben werden, oder darf dieser
> Teil auch einfach weggelassen werden und die Bits sind Automatisch "0"?

Du ahnst es schon :-)
Die Antwort lautet: Was steht dazu im Datenblatt?

> An nächster Stelle steht dann:
>
> UCSRC  = (1<<URSEL)|(3<<UCSZ0);
>
> Bedeutet das ein Bit bei URSEL gesetzt wird und die Zahl
> 3(Dezimalsystem)= 11 im Binärsystem um 0 Stellen (also um UCSZ0(da
> erstes Bit)) verschoben wird. Somit ergibt sich eine Framerate von
> 8-Bits(steht in der Tabelle im Datenblatt). Beide Werte werden danach
> per "oder" verknüpft und in das UCSRC-Register geschrieben.
>
> Die Funktion von (1<<URSEL) verstehe ich jedoch nicht...

Atmel hat Register-Adressen gespart.
UBRRH und UCSRC sind vom Programm aus an der selben Stelle im Speicher. 
WEnn das Programm also an diese Stelle in den Speicher schreibt, muss es 
eine Möglichkeit geben, wie man angeben kann "Ich meine jetzt das UBRRH 
Register" bzw. "Ich meine jetzt das UCSRC Register".
Genau das macht das URSEL Bit.

von innerand i. (innerand)


Lesenswert?

Christian Karle schrieb:

> Ich weis dass, das UBRR-Register aus 12-Bits besteht,
> unterteilt in:
> UBRRL (enthält die 8 unteren Bits)
> UBRRH (enthält die 4 oberen Bits)

Grundsätzlich sind alle Register dieses µCs 8 Bit breit.
Wenn man mal mehr als 8 Bit braucht, dann werden diese aus mehreren 
Registern zusammengesetzt.
Das 12 Bit breite UBRR-Register gibt es also "in Hardware" nicht, dieses 
wird aus 2 Registern, eben UBRRL und UBRRH zusammengesetzt.
Grundsätzlich simmt das mit den oberen und untern Bits aber.

In c kann man (teilweise) auch direkt 12 (16) Bits auf UBRR setzen, da 
kümmert sich dann der Kompiler um die Aufteilung auf UBRRL und UBRRH 
(nur falls dir das mal irgendwo unterkommt).

> Im Quellcode steht nun:
>
> UBRRL  = 1;  -> Bedeutet das bei UBRR1 ein Bit gesetzt wird ?
> UBRRH  = 0;  -> Bedeutet dass, das gesamte Register 0 ist?
>
> Somit würde das Register im Binärsystem so aussehen : 000000000010 =
> 2(in Dezimal)

> Oder mache ich einen Denkfehler?

Einen kleinen. Die 1 ist Dezimal, also 0000 0001 binär.
In UBBRH + UBRRL steht somit 0000 0000 0000 0001.

von Christian K. (christiankarle)


Lesenswert?

Ok, wenn ich das richtig verstanden habe heißt das so viel wie:
(1<<URSEL)
Wenn dieses Bit gesetzt ist kann ich in das UCSRC-Register schreiben.
Dies ist ja von mir erwünscht, da ich ja die Framerate einstellen 
möchte.
Wenn dieses Bit nicht gesetzt ist kann ich in das UBRR-Register 
schreiben?
Da ich ja schon das UBBR-Register beschrieben habe(da vorher das Bit 
nicht gesetzt war) und nun die Framerate einstellen möchte setzte ich 
zum weiter Programmieren(also zum Einstellen der Framerate) das Bit für 
URSEL.

Entschuldigung, das ich jetzt vielleicht "dumm" frage aber für Anfänger 
ist das Datenblatt doch eher schwer verständlich...

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Christian Karle schrieb:
> Ok, wenn ich das richtig verstanden habe heißt das so viel wie:
> (1<<URSEL)
> Wenn dieses Bit gesetzt ist kann ich in das UCSRC-Register schreiben.
> Dies ist ja von mir erwünscht, da ich ja die Framerate einstellen
> möchte.
> Wenn dieses Bit nicht gesetzt ist kann ich in das UBRR-Register
> schreiben?

Genau.
UBRRH und UCSRC sind aus Sicht des Programms dasselbe.

Du könntest genausogut schreiben
1
   UBRRH =  (1<<URSEL)|(3<<UCSZ0);

und würdest trotzdem ins UCSRC schreiben.
UBRRH und UCSRC sind im Speicher an derselben Stelle angeordnet. Quasi 2 
Variablen, die zwar verschieden heißen, aber eigentlich dasselbe sind, 
weil sie im Speicher an derselben Stelle liegen.
Nur durch die Angabe des Registernamens kann man die beiden (auf diesem 
µC-Typ) nicht unterscheiden.

: Bearbeitet durch User
von Christian K. (christiankarle)


Lesenswert?

In der nächsten Zeile wird nun UDR=0; gesetzt.
Im Datenblatt gibt es jedoch keine Tabelle oder Funktion für diesen 
Zustand...


Wird also durch den Befehl UDR=0; Binär einfach nur 00000000 in das 
Register geschrieben?

Und wenn ja, welche genaue Funktion besitzt dieses Register. Habe schon 
im Datenblatt nachgelesen, aber werde daraus nicht schlau...ich glaub 
mir fehlt an dieser Stelle Vorwissen...


Danach wird gleich noch UCSRA  = 0; gesetzt.
Im Datenblatt steht das beide Befehle, soweit ich das verstanden habe 
voneinander abhängig sind.

Ich verstehe aber nicht was hier genau passiert, bzw. zu was das gut 
ist.

von spess53 (Gast)


Lesenswert?

Hi

>In der nächsten Zeile wird nun UDR=0; gesetzt.
>Im Datenblatt gibt es jedoch keine Tabelle oder Funktion für diesen
>Zustand...

Ist ja auch Unsinn. UDR ist das Register in das du Daten schreibst die 
du Senden willst und aus dem du Daten liest die empfangen wurden. Das 
hat in der Initialisierung nichts verloren.

>Danach wird gleich noch UCSRA  = 0; gesetzt.

Genau solcher Blödsinn. Nach einem Reset (auch nach dem Einschalten) 
brauchst du das Register für dein Vorhaben nicht anfassen.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Christian Karle schrieb:
> In der nächsten Zeile wird nun UDR=0; gesetzt.
> Im Datenblatt gibt es jedoch keine Tabelle oder Funktion für diesen
> Zustand...
>
>
> Wird also durch den Befehl UDR=0; Binär einfach nur 00000000 in das
> Register geschrieben?

Zuweisung ist Zuweisung.
Wird an UDR 0 zugewiesen, wird binär 0b00000000 ins Register 
geschrieben.

> Und wenn ja, welche genaue Funktion besitzt dieses Register.

Das ist in dem Fall (weil es eine Zuweisung ist) das Senderegister. 
Alles was du diesem Register zuweißt, wird rausgesendet. In diesem Fall 
eben ein Byte mit dem Wert 0

> Danach wird gleich noch UCSRA  = 0; gesetzt.

Was soviel bedeutet wie: alle gesetzten Bits in UCSRA werden gelöscht. 
Welche Bits sind in UCSRA? Alles was durch ein 1 Bit in UCSRA aktiviert 
worden wäre, wird damit wieder deaktiviert.

> Im Datenblatt steht das beide Befehle, soweit ich das verstanden habe
> voneinander abhängig sind.

Kann man so nicht sagen.
Ja und nein.
Beim Versenden könnten theoretisch Fehler auftreten, die durch 
entsprechende Bits in UCSRA angezeigt werden würden.

> Ich verstehe aber nicht was hier genau passiert, bzw. zu was das gut
> ist.

Er schickt ein 0-Byte raus und setzt dann die UART wieder zurück.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Er schickt ein 0-Byte raus und setzt dann die UART wieder zurück.

Nö.
Moment mal.
Er schickt kein 0 Byte raus.
Denn der Transmitter ist zu diesem Zeitpunkt nicht eingeschaltet.

Daher: Panikzuweisung um auf Nummer sicher zu gehen, dass das Register 
auch wirklich 0 ist. Reichlich sinnlos.

von Christian K. (christiankarle)


Lesenswert?

Ok, also das kann ich dann weglassen :) Hab mich auch schon gewundert 
warum das gelöscht werden soll... wahrscheinlich eh nur zur Sicherheit 
oder so...

Dann noch zu letzten Zeile:

UCSRB  = (1<<RXCIE)|(1<<RXEN);

Bedeutet das Interrupts erlaubt werden falls ein Bit am USART ankommt 
indem das Bit RXCIE gesetzt wird. Das aktuelle Programm wird dann 
unterbrochen und der Controller springt in den Programmteil ISR. sei() 
muss global erlaubt sein und die Header-Datei <avr/interrupt.h> muss 
eingebunden sein. Zum Schluss wird der USART dann noch als Empfänger 
eingestellt indem das Bit RXEN gesetzt wird. Beide werden per "oder" 
verknüpft und in das Register geschrieben.

Ist das Alles so richtig ?

von Karl H. (kbuchegg)


Lesenswert?

Christian Karle schrieb:

> Ist das Alles so richtig ?

korrekt.

von Christian K. (christiankarle)


Lesenswert?

Vielen, vielen Dank für die guten Erklärungen und die schnelle Hilfe :)
Mein Problem wäre damit gelöst :) -> Danke :)

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.