UART in C - Problem

Gast #3608990
Lesenswert?

Hallo. :)

einfache Frage, folgender CODE:
1
/*
2
 * UART_Test.c
3
 *
4
 * Created: 08.04.2014 14:17:40
5
 *  Author: Freddy
6
 */
7
#define F_CPU 16000000
8

9
#include <avr/io.h>
10
#include <stdlib.h>
11
#include <util/delay.h>
12

13

14

15
int main(void)
16
{
17
  init_uart();
18
    while(1)
19
    {
20
    send_uart();
21
    _delay_ms(1000);
22
    }
23
}
24

25
void init_uart(){
26
  
27
  //setze BAUD-Wert
28
  UBRRL =  103;  //9600
29
  
30
  //Frame Format konfigurieren: 8n1
31
  //Tx und Rx aktivieren
32
  UCSRB = (1<<RXEN) | (1<<TXEN);
33
  UCSRC = (1<<UCSZ1) | (1<<UCSZ0) | (0<<UMSEL);
34
}
35

36
void send_uart(){
37
  
38
  while (!(UCSRA & (1<<UDRE)))
39
  {
40
  }
41
  UDR = 'x';
42
}

Wenn ich mein PC dran hänge, dann kommt im 1s - Takt zweimal eine Null.. 
Warum? Das sollte doch alles passen oder?

Hab die RegisterKonfiguration aus dem Datenblatt.

Danke! Viele Grüße!
Gast #3609231
Lesenswert?

Ja tut mir leid, das habe ich vergessen.

Ist ein Atmega8 :)

Das URSEL ist standart mäßig 1 und das UMSEL 0... beide werte stimmen 
mit dem was ich konfigurieren möchte überein.

Ich möchte eine 8n1 bei 9600 b/s einrichten :)


Wegen der Frequenz, auf das Herz genau vlt nicht, aber mit dem Oszi 
gemessen lieg ich 50Hz daneben..

Grüße!
#3609416
Lesenswert?

Freddy schrieb:
> Thomas Eckmann schrieb:
>> Ja. Aber da die UCSZ-Werte ohnehin 1 sind, kannst du dir das Ganze auch
>> sparen.
>
> Okay, aber dann wär ja auch die Angabe der UMSEL und URSEL Werte
> überflüssig.. Die sind standardmäßig ja auch entsprechend gesetzt.

Darum geht es nicht. Vergiss das UMSEL. Das schaltet eine Funktion im 
UART und steht per Default auf Asynchron. Das ist das, was du brauchst.

Das URSEL-Bit schaltet aber keine Funktion im UART, sondern steuert den 
Zugriff auf UBRRH und UCSRC. Diese Register haben dieselbe(!) Adresse.
Wenn URSEL 1 ist, geht der Wert ins UCSRC, wenn es 0 ist, ins UBRRH. Per 
Default ist dieses Bit eins. Wenn man zuerst das UCSRC setzt, braucht 
man sich nicht darum kümmern. Man darf nur nicht das ganze Byte 
zuweisen.
> UCSRC = (1<<UCSZ1) | (1<<UCSZ0) | (0<<UMSEL) = 0x06;
Damit ist URSEL nämlich 0!

Es dürfen nur die Bits geändert werden:
1
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0;

oder
1
UCSRC = (1 << URSEL) | (1<<UCSZ1) | (1<<UCSZ0;

Sonst landet das Byte im UBRRH und setzt es in diesem Fall auf 6. Welche 
Baudrate du dann hast, kannst du selber ausrechnen. Die, die du haben 
haben willst auf jeden Fall nicht.

Nach einem Zugriff auf UBRRH, für das der Maximalwert 15 ist und kein 
normaler Mensch einzelne Bits setzt, wird das URSEL automatisch auf 0 
gesetzt.
1
UBRRH = 7;

Damit ist das Bit7, also URSEL, 0 und der Wert geht ins UBRRH.

Deswegen ist es grundsätzlich keine gute Idee, das URSEL beim Schreiben 
nicht explizit zu setzen.

mfg.
Gast #3609448
Lesenswert?

Ahh! Ich verstehe! Sehr eingängige und klare Erklärung! :)
Danke!

Das URSEL bit ist quasi eine Art Steuerbit das sozusagen eine Art 
Switch-Funktion hat zwischen den Registern!
Und da ich das "|=" nich hatte hat es logischerweise das URSEL immer 0 
gesetzt und dadurch den Wert 6 ins BAUD-Bestimmende Register UBRR 
geschrieben...

Macht echt total sinn!

Vielen Dank! :)
Ich probier das mal!

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