Forum: Mikrocontroller und Digitale Elektronik UART sendet falsche Daten


von Jens K. (mister232)


Lesenswert?

Hallo Leute,
zunächst einmal: Ich bin gerade ganz neu in diesem Forum, also verzeiht 
es mir bitte, wenn mein erster Post nicht perfekt und evtl. etwas 
unvollständig ist. Ich hoffe wircklich das ihr mir weiter helfen könnt, 
denn ich habe schon sehr viel gutes von diesem Forum gehört und auch das 
AVR-GCC-Tutorial dieser Seite hat mir schon oft geholfen :-)

Ich habe folgendes Problem:
Ich versuch gerade das erste Mal mit einem Mikrocontroller (ATtiny2313) 
und einem Computer (HTerm) seriell zu kommunizieren. Ich benutze AVR 
Studio 6 und habe folgendes Programm in den µC geladen (hier nur die 
Datei in der mit dem UART gearbeitet wird, in der main werden diese 
Funktionen nur aufgerufen):
1
/*
2
 * uart_control.c
3
 *
4
 * Created: 03.09.2012 15:23:59
5
 *  Author: Jens
6
 */ 
7
8
#include <avr/io.h>
9
#include "uart.h"
10
11
#define BAUD 9600
12
#define F_CPU 8000000UL
13
14
#include <util/setbaud.h>
15
16
void uart_init(void)
17
{
18
  //Baudrate festlegen
19
  UBRRH = UBRRH_VALUE;
20
  UBRRL = UBRRL_VALUE;
21
  
22
  UCSRB |= (1<<TXEN); //Senden aktivieren
23
  UCSRC = (3<<UCSZ0); //RS232-Frame festlegen, 8 Datenbits, 1 Stoppbit
24
}
25
26
void uart_send()
27
{
28
  while(!(UCSRA & (1<<UDRE))){} // Warten bis Senden möglich
29
    
30
  UDR = '3';  // Zeichen senden
31
}

Am PC nutze ich, wie oben schon erwähnt HTerm. Am µC habe ich einen 
externen 8MHz Quarz angeschlossen, welcher laut Oszilloskop auch richtig 
arbeitet. Die Fuse-Bits für diesen Quarz sind gesetzt und das CKDIV8-Bit 
ist nicht gesetzt.
Bei HTerm empfange ich jedoch nur Datenmüll. Ich habe auch schon ein 
anderes Terminalprogramm namens Termite ausprobiert, mit demselben 
Ergebnis.
Wenn ich allerdings bei Termite des Öfteren Disconnecte und dann wieder 
Connecte kommt manchmal das richtige an.
Ich hoffe ihr hab nun alle Infos die ihr braucht, um mir evtl. zu 
helfen, sitze nämlich nun schon seit 2 Tagen daran und würde nun gerne 
mit dem Projekt fortfahren, dies sollten ja eigentlich nur 
Vorbereitungen werden :-)

von amateur (Gast)


Lesenswert?

Ich habe die Initialisierungssequenzen für den -2313 nicht im Kopf, aber 
ich habe die Erfahrung gemacht dass, wenn Datenmüll ankommt, was 
verschickt wird. Da Du ein Oszi. hast, schau Dir mal die 
Übertragungsrate am Ausgang an. Möglicherweise ist die Baudrate daneben.

von Jens K. (mister232)


Lesenswert?

Okay, ich werde mich morgen Abend mal dran setzen und poste dann wie die 
Übertragungsrate ist.

von amateur (Gast)


Lesenswert?

P.S. Ich habe mal vor ein paar Jahren Probleme mit der seriellen 
Datenübertragung, allerdings bei einem ATMega, gehabt. Die konnte ich 
nur lösen indem ich mit 2 Stoppbits gearbeitet habe. Keine Ahnung warum. 
Ist wohl irgendwie aus dem (Übertragungs-)Rahmen gefallen.

von Carsten R. (kaffeetante)


Lesenswert?

Wenn das alles ist was Du sendest könnte die Ursache hier liegen

http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART

"Wenn man das nachfolgende Programm laufen lässt und Hyperterminal 
startet, scheint es problemlos zu funktionieren. Wenn man aber das RS232 
Kabel zwischenzeitlich abzieht und wieder ansteckt wird es oft 
passieren, dass nur noch wirre Zeichen auf dem PC erscheinen. Das liegt 
daran, dass der PC aus einem ununterbrochen Zeichenstrom nicht den 
Anfang eines Zeichens erkennen kann. Darum muss in solchen Fällen 
periodisch eine kleine Pause von der Länge mindestens eines Zeichens 
eingelegt werden, damit der PC sich wieder synchronisieren kann. "

Füge mal eine Pause in den gesendeten Datenstrom aus lauter Dreien ein 
damit der Empfänger eine Chance hat ein Anfang solide zu erkennen. 
Ansonsten ist es Glückssache, daß die Verbindung synchron mit dem Begin 
eines Zeichens zum passenden Zeitpunkt hergestellt wird, was zu deiner 
Beschreibung passen würde.

Gruß

Carsten

von Jens K. (mister232)


Lesenswert?

Okay, danke für die schnellen Antworten. Ich werde morgen Abend maleine 
Pause einbauen und das Ergebnis hier posten.

von amateur (Gast)


Lesenswert?

@Jens
Wenn Du dich das nächste Mal meldest, spendier uns doch mal die 
konkreten Werte von: UBRRH_VALUE und UBRRL_VALUE.

von Jens K. (mister232)


Lesenswert?

Yeah!!!! Endlich funktioniert es. Ich habe einfach eine Pause mit 
_delay_ms() von 500ms eingebaut und schon funktioniert alles 
einwandfrei.n Ich danke euch für die schnellen und guten Ratschläge!

@amateur(Gast)
soweit ich weiß, berechnet doch der Compiler UBRRH_VALUE und UBRRL_VALUE 
mit genau dieser Anweisung?

von Michael (Gast)


Lesenswert?

Jens Kathe schrieb:
> Endlich funktioniert es. Ich habe einfach eine Pause mit
> _delay_ms() von 500ms eingebaut und schon funktioniert alles
> einwandfrei.

Du brauchst gar nicht eine Ewigkeit zu waren. Eine Millisekunde würde 
bei 9600 Bd völlig reichen.

von amateur (Gast)


Lesenswert?

@Jens: Wo genau hast Du die Pause eingebaut?

von Carsten R. (kaffeetante)


Lesenswert?

Stimmt, eine Millisekunde ist ausreichend. Kürzer sollte die Pause aber 
nicht sein. Die benötigte Pause richtet sich nach der Symbolrate, ist 
also konfigurationsabhängig.

Zum Beispiel hat ein Byte 8 Bit. Dazu kommen noch ein Start und ein 
Stopbit. Das macht insgesamt 10 Bit. Man kann aber auch 5,6,7 oder 9 Bit 
und zwei Stopbits, Parity etc. verwenden. Die Pause muß groß genug sein, 
daß ein ganzes Frame reinpaßt. Damit wäre dann gewährleistet, daß Sie 
zweifelsfrei als Idle und nicht durch angrenzende Pegelwechsel als 
Symbol erkannt wird.

Bei einem 10 Bit Frame wie hier und 9600 Baud sind es dann 10/9600=1/960 
Sekunden, also sehr knapp an einer Millisekunde. Ein Bit mehr im Frame 
und es Funktioniert nur noch in 99% aller Fälle, was das Ganze schwer 
reproduzierbar macht und dann die Fehlersuche erschwert. Große Frames 
bei 2400 Baud brauchen 5 Millisekunden.

500 Millisekunden sind großzügig, aber umgekehrt muß man auch nicht 
gerade auf Kante nähen solange es nicht erforderlich ist. Sonst erlebt 
man bloß durch kleine Frame oder Baudratenänderungen böse 
Überraschungen. Und wer hat dann schon solche Details im Hinterkopf? In 
zeitkritischen Anwendungen kann man dann noch immer tunen. Dann ist man 
wenigstens mit den Gedanken bei der Sache und man weiß dann, daß man 
bewußt auf Kante näht und findet das grenzwertige Verhalten schneller.

Lieber etwas größere Pausen, man braucht sie eh nur selten.

Gruß Carsten

@Amateur:

Wo man die Pausen hinsetzt hängt davon ab was man wie überträgt. Es geht 
eigentlich nur darum, daß unmittelbar bevor die interessanten Daten 
kommen ein ausreichend langes Idle vorangeht. Sendet man nur 
gelegentlich, braucht man das nicht, weil naturgemäß eine Pause 
vorangeht.

Sendet man kontinuierlich, ist dies eine simple von mehreren 
Möglichkeiten um eine Synchronisierung sicherzustellen. Dann kommt die 
Pause zu Beginn eines Datensatzes, selten auch zwischendurch wenn der 
Datensatz riesig ist oder die Verbindung nicht kontinuierlich besteht, 
bzw gestört ist. Dann braucht man aber auch noch andere Mechanismen.

von Michael H. (michael_h45)


Lesenswert?

Carsten R. schrieb:
> ...
so ein blödsinn!
man wartet, bis das vorherige byte draußen ist und schickt dann das 
nächste hinterher.
irgendwelches geschätztes, gerundetes, aufgemöbeltes und dann wieder 
vergessenes gewarte ist einfach nur mist!
lern einem anfänger nicht solches gestümpe.

die avrs haben extra ein status register mit einem flag für genau diesen 
zweck.
wenn diese zeile hier stimmt, ist es genau die warte-methode, die man 
anwendet.
>  while(!(UCSRA & (1<<UDRE))){} // Warten bis Senden möglich

von Stefan E. (sternst)


Lesenswert?

Michael H. schrieb:
> so ein blödsinn!
> man wartet, bis das vorherige byte draußen ist und schickt dann das
> nächste hinterher.
> irgendwelches geschätztes, gerundetes, aufgemöbeltes und dann wieder
> vergessenes gewarte ist einfach nur mist!
> lern einem anfänger nicht solches gestümpe.

Darum geht es doch bei diesem Warten überhaupt nicht. Es geht darum, für 
einen Empfänger, der während einer laufenden Übertragung aufgeschaltet 
wird, eine Pause im Datenstrom zu erzeugen, die lang genug ist, dass er 
sicher auf das nächste Startbit synchronisiert. Eine solche Pause sollte 
immer mal wieder eingestreut werden, am Besten zum Beispiel zwischen 
einzelnen Datenpaketen.

von Michael H. (michael_h45)


Lesenswert?

das teil hängt an einem pc... und nicht an einem rechenschieber.
und das eröffnungsposting lässt auch nicht im geringsten auf einen 
solchen fehler schließen.

von Stefan E. (sternst)


Lesenswert?

Michael H. schrieb:
> das teil hängt an einem pc...

Ach, und bei dem kann man nicht ein serielles Kabel im laufenden Betrieb 
ab- und anstöpseln?

Michael H. schrieb:
> und das eröffnungsposting lässt auch nicht im geringsten auf einen
> solchen fehler schließen.

Erstens gibt es im Thread ja auch noch mehr Postings, und zweitens ist 
das nun mal genau die Situation, auf die sich Carstens Beschreibungen 
bezogen haben. Dein "so ein blödsinn!" war somit unangebracht, und deine 
Kritik ging am eigentlichen Thema des Postings, auf das du dich bezogen 
hast, komplett vorbei.

von Michael H. (michael_h45)


Lesenswert?

Stefan Ernst schrieb:
> das nun mal genau die Situation, auf die sich Carstens Beschreibungen
> bezogen haben.
nö.
denn wenn es so wäre, würde zufälliges an- und abstöpseln bei 3of5 
decision nicht mal zu .5% der zeit funktionieren.
das ist schon ziemlich bescheidener zufall.

der fehler ist und bleibt woanders.
zusammenhangsloses rumgewarte kaschiert den fehler, behebt ihn aber 
nicht. der tipp an einen anfänger ist und bleibt käse.

von amateur (Gast)


Lesenswert?

Meine Frage nach dem "wo" die Pause eingefügt wurde zielte auf folgende 
Problematik:

>while(!(UCSRA & (1<<UDRE))){} // Warten bis Senden möglich

... bedeutet ja "die Bahn ist frei". - Zumindest auf Atmel-Seite.

Der Empfänger ein PC, schon seit Jahren im Gigaherzbereich laufend, 
sollte doch eigentlich mit Verzögerungen, die sich aus Übertragungen im 
9600-Baud-Bereich ergeben 0,0 Probleme haben.

Ja, wenn wir hier über unangekündigte Pakete im 100 MHz-Bereich reden 
würden, würde ich die Problematik einsehen.

von Michael H. (michael_h45)


Lesenswert?

amateur schrieb:
> Der Empfänger ein PC, schon seit Jahren im Gigaherzbereich laufend,
> sollte doch eigentlich mit Verzögerungen, die sich aus Übertragungen im
> 9600-Baud-Bereich ergeben 0,0 Probleme haben.
>
> Ja, wenn wir hier über unangekündigte Pakete im 100 MHz-Bereich reden
> würden, würde ich die Problematik einsehen.

falsch... denn der pc weiß nicht, an welcher stelle im rahmen er 
angesteckt wurde. in einer kontinuierlichen symbolkette kann er das 
start-bit nicht von einem anderen symbol unterscheiden.


aber das ist hier nicht der fehler.

von Stefan E. (sternst)


Lesenswert?

Michael H. schrieb:
> nö.
> denn wenn es so wäre, würde zufälliges an- und abstöpseln bei 3of5
> decision nicht mal zu .5% der zeit funktionieren.
> das ist schon ziemlich bescheidener zufall.

Zufälliges ab- und anstöpseln funktioniert nur deshalb fast immer, weil 
ein "normaler" Datenstrom eben genau solche Pausen enthält. Entweder 
weil absichtlich eingefügt, oder weil wegen des Protokolls eh vorhanden.

Außerdem geht es nicht nur um ab- und anstöpseln.
Ein anderes Szenario ist:
Wenn kein externer Pull-Up verwendet wird, ist die Sendeleitung bis zur 
UART-Initialisierung hochohmig. Hier kann durchaus vom Empfänger eine 
fallende Flanke gesehen werden, und er fängt an ein Byte zu empfangen. 
Und mitten in diesem "Fake-Byte" fängt nun der Sender an, einen 
kontinuierlichen Datenstrom zu senden. Auch dann ist der Empfänger nicht 
synchron.

von Michael H. (michael_h45)


Lesenswert?

Stefan Ernst schrieb:
> Außerdem geht es nicht nur um ab- und anstöpseln.
> Ein anderes Szenario ist:
> Wenn kein externer Pull-Up verwendet wird, ist die Sendeleitung bis zur
> UART-Initialisierung hochohmig. Hier kann durchaus vom Empfänger eine
> fallende Flanke gesehen werden, und er fängt an ein Byte zu empfangen.
> Und mitten in diesem "Fake-Byte" fängt nun der Sender an, einen
> kontinuierlichen Datenstrom zu senden. Auch dann ist der Empfänger nicht
> synchron.
Genau - zum Beispiel.
Würdest du in einer anständigen Lösung jetzt irgendwie warten, oder 
würdest du dich um einen Power-On-Zustand kümmern?

von Carsten R. (kaffeetante)


Lesenswert?

@Michael H.

"das teil hängt an einem pc... und nicht an einem rechenschieber.
und das eröffnungsposting lässt auch nicht im geringsten auf einen
solchen fehler schließen."

Das Problem war als genau dieses aus der Beschreibung erkennbar und es 
wurde mit der beschriebenen Methode erfolgreich sofort behoben. Es 
stimmt zwar daß für gewöhnlich ausreichende Sendepausen vorangehen, für 
gewöhnlich. Ich habe selbst darauf hingewiesen daß dies bei 
unterbrochenem Senden der Fall ist, nicht aber bei kontinuierlichen 
Übertragungen. In diesem Szenario war das also nicht der Fall. Und 
manchmal reicht "für gewöhnlich" nicht und man geht auf nummer Sicher.

Es ist kein Gestümpe einem Protokoll ein definiertes IDLE 
voranzustellen. Wenn Du es dennoch für Gestümpe hältst, dann nenne doch 
bitte eine bessere und eifachere Alternative um ein Sicheres Idle direkt 
vor dem Datenpaket zu gewährleisten. Eine Data Register Empty Prüfung 
reicht nicht.

Michael H.schrieb
>nö.
>denn wenn es so wäre, würde zufälliges an- und abstöpseln bei 3of5
>decision nicht mal zu .5% der zeit funktionieren.
>das ist schon ziemlich bescheidener zufall.

Das ist ein Trugschluß. Eben wegen der erwähnten üblichen Pausen erfolgt 
das Einstöpseln sehr oft in einer Idle Phase. Das geht in der Regel gut 
solange man nicht gerade ein Masseproblem etc. hat. Kritisch ist das 
Verbinden während einer laufenden Übertragung. Da ist dann nicht nur das 
aktuelle Symbol Schrott (völlig logisch), sondern der Uart weiß nie wo 
das nächste Symbol beginnt und das alte Endet. Das ergibt dann nur noch 
Mist bis zur nächsten Sendepause. Dann geht es wieder.

Wie schnell der Gigamegasuperduper-PC ist ist völlig egal, denn der 
steht am Ende der Verbindung. Dann kommt der Tranciever, die Leitung, 
der andere Usart und dann der Mikrocontroller. Die U(S)arts laufen 
autark und interessieren sich nur dafür, ob die Register voll oder leer 
sind etc. Die übertragung erledigen sie eigenverantwortlich. Wenn man 
Salat empfängt wurde entweder zu Begin nur Unfug versendet oder der 
Fehler liegt in oder zwischen den U(S)arts. Der PC wird damit selten 
überfordert.

Ach ja, es müssen nicht unbedingt Störungen oder Steckvorgänge sein. Es 
kann auch sein daß der Empfänger auf der anderen Seite erst während des 
laufenden Sendevorgangs durch die Software aktiviert wurde. Es gibt 
viele möglichkeiten die schief laufen. Funktionieren tut es nur wenn 
alles richtig läuft und nicht nur zu 99% richtig.

Ein Sleep mode kann da auch mal was durcheinanderbringen, denn bei den 
tieferen Modes werden die Taktsignale für die Peripherie abgeschaltet. 
Wer jetzt denkt, er weckt seinen Zielcontroller mit einem INT0 und 
schickt dann gleich die Sendung vom Uart ab kann Spaß haben wenn die 
Daten ankommen bevor der Watchdog das Einschwingen der Taktquelle 
abgezählt hat und das Dornröschen an die Arbeit läßt. Dann hat man 
wieder nur Grütze bis zu nächsten Sendepause. Und dann geht es plötzlich 
wieder.

Komisch. Sporadische aussetzer. Hm, wackel mal am Kabel.

viele Grüße und gute Nacht

Carsten

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.