Forum: Mikrocontroller und Digitale Elektronik ATmega8A USART Übertragung Fehlerhaft


von Stefan H. (practical)


Angehängte Dateien:

Lesenswert?

Hallo an alle,

ich versuche mich gerade in die Programmierung eines Microcontrollers 
mit C. Dabei möchte ich zunächst den USART initalisieren und mir 
gesendete Zeichen am PC anzeigen lassen. Zum Programmieren und Flashen 
des Controllers verwende ich die Software AtmelStudio, zum auslesen des 
USART die Software hterm.

Der Microcontroller wird mit einem externen 12 Mhz Quarz betrieben, die 
Fusebits sind entsprechend gesetzt:
High:0xDF
Low 0x3F.

Mein Problem:
Die richtigen Zeichen werden gesendet und empfangen.
Allerdings scheint es so als ob Zeichen übersprungen werden.

In dem Angehangenen Programm soll schlicht "Hallo" in einer 
Endlosschleife ausgegeben werden.
hterm Empfängt aber folgendes:

loHal
HloHal
Hlo
aloHlo
aloHll
aloHll
aloHal
HloHal
Hlo
aloHlo
aloHll
aloHll
aloHal
HloHal
Hlo
aloHlo
aloHll


Vielleicht kann mir hier jemand auf die Sprünge helfen.

Gruß,
Practical

von Florian (Gast)


Lesenswert?

Hallo,

versuch mal nach jedem Senden des Strings eine Pause zu machen. Wenn 
Deine Baudrateneinstellungen passen, könnte es sein, das Dein µC den PC 
zuwirft und dieser nicht hinterherkommt.

Zweite Möglichkeit ist, das Dein Takt nicht genau genug ist.
Verwendest Du einen externen Quarz? Bei Kommunikation zwingend nötig!

Berechne mal Deine BER (Bit Error Rate) ev. ist Deine ausgewählte 
Baudrate zu ungenau. Teiler anpassen!

Gruß
Florian

von Stefan H. (practical)


Lesenswert?

Hi,

wenn ich zwischen dem Senden von jedem Zeichen eine Pause von 100ms 
mache dann funktioniert es.
In meinem Code frage ich das Register UCSRA ab um dort zu erfahren ob 
das Zeichen gesendet wurde, erst dann sende ich das nächste Zeichen.
Diese Lösung finde ich flexibler. Daher frage ich mich, warum die von 
mir verwendete Abfrage nicht den selben Effekt hat:
1
while( !( UCSRA & (1<<UDRE)) );

Ich verwende einen externen Quarz.

von Ingo (Gast)


Lesenswert?

Zeig mal deinen Code!

von Karl H. (kbuchegg)


Lesenswert?

Stefan Harney schrieb:

> In meinem Code frage ich das Register UCSRA ab um dort zu erfahren ob
> das Zeichen gesendet wurde, erst dann sende ich das nächste Zeichen.

Das ist auch ok so.

> Diese Lösung finde ich flexibler. Daher frage ich mich, warum die von
> mir verwendete Abfrage nicht den selben Effekt hat:

Mach die Pause mal nach DEM STRING als ganzes, nicht nach jedem Zeichen.

von Falk B. (falk)


Lesenswert?

@ Stefan Harney (practical)

>wenn ich zwischen dem Senden von jedem Zeichen eine Pause von 100ms
>mache dann funktioniert es.

Soviel braucht man gar nicht. Es reicht, EINMALIG am Anfang des Sendens 
eine kleine Pause zu machen, um dem Empfänger, hier dem PC, die 
Möglichkeit zur Synchronisation zu geben. Das Thema ist alt.

Siehe UART.

>In meinem Code frage ich das Register UCSRA ab um dort zu erfahren ob
>das Zeichen gesendet wurde, erst dann sende ich das nächste Zeichen.
>Diese Lösung finde ich flexibler.

Das ist auch OK so.

>Daher frage ich mich, warum die von
>mir verwendete Abfrage nicht den selben Effekt hat:

Beitrag "Unnachvollziehbares Verhalten von AVR mit UART"
Beitrag "Woran erkennt ein UART eigentlich das Startbit?"
Beitrag "Das A und O des UART- Puffers"

von Ingo (Gast)


Lesenswert?

Sorry, hast du ja...

von Toff (Gast)


Lesenswert?

Bei 12MHz und einer Baudrate von 9600 hast du einen Fehler von 0,993%. 
Laut Datenblatt kannst Du ab 0,5% Fehler Probleme bei bei 
kontinuierlicher Übertragung bekommen.
Mögliche Korrekturen:
- Baudratenquarz benutzen
- eine Baudrate finden, bei der der Fehler unter 0,5% liegt
- Pausen zwischen der Übertragung des Arrays einfügen

von Stefan H. (practical)


Lesenswert?

Okay ich habe mein Hauptprogramm jetzt etwas angepasst:
___________________________________________________________________
1
/*
2
 * usart_test.c
3
 *
4
 * Created: 18.07.2013 11:11:28
5
 *  Author: Practical
6
 */ 
7
8
#ifndef F_CPU
9
#define F_CPU 12000000UL // 12 MHz
10
#endif
11
#ifndef BAUD
12
#define BAUD  9600UL//UART mit 9600 Baud
13
#endif
14
15
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
16
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
17
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
18
19
#if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
20
#error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
21
#endif
22
23
24
#include <avr/io.h>
25
#include "usart.h"
26
#include <util/delay.h>
27
28
char ausgabe[]={'H','a','l','l','o', '\r','\0'};
29
30
int main(void)
31
{
32
  usart_init(UBRR_VAL);
33
  _delay_ms(3);
34
  usart_write_str(ausgabe);
35
    while(1)
36
    {
37
    }
38
}
___________________________________________________________________

Ich warte nach der initialisierung des USART 3ms, dann Sende ich den 
String einmal.
Jetzt werden die ersten drei Zeichen korrekt übertragen. Die 
hterm-Ausgabe sieht so aus (mehrmaliges Reseten des Controllers bei 
aktiver Verbindung mit hterm):
Hal
Hall
Hall
Hal
Hall
Hall
Halo
Hall
Hall
Hall
Hal
Hal
Halo
Hall
Hall

von Karl H. (kbuchegg)


Lesenswert?

Ich weigere mich, daran zu glauben, dass man einen PC mit 9600 Baud und 
Stringlängen_am_Stück von 7 Bytes überfahren kann.

Aber genau so siehts aus.
Entweder das, oder der Mega hat einen Schuss.

von Karl H. (kbuchegg)


Lesenswert?

Haben deine UART Funktionen IMMER schon so ausgesehen, oder hast du 
irgendwann mal drann gebastelt?
Zb. mal ein vergessenes ! ergänzt?

Geh mal in Windows ins AVR-Projekt Verzeichnis und lösche alle *.o 
Files, die dort liegen. Das müssten bei dir 2 sein. Geh auch in die 
Subverzeichnisse rein und lösch dort die *.o Files.

Und dann bau im AVR-Studio das Projekt neu. Achte drauf, dass auch 
wirklich alle beiden C-Files kompiliert werden. Sieh dir die Pfade im 
Output Fenster bei den Compiler-Aufrufen an, ob das auch wirklich die 
richtigen Files sind.

von Falk B. (falk)


Lesenswert?

@ Stefan Harney (practical)

>Okay ich habe mein Hauptprogramm jetzt etwas angepasst:

Wie sieht deine Senderoutine usart_write_str(ausgabe) aus?

>char ausgabe[]={'H','a','l','l','o', '\r','\0'};

Schon mal ein C-Buch von innen betrachtet?

char ausgabe[]={"Hallo\r"};

ist deutlich einfacher einzugeben und der Compiler ist sogar so nett, 
die Null zur Stringterminierung automatisch anzufügen.

von Toff (Gast)


Lesenswert?

Wo wir schon mal dabei sind:
Wie ist die Hardware aufgebaut? (Schaltplan und Bild vom Aufbau). 
Welchen Pegelwandler verwendest Du, was für Kondensatoren, etc.

von Paul Baumann (Gast)


Lesenswert?

O.T.
Vielleicht ist der Kontroller bei dem Wetter ja eher geneigt,
statt "Hallo" lieber "Aloha heja" auszugeben, jedenfalls hat
man an Hand der Ausgabe den Eindruck.
http://www.youtube.com/watch?v=44ZF_B5ijfo

;-)
MfG Paul

von Peter II (Gast)


Lesenswert?

Ich errechne eine recht hohe Baudratenfehler - das würde das Problem 
auch erklären.

> char ausgabe[]={'H','a','l','l','o', '\r','\0'};
geht auch einfacher:

char ausgabe[]={'Hallo\r'};

von Peter II (Gast)


Lesenswert?

Peter II schrieb:
> char ausgabe[]={'Hallo\r'};

2.Versuch:

char ausgabe[]={"Hallo\r"};

von Stefan H. (practical)


Lesenswert?

@  Falk Brunner (falk)

Ich bin gerade dabei mir ein Buch über C zu betrachten, hatte es bisher 
nur mit so gutmütigen Sprachen wie Matlab und Python zu tun. Der Code 
von mir mag etwas umstandlich sein, aber da es sich hier nur um ein 
Test-Projekt handelt, spielt das ja eigentlich keine Rolle.



@ Toff (Gast)
Ich verwende ein Experimentierboard, welches einen AVR-CDC Wandler an 
Bord hat. http://www.recursion.jp/avrcdc/.
Ob dieser Wandler wirklich korrekt funktioniert, kann ich nicht sagen.

@ Karl Heinz Buchegger (kbuchegg)
Ich habe dieses Projekt nur angelegt um mein Problem zu schildern.
Dafür habe ich die include und C-Files aus meinem eigentlichen Projekt 
einfach
kopiert. Dass der Atmega vlt einen Schaden hat ist natürlich nie 
auszuschließen.

Ich werde mich etwas mit dem Baudratenfehler beschäftigen.

von Karl H. (kbuchegg)


Lesenswert?

Stefan Harney schrieb:

> Ich habe dieses Projekt nur angelegt um mein Problem zu schildern.
> Dafür habe ich die include und C-Files aus meinem eigentlichen Projekt
> einfach

Ist schon klar.
Und ist auch gut so.

Wichtig ist nur, dass sicher gestellt ist, dass auch TATSÄCHLICH der 
Code den du herzeigst, auf dem µC läuft. Das soll schon passiert sein, 
dass auf dem µC eine ältere Version gelaufen ist, die noch fehlerhaft 
war.


> Ob dieser Wandler wirklich korrekt funktioniert, kann ich nicht sagen.

Hast du irgendeine Möglichkeit, alter PC oder altes Notebook, ohne 
diesen Umsetzer auszukommen?

von Toff (Gast)


Lesenswert?

Ich weiß jetzt nicht, welchen genauen Wandler Du einsetzt. Manche 
scheinen von Werk her auf maximal 4800 Baud eingestellt zu sein. 
Versuche mal eine geringere Baudrate.

von Stefan H. (practical)


Lesenswert?

@ Karl Heinz Buchegger (kbuchegg)

Ich habe mir, um von dem Experimentierboard unabhäniger werden zu 
können, einen Wandler bestellt:
http://www.ebay.de/itm/USB-2-0-to-UART-TTL-6PIN-Connector-Module-Serial-Converter-CP2102-New-/190685792376

Allerdings lässt die Lieferung aus Fern Ost noch auf sich warten.

______________________________________________________________________ 
__

Um die Ergebnisse hier zusammenzufassen:

- Pausenloses Senden über den UART ist keine Gute Idee
- Mein verwendeter Code sollte sonst Grundsätzlich funktionieren


Da ich keinen alternativen Rechner mit einer alten 
Seriellen-Schnittstelle zur Verfügung habe, werde ich wohl auf den Neuen 
Wandler warten.
Weiter kann ich den Atmega8A durch einen neuen ersetzen und sehen was 
dann passiert.

Die gute Resonanz in diesem Forum ist echt überwältigend, Danke an 
alle!!

von Falk B. (falk)


Lesenswert?

@ Stefan H. (practical)

>- Pausenloses Senden über den UART ist keine Gute Idee

Jain. Man kann schon SEHR lange Datenströme ohne Pause senden, ehe der 
UART ein Problem kriegt, so in der Größenordnung 100++.

>- Mein verwendeter Code sollte sonst Grundsätzlich funktionieren

Wir sehen deinen COde nicht vollständig.

>Weiter kann ich den Atmega8A durch einen neuen ersetzen und sehen was
>dann passiert.

Nicht sinnvoll.

von Karl H. (kbuchegg)


Lesenswert?

Stefan H. schrieb:
> @ Karl Heinz Buchegger (kbuchegg)
>
> können, einen Wandler bestellt:
> 
http://www.ebay.de/itm/USB-2-0-to-UART-TTL-6PIN-Connector-Module-Serial-Converter-CP2102-New-/190685792376

Bei deinem bisher verwendeten Wandler steht auf der WEbsite, dass du, 
wenn du eine zuverlässige Verbindung haben willst, lieber einen 
FTDI-Chip nehmen sollst, weil das alles noch sehr 'experimental' ist.

Sehr vertrauenerweckend ist das nicht gerade.

Zumal es ja augenfällig ist, dass ausgerechnet jedes 2. Zeichen fehlt 
(im wesentlichen) aber das, was durch kommt, korrekt ist.
Wenn die Baudrate fehlerhaft wäre, dann würde da Zeichensalat 
auftauchen. Aber das tut es bei dir nicht.

> - Pausenloses Senden über den UART ist keine Gute Idee

In dieser Allgemeinheit kann man das so nicht sagen.
Die Synchronisierung wird bei jedem Byte neu hergestellt, von daher 
kannst du in einer Wurscht dahinsenden (Handshake mal ausgenommen).
Das Problem ist das erste Zeichen!
Genauer gesagt: Wenn der Sender mit Senden beginnt und der Empfänger 
aber noch nicht bereit ist. Dann verpasst er die ersten Flanken vom Byte 
und steigt quer in die Übertragung ein. Ohne eine Pause kann sich der 
Empfänger nie auf einen korrekten Byteanfang synchronisieren. Sobald die 
Synchronisation da ist, ist alles in Butter. Dann gehts dahin.

Wobei: kein reales Programm sendet pausenlos. Was soll es denn auch 
senden? Irgendwann muss ja mal auch was berechnet werden, damit man was 
zum Senden hat.

> - Mein verwendeter Code sollte sonst Grundsätzlich funktionieren

Jep.

von Stefan H. (practical)


Lesenswert?

Habe den neuen Wandler erhalten.
Mit diesem Wandler funktioniert das ganze Fehlerfrei!!!

Danke für die schnelle Hilfe hier im Forum.

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.