Forum: Compiler & IDEs UART teilweise nicht komplett übertragen


von Ulf (Gast)


Lesenswert?

Hi Leute, ich benutze einen UART, das Daten senden an den PC geht auch 
super, aber es kommt nach dem Resetten des µC sehr leicht zu massivsten 
Fehlern.

Ich habe die Funktionen:

1
void uart_init(void)
2
{
3
  // Baudrate setzen
4
  UBRR0H = 0x00;  //0000 0000
5
  UBRR0L = 0x0C;  // Wert 23 ^= 9600 bei 3,686 MHz
6
7
  // Empfänger und Sender aktivieren
8
  UCSR0A = 0x00;   //0000 0000
9
  UCSR0B = 0x18;  //0001 1000  
10
11
  /* Einstellungen: Asynchron, 8-Bit, keine Parität, 1 Stop bit */
12
  UCSR0C = 0x06;   //0000 0110
13
}
14
15
void uart_putc( char c )
16
{
17
  // Warte bis die Sendeeinheit bereit ist
18
  while( !(UCSR0A & ( 1<<UDRIE0) ) );
19
20
  UDR0 = c;
21
}
22
23
void uart_puts( const char* str )
24
{
25
  while( *str ) 
26
  {
27
    uart_putc( *str );
28
    str++;
29
  }
30
}
 verwendet, die eigentlich genau sowas verhindern sollte. Leider schafft 
sies nicht immer, erst, wenn ich einen delay von 1ms reinsetze, klappt 
es immer. Was für Statusbits muss ich denn noch setzen, damit das Teil 
definitiv richtig sendet.

Ich habe einen mega644p, der mit dem internen Quarz von 8Mhz betrieben 
wird. Auslesen tu ich mit Putty.

lg Ulf

von ... (Gast)


Lesenswert?

Ulf schrieb:
> wenn ich einen delay von 1ms reinsetze

Wo setzt Du das denn rein?

Ulf schrieb:
> mega644p, der mit dem internen Quarz von 8Mhz

Einen internen Quartz gibt es bei AVRs nicht!

Vermutlich meinst Du den internen RC-Oszillator. Der ist allerdings für 
die Benutzung der UART eher ungeeingnet, da viel zu ungenau. 
Wahrscheinlich stimmt also Deine Baudrate nicht. Die Gegenseite kann 
dann die einzelnen Zeichen nicht mehr voneinander trennen und Du erhälst 
nur Müll. Durch die Pausen klappt dann die Synchronisation zufällig 
wieder, allerdings nur solange die Temperatur halbwegs konstant ist.

Du hast 2 Möglichkeiten, etweder Du benutzt einen Quartz (vorzugsweise 
einen Baudratenquartz) oder Du kalibrierst Deinen internen RC-Oszillator 
(und das regelmäßig)

PS:
Das hier: "// Wert 23 ^= 9600 bei 3,686 MHz" passt auch nicht gerade zu 
dem hier: "8Mhz".

von Ulf (Gast)


Lesenswert?

jup, ich meine den RC Oszillator

Die 23 stimmen ja auch nicht, es steht ja 0x0C dahinter und das sollten 
bei 8 Mhz eine Baudrate von 38400 ergeben, die ich auch immer im Putty 
eingestellt hatte.

Das Delay:

void uart_putc( char c )
{
  // Warte bis die Sendeeinheit bereit ist
  while( !(UCSR0A & ( 1<<UDRIE0) ) );
_delay(1);

  UDR0 = c;
}

Die ungenauigkeiten hatte ich auch schon im Verdacht, die Funktion 
uart_init() wird einmal vom main aufgerufen, der Rest läuft dann per 
Interrupt oder in der while schleife im main ab

lg Ulf

von Karl H. (kbuchegg)


Lesenswert?

Ulf schrieb:

> aber es kommt nach dem Resetten des µC sehr leicht zu massivsten
> Fehlern.
...
> verwendet, die eigentlich genau sowas verhindern sollte. Leider
> schafft sies nicht immer, erst, wenn ich einen delay von 1ms reinsetze,
> klappt es immer. Was für Statusbits muss ich denn noch setzen, damit das
> Teil definitiv richtig sendet.


Das könnte auch ein ganz anderes Problem sein (abgesehen davon, dass 
interner Takt versus Quarz sowieso immer verliert):

Das Problem ist in der Methodeik der seriellen Übertragung selber zu 
finden. Der Empfänger kann nicht zweifelsfrei feststellen, wenn denn nun 
eigentlich exakt ein neues Zeichen anfängt. Er macht dies indem er aus 
der Ruhelage heraus die erste Pegeländerung als Beginn des Zeichens 
wertet. Ab dieser Flanke ist alles weitere zeitgesteuert. Nachdem ein 
Zeichen komplett übertragen wurde, kehrt alles wieder in die Ruhelage 
zurück und die nächste Flanke triggert den Beginn des nächsten Zeichens.

Soweit so gut.

Wenn du jetzt aber den µC mitten in der Übertragung eines Zeichens 
resettest, dann passiert es, dass zwar der µC schon längst aufgehört hat 
zu senden, der Empfänger aber noch die Bitzeiten für einzelne Bits 
abwarten will, weil ja für ihn das Zeichen noch nicht komplett empfangen 
wurde.
Und jetzt entsteht das Problem. Beginnt dein µC wieder frisch mit seiner 
Arbeit und fängt sofort wieder zu senden an, dann wertet der Empfänger 
die Pegeländerungen (die vom µC aus eigentlich als der Beginn eines 
neuen Zeichens gedacht waren) als noch zum vorhergehenden Zeichen 
gehörig. Und ab dort kommt dann alles durcheinander.

Es ist ein bischen so, wie wenn du beim Zappen im Fernseher nicht 
mitbekommst, dass in der Zwischenzeit der Sender gewechselt wurde. Das 
sagt dann Humphry Bogart plötzlich: "Ich seh dir in die .. Windel mit 
Nässeschutz". Nur dass es bei der UART dann eben um die Bitebene geht.

In dem Moment, wo du als Sender auf der UART eine kleine Pause einlegst, 
ermöglichst du dem Empfänger, dass er sich wieder einwandfrei auf deine 
Byteanfänge synchronisieren kann. Und genau das hat du mit deinem 1ms 
delay gemacht.

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.