UART sendet nur 0x00 und 0xC0

Gast #363063
Lesenswert?

Ich steh gerade mal im Wald
[C]
#include <avr/io.h>
#include <avr/delay.h>

#define SYSCLK    1048576  //intern 1Mhz = 2^20
#define BAUD    9200
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)

/* USART initialisieren */
void uart_init(void);


int main(void)
{
  unsigned char buffer;
  DDRD |= (1 << DDD7);    //Ausgang
  PORTD |= (1 << PD7);    //High

  /* USART initialisieren */
  uart_init();

  while (1)
  {
    /* Warten bis Daten empfangen wurden */
    while ( !(UCSRA & (1<<RXC)) );

    PORTD &= ~(1 << PD7);
    _delay_ms(300);

    /* Empfangsregister auslesen */
    buffer = UDR;

    /* Warten bis der Sendepuffer frei ist */
    while ( !( UCSRA & (1<<UDRE)) );

    PORTD |= (1 << PD7);

    /* Daten in den Puffer schreiben und damit senden */

    UDR = buffer;
   }
}

/* USART initialisieren */
void uart_init(void)
{
  /* Baudrate einstellen ( Normaler Modus ) */
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
  UBRRL = (unsigned char) UBRR_BAUD;

  /* Aktivieren von receiver und transmitter */
  UCSRB = (1<<RXEN)|(1<<TXEN);

  // 8 Datenbits, 1 Stoppbit
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

[\C]

Wenn ich über Bray-Terminal was sende, leuchtet eine LED und das
Empfangene wird wieder zurück gesendet.
Nur ... die LED leuchtet brav so wie es sein soll.
Aber das Empfangene im Terminal ist 0x00 und darauf folgend 0xC0, egal
was ich sende. Auch wenn ich einen String sende.
Was ist falsch ??
Persönliche Seite #363067
Lesenswert?

Ich dachte erst,
> #define SYSCLK    1048576  //intern 1Mhz = 2^20
> #define BAUD    9200
> #define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)

könnte zufällig den richtigen Wert liefern, aber:

1048576/(9200*16)=7,
Gegenprobe: 1000000/(7*16)=8928 und das ist daneben genug...

Falk
P.S.: RS232 ist alles andere als trivial. Wenn man alle Möglichkeiten
berücksichtigt, einen Fehler zu machen, kommt man auf eine Erfolgsquote
von ca. 2^10:1 ;-)
Gast #363068
Lesenswert?

Danke. Ich habs jetzt abgeändert. Funktioniert auch. Aber eine kleine
Frage hab ich noch.
Ich habe stehen:
1
// 8 Datenbits, 2 Stoppbit
2
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
Nach dem AVR-GCC Tutorial und einigen Beispielen im WWW müsste das
Terminal-Programm auch auf 8Daten, 2Stopp eingestellt werden.
Stelle ich es auf 8Daten,2Stopp kommen alle Ziffern zurück. Buchstaben
jedoch werden verfälscht.
Binär für ein 'a' kommt an: 11100001b
Stelle ich es auf 7Daten,2Stopp kommt alles richtig zurück.
Jetzt kommt für 'a': 01100001b
(?? 8te bit nicht gesendet ??)
Warum??
Gast #363069
Lesenswert?

"Stelle ich es auf 8Daten,2Stopp kommen alle Ziffern zurück.
Buchstaben
jedoch werden verfälscht."


Das liegt daran:

#define SYSCLK    1048576  //intern 1Mhz = 2^20

Genauer an dem Wörtchen "intern"

Mehr sag ich dazu nicht, zweimal die Woche reicht mir, hab ja schon
Fusseln am Mund.


Peter
Persönliche Seite #363070
Lesenswert?

Homer:
> "Stelle ich es auf 8Daten,2Stopp kommen alle Ziffern zurück.
> Buchstaben jedoch werden verfälscht."

Peter:
> Das liegt daran:
> #define SYSCLK    1048576  //intern 1Mhz = 2^20
> Genauer an dem Wörtchen "intern"

Er hat ja "etwas" abgeändert.

Die wahrscheinlichsten Fehler:
1) 9600Bd mit ca. 1MHz ergibt einen Fehler >7% (Wenn U2X==0)
2) 9200 != 9600, 2^20 != 10^6
3) Der RC-Oszillator ist für sowas nicht gut geeignet.

Wenn 1) und 2) korrigiert sind, könnte es trotz 3) sogar oft
funktionieren.

> Mehr sag ich dazu nicht, zweimal die Woche reicht mir, hab ja
> schon Fusseln am Mund.

Deswegen tippe ich mit den Fingern, das gibt zwar Hornhaut, aber die
Tasten bleiben trocken ;-)

Falk
Gast #363071
Lesenswert?

1
#include <avr/io.h>
2

3
#define F_CPU    1000000ul
4
#define BAUD    9600
5
#define UBRR_BAUD ((F_CPU/(16l*BAUD))-1)
6

7
/* USART initialisieren */
8
void uart_init(void);
9
void uart_send(unsigned char buffer);
10
unsigned char uart_receive(void);
11

12
int main(void)
13
{
14
  unsigned char buffer;
15
  //DDRD |= (1 << DDD7)|(1 << DDD6);    //Ausgang
16
  //PORTD |= (1 << PD7)|(1 << PD6);    //High
17

18
  /* USART initialisieren */
19
  uart_init();
20
    
21
  while (1)
22
  {
23
  /*  
24
    // Warten bis Daten empfangen wurden
25

26
    PORTD &= ~(1 << PD7);
27
    while ( !(UCSRA & (1<<RXC)) );
28
    
29
    // Empfangsregister auslesen
30
    PORTD |= (1 << PD7);
31
    buffer = UDR;
32

33
    // Warten bis der Sendepuffer frei ist
34
      PORTD &= ~(1 << PD6);
35
    while ( !( UCSRA & (1<<UDRE)) );
36

37
    PORTD |= (1 << PD7)|(1 << PD6);
38

39
    // Daten in den Puffer schreiben und damit senden
40
    
41
    UDR = (buffer);
42
  */  
43
  buffer = uart_receive();
44
  uart_send(buffer);  
45
  
46
   }
47
}
48

49
/* USART initialisieren */
50
void uart_init(void)
51
{
52
  /* Baudrate einstellen ( Normaler Modus ) */
53
  UBRRH = (unsigned char) (UBRR_BAUD>>8);
54
  UBRRL = (unsigned char) UBRR_BAUD;
55

56
  /* Aktivieren von receiver und transmitter */
57
  UCSRB = (1<<RXEN)|(1<<TXEN);
58

59
  // 8 Datenbits, 2 Stoppbit
60
  UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
61
}
62
void uart_send(unsigned char buffer)
63
{
64
    // Warten bis Daten empfangen wurden
65
    while ( !(UCSRA & (1<<RXC)) );
66
    
67
    /* Warten bis der Sendepuffer frei ist */
68
    while ( !( UCSRA & (1<<UDRE)) );
69

70
    /* Daten in den Puffer schreiben und damit senden */
71
    UDR = (buffer);
72
    while ( !( UCSRA & (1<<UDRE)) );
73
}
74

75
unsigned char uart_receive(void)
76
{
77
    // Warten bis Daten empfangen wurden
78
    while ( !(UCSRA & (1<<RXC)) );
79

80
    // Empfangsregister auslesen
81
//    buffer = UDR;
82
    
83
    // Wert zurückgeben
84
    return UDR;
85
}
Ich habs jetzt abgeändert. Funktioniert bei 7Datenbits. Danke also
schon mal.
7Datenbits
01100010    'a'
8Datenbits
11100001    'a'
(?? 8te Bit nicht gesendet ??)
Persönliche Seite #363072
Lesenswert?

> #define F_CPU    1000000ul
> #define BAUD    9600
> #define UBRR_BAUD ((F_CPU/(16l*BAUD))-1)

Rechnen wir mal:
1.000.000/(16*9600)=6,51041 --> UBRRL=6, UBRRH=0

>  UBRRH = (unsigned char) (UBRR_BAUD>>8);
>  UBRRL = (unsigned char) UBRR_BAUD;

Und damit stellst Du
1.000.000/(6*16)=10416,66666 --> 10416 Baud ein.

Schreibe mal
UCSRA |= (1 << U2X);
UBRR = 12;         //Statt UBRRL=... und UBRRH=...
in die Initialisierung.

Warum das dann klappt, steht in
http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf
genau erklärt.

Falk

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