ATmega8A USART Übertragung Fehlerhaft

OP #3245396
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
Angehängte Dateien:
Gast #3245453
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
OP #3245486
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.
#3245509
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.
#3245513
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"
Gast #3245548
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
OP #3245553
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
#3245566
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.
#3245573
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.
OP #3245620
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.
#3245637
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?
OP #3245686
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!!
#3245741
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.
#3245779
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.

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