Forum: Mikrocontroller und Digitale Elektronik Uart bringt manchmal Schrott


von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

ich habe ein Probelm: ich hab mir ein kleines Progrämmchen auf für den 
atmega8 geschrieben, er soll einfach die Zeichenkette 123x auf dem Uart 
ausgeben.
Manchmal kommt korrekt:
>>>>>1
>>>>>2
>>>>>3
>>>>>x

dann aber wieder (z.B.: wenn ich das ausleseprogramm neu starte, 
Neustart des Atmega hilft dann auch nichts?
>>>>>x
>>>>>à
>>>>>?
>>>>>à
>>>>>x
....

1
//---------------------------------
2
void send_char(unsigned char data) 
3
//---------------------------------
4
{
5
        while (!(UCSRA & (1<<UDRE)));
6
        UDR = data;
7
}
8
9
//---------------------------------
10
void send_string(char *data) 
11
//---------------------------------
12
{
13
        while (*data) {
14
                send_char(*data);
15
                data++;
16
        }
17
}
18
19
20
//-----------------
21
ISR(USART_RXC_vect)//Die Interrupt-Routine
22
//-----------------
23
{
24
          unsigned char nextChar;
25
 
26
        // Daten aus dem Puffer lesen
27
        nextChar = UDR;
28
29
30
    uint16_t adcval1;
31
        adcval1 = ADC_Read(0);
32
    char text1[32];
33
        sprintf (text1, "%u", adcval1);
34
35
    UDR=ADC_Read(0);
36
37
}
38
39
//************
40
int main(void)
41
//************
42
 {
43
       
44
  char buffer[3] = { 0 };
45
    uint16_t adcval;
46
    uint16_t kanal;
47
    kanal =0;
48
    init_uart(UBRR_VAL);
49
    init_adc(); 
50
        sei();
51
    uint8_t zahl = 123;
52
        
53
    //Hauptschleife
54
    while (1) {
55
                adcval = ADC_Read(kanal);
56
57
58
59
      itoa(zahl, buffer, 10);
60
    while (!(UCSRA & (1<<UDRE)));
61
62
    send_string(buffer);
63
    send_string("x");
64
65
        
66
 
67
    }
68
        return 1;
69
}


Auslesezeile in Java:^
1
      StringBuffer readBuffer = new StringBuffer();
2
      int c;
3
//      while ((c = inputStream.read()) != 88) { // lies bis X (88)
4
        while ((c = inputStream.read()) != 88) { // lies bis X (88)
5
        if (c != 13) {
6
          System.out.println(">>>>>" + (char)c );
7
          readBuffer.append((char) c);
8
        }
9
      }
kann mir jemand helfen - ok, ich hab noch den internen oszillator und 
empfange mit 4800Baud, aber daran liegts doch nicht oder?

Gruß
Pfeiffy

von spess53 (Gast)


Lesenswert?

Hi

>ok, ich hab noch den internen oszillator und
>empfange mit 4800Baud, aber daran liegts doch nicht oder?

Wahrscheinlich ja. Vergrößere oder verkleinere doch mal den Wert für 
UBRR.

MfG Spess

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Dirk P. schrieb:
> ich hab noch den internen oszillator und
> empfange mit 4800Baud, aber daran liegts doch nicht oder?
Doch, daran liegts sehr wahrscheinlich.
Lies mal nach, wie GENAU der interne Oszillator OHNE Ableich ist. Und 
dann hat sich die Frage erübrigt.

http://www.mikrocontroller.net/search?query=interner+oszillator+rs232
http://www.mikrocontroller.net/search?query=interner+oszillator+fehler+uart
http://www.mikrocontroller.net/search?query=interner+oszillator+schrott

von hans (Gast)


Lesenswert?

Das kann passieren.

Mögliche Ursachen:
Baudrate stimmt nicht ganz, Anzahl Start- und Stopbits und oder 
Paritybits passen nicht. Stimmt die Einstellung der Timer für die 
gewünxhte Bautrate ?

Wahrscheinlich liegt dein RC Oszilator zu sehr daneben.
Für seriele Schnittsellen sollte die Bautrate auf besser als 2% stimmen 
sonst kommt es zu Fehlern. Der interne Oszillator ist meist nicht so 
genau, läßt sich aber abgleichen (siehe Datenblatt, OSCAL).

Ich hatte das mal probiert und der interne Oszillator lag ca. 5% 
daneben.
Nach Abgleich ging es dann ganz gut.
Für sorgenfreie Funktion mit allen Betriebsspannungen und Temperaturen 
hilft nur ein Quarz, der interne Oszillator ist dafür zu schlecht.

Frohes Fest

Hans

von Purzel H. (hacky)


Lesenswert?

Man sollte bedenken, dass der Abgleich des RC Oszillators von der 
Temperatur, sowie von der Versorgungsspannung abhaengt. Eine sinnvolle 
Loesung beruht auf einem Keramikschwinger, oder einem Quarz.
Da ein Quarz nur um die 20 cents kostet, lohnt sich eine Sparuebung hier 
nicht.

von Roland H. (batchman)


Lesenswert?

Es mag nicht relevant sein, aber

Dirk P. schrieb:
> char buffer[3] = { 0 };
>     uint8_t zahl = 123;
>       itoa(zahl, buffer, 10);

Wenn itoa die drei Ziffern + \0 in den Buffer schreibt, dann wird's da 
drin eng. Er schreibt also munter weiter, und die \0 landet in adcval.
Die \0 wird dann von ADC_Read(kanal) überschrieben.

Die Größe des Puffers muss gewisse Kriterien erfüllen, siehe stdlib.h

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

danke, ich werde nun doch mal den exteren Quarz einbauen, dann werde ich 
sehen, obs daran liegt.

Gruß
Pfeiffy

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

ich habe nun einen 4MHZ ceramic quarz als externen oszilator drangehängt 
und auch die Fuses richtig eingestellt. Aber es ist immer so, wenn ich 
das (Abfrageprogramm) Programm starte kommen die richtigen werte, wenn 
ich es aus und wieder einschalte kommen andere Zeichen - kann es sein, 
dass das normal ist ,wenn ich den AVR aus und wieder einschalte kommen 
wieder die richtigen Zeichen.

Gruß
Pfeiffy

von Dirk P. (pfeiffy)


Lesenswert?

Achso, Baud sind 9600 und ich schreibe nur 4 chars (ohne Buffer)

von Roland H. (batchman)


Lesenswert?

Dirk P. schrieb:
> und ich schreibe nur 4 chars (ohne Buffer)

Sollen wir nun raten?

Hast Du das Programm verändert? Offensichtlich ja, dann stelle es bitte 
ein.

von Karl H. (kbuchegg)


Lesenswert?

Dirk P. schrieb:

> das (Abfrageprogramm) Programm starte kommen die richtigen werte, wenn
> ich es aus und wieder einschalte kommen andere Zeichen - kann es sein,
> dass das normal ist ,wenn ich den AVR aus und wieder einschalte kommen
> wieder die richtigen Zeichen.

Sendest du in einem durch?

Dann kann das schon sein.
Eine UART muss sich erst mal mit der Gegenstelle synchronisieren, ehe 
sie synchron laufen. Das geht aber nur, wenn der Sender ab und zu mal 
einen kleine Pause einlegt, damit beide (Sender und Empfänger) dieselbe 
Flanke einem Zeichenanfang zuordnen. Durch das Ein/Ausschalten des AVR 
verschaffst du dem PC diese kleine Pause, während wenn du das 
Abfrageprogramm startest es zufällig an irgendeiner Stelle die nächste 
eintreffende Flanke als Zeichenanfang nimmt, was gar nicht stimmen muss.

Mach mal in deine Hauptschleife einen kleinen delay rein. Das könnte das 
Problem beheben.

von Holler (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Eine UART muss sich erst mal mit der Gegenstelle synchronisieren, ehe
> sie synchron laufen.

Das ist doch ziemlicher Unsinn: das Ding heisst nicht umsonst
Universal Asynchronous (!) Receiver Transmitter.

Durch Störungen kann bei anhaltendem Datenstrom die Sache zwar aus dem 
Takt kommen, aber das ist hier wohl nicht das Problem: nur 4 Zeichen.

Wie etliche Vorposter auch tippe ich auf ein ungenaues Setup, entweder 
wegen Oszillatorablage oder ungenauen Vorteiler. Da sind UARTs 
empfindlich.
Das es mal geht und mal nicht passt ins Bild. Mitunter ist das sogar 
zeichenabhängig.
Weiter Fehlermöglichkeit: die UART wird während des Betriebs durch 
Registerzugriffe gestört.

von Simon K. (simon) Benutzerseite


Lesenswert?

Holler schrieb:
> Karl Heinz Buchegger schrieb:
>
>> Eine UART muss sich erst mal mit der Gegenstelle synchronisieren, ehe
>> sie synchron laufen.
>
> Das ist doch ziemlicher Unsinn:
Das ist kein Unsinn.

> das Ding heisst nicht umsonst
> Universal Asynchronous (!) Receiver Transmitter.
In wie fern ist das jetzt ein widerspruch? Klar, die Übertragung ist 
Asynchron, deshalb muss ja eben erst synchronisiert werden, damit es 
funktioniert.

Das Synchronisieren geschieht dann über eine entsprechende Taktflanke 
und einer State-Machine in dem UART Empfänger und der Baudrate, die man 
vorgeben muss.

von Karl H. (kbuchegg)


Lesenswert?

Holler schrieb:
> Karl Heinz Buchegger schrieb:
>
>> Eine UART muss sich erst mal mit der Gegenstelle synchronisieren, ehe
>> sie synchron laufen.
>
> Das ist doch ziemlicher Unsinn: das Ding heisst nicht umsonst
> Universal Asynchronous (!) Receiver Transmitter.

Und, schon mal angesehen wie das funktioniert?
Und warum es da Probleme geben kann, wenn man sich in eine gerade 
laufende Übertragung als Empfänger aufschaltet?

Nur weil das Ding Asynchron heißt, bedeutet das noch lanbge nicht, dass 
Sender und Empfänger während der Dauer eines Zeichens nicht 
synchronisiert werden müssen. Der Empfänger sieht haufenweise Flanken an 
seinem Eingang. Welche davon ist denn der Beginn des ersten gültigen 
Startbits?

> Durch Störungen kann bei anhaltendem Datenstrom die Sache zwar aus
> dem Takt kommen, aber das ist hier wohl nicht das Problem: nur 4 Zeichen.

Programmtext besser lesen: die in einer Schleife laufend wiederholt 
werden.
Fehlerbeshreibung besser lesen: Zitat: Wenn ich das Empfangsprogramm 
abstelle und neu starte, ....   Starte ich dann den AVR neu, dann klappt 
wieder alles ....

von Holler (Gast)


Lesenswert?

Eine UART arbeitet in der Regel nicht als Statemachine die sich die 
erstbeste Flanke schnappt und losrennt. Bekannte UARTS (16450, 16550D) 
tasten das Signal ab. Wenn das Timing nicht passt (Stopp Bit nicht 
erkannt), setzen die UARTs ein Framing Error und versuchen das nächste 
Startbit zu finden, ebenfalls mit Überabtastung. Manche 
Terminalprogramme können Framingfehler anzeigen. Oder bei 
Selbstgeschiebenem die Register aauslesen.

Details z.B. http://www.ti.com/lit/ds/symlink/pc16550d.pdf

Auch wenn man 123 x 4 Zeichen ausgibt: das ist fast nichts (von wegen 
laufend wiederholt ... eben besser lesen).

Bitte sicherstellen, dass der Teiler passt: 4 MHz / 9600 ergibt einen 
krummen Teiler. Eine UART kann bei mehr als 1-3 % Ablage bereits in 
Schwierigkeiten kommen.

von Karl H. (kbuchegg)


Lesenswert?

Holler schrieb:

> Bekannte UARTS (16450, 16550D)
> tasten das Signal ab. Wenn das Timing nicht passt (Stopp Bit nicht
> erkannt), setzen die UARTs ein Framing Error und versuchen das nächste
> Startbit zu finden, ebenfalls mit Überabtastung.

Was sie aber nciht finden werden, weil sie zum falschen Zeitpunkt 
beginnen, danach zu suchen.


> Auch wenn man 123 x 4 Zeichen ausgibt: das ist fast nichts (von wegen
> laufend wiederholt ... eben besser lesen).

Und die while Schleife drummherum ignorierst du einfach, oder wie? Und 
dass der UART am AVR 2 Zeichen buffern kann, d.h. der ADC und itoa die 
Zeit bekommen ihr Ding zu machen, ehe auf der UART lange genug Ruhe 
herrscht, dass PC_seitig der UART die nächste Flanke garantiert als 
Startbit auffasst, auffassen muss, weil eben lange genug die Leitung 
nichts getan hat.
Gerade bei 16Mhz hat der AVR viele Zyklen frei, ehe die UART komplett 
leer ist.

Mach doch ein Experiment.
Sende in einer Schleife laufend ein bestimmtes Zeichen.
Während dessen ziehst du das Kabel ab und steckst es wieder an. Der 
Empfänger wird dir ganz was anderes anzeigen. Und schlimmer noch: er 
wird nie wieder sich korrekt in den Datenstrom einklinken.

Dann machst du einen kleinen Delay in die Schleife zusätzlich mit rein. 
10ms.
Und probierst dasselbe. Das erste Zeichen nach dem Wiedereinstecken wird 
falsch sein. Aber die restlichen stimmen wieder. Warum? Weil die Pause 
dem Empfänger ermöglicht hat, sich auf die richtige Flanke als Startbit 
zu synchronisieren.

Alles schon vor Jahren durchprobiert und durchdacht, warum das so ist.

von Karl H. (kbuchegg)


Lesenswert?

> Eine UART arbeitet in der Regel nicht als Statemachine
> die sich die erstbeste Flanke schnappt und losrennt.

Natürlich tut sie das! Sie hat ja nichts anderes als eine Leitung auf 
der der Pegel ständig wechselt. Die UART weiß nicht per se, welche 
Flanke jetzt ein Startbit ist und welche nicht.

Und klar: man kriegt einen Framing Error, wenn die Leitung eigentlich 
auf Ruhepegel für das Stoppbit sein sollte, es aber nicht ist. Man kann 
aber auch die Daten so hindrehen, dass diese Bedingung erfüllt ist, es 
also keinen Framing Error gibt, und die Übertragung trotzdem falsch ist.

von Holler (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:

> Und die while Schleife drummherum ignorierst du einfach, oder wie?

Stimmt, da habe ich Mist geschrieben. Stellt aber den restlichen Text 
nicht in Frage.

Was definitiv nicht geht, ist auf eine laufende Sendung des AVRs das 
Terminalprogramm bzw die Java-Abfrageschleife zu starten. Das geht 
schief.

Um den Fehler einzugrenzen, würde ich z.B. ein Freeware Terminalprogramm 
starten (z.B. Terraterm unter Windows).

- Standardeinstellung 9600N81 (9600 Bit/s, keine Parität, 8 Daten, ein 
Stoppbit.)
- AVR starten
- Alles sauber? Mehrfach den AVR stoppen und starten.
- Wenn wieder Schrott erscheint, ggf den AVR mit 2 Stoppbits betreiben. 
Damit kann man unsauberes Timing kaschieren.
Oder wie oben beschrieben ein kleines Delay einbauen. Das reduziert die 
Datenrate und ist eine Krücke.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Eine grundlegende andere Sache fällt mir in dem Programm aber auch noch 
auf. Sowohl in der Hauptschleife als auch im RXC Interrupt wird 
ADC_Read() aufgerufen.
Um Konflikte zu vermeiden, würde ich mich da auf eine Methode 
beschränken, also entweder im Interrupt oder in der Hauptschleife.
Wenns nämlich in der Hauptschleife ein RXC Interrupt gibt, während 
ADC_Read() gerade läuft, wirds lustig.

von Karl H. (kbuchegg)


Lesenswert?

Holler schrieb:

> Oder wie oben beschrieben ein kleines Delay einbauen. Das reduziert die
> Datenrate und ist eine Krücke.

Da geh ich absolut mit dir konform. Eine Krücke ist es. Zur Not würde 
ich es so machen, dass ich diesen delay nur ab und zu (zb 10. 
Schleifendurchlauf) mache. Um eine Möglichkeit zur empfängerseitigen 
Fehlererkennung kommt man sowieso nicht herum. Ist zwar nicht ideal, 
aber sein hinten nach gesendetes 'x' kann das in Ansätzen schon leisten. 
Der PC verwirft dann eben alle Übertragungen, bei denen das 'x' fehlt 
und die Zeichen dazwischen keine Zahl ergeben.

von Holler (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Natürlich tut sie das! Sie hat ja nichts anderes als eine Leitung auf
> der der Pegel ständig wechselt. Die UART weiß nicht per se, welche
> Flanke jetzt ein Startbit ist und welche nicht.
>
Es trägt wenig zur Problemlösung bei, trotzdem: Eine UART tastet den 
Eingangspegel ständig ab, meist mit 16facher Baudrate. Wenn aus dem 
Idle-Zustand eine bestimme Anzahl von Abtastwerten low sind, wird das 
als Startbit gewertet. Mittig der low-erkannten Startsamples wird allen 
16. folgenden Samples die Folgebits abgetastet. Beim Stoppbit findet 
wieder eine Gewichtung statt.
So funktioniert der Empfang bei einer UART. Wenn du mir nicht glaubst 
lese ausführliche Datenblätter. Oder schaue dich in Asic/VHDL Foren um.

von Karl H. (kbuchegg)


Lesenswert?

Holler schrieb:
> Karl Heinz Buchegger schrieb:
>> Natürlich tut sie das! Sie hat ja nichts anderes als eine Leitung auf
>> der der Pegel ständig wechselt. Die UART weiß nicht per se, welche
>> Flanke jetzt ein Startbit ist und welche nicht.
>>
> Es trägt wenig zur Problemlösung bei, trotzdem: Eine UART tastet den
> Eingangspegel ständig ab, meist mit 16facher Baudrate. Wenn aus dem
> Idle-Zustand eine bestimme Anzahl von Abtastwerten low sind, wird das
> als Startbit gewertet.

Du redest von anderen Dingen.
Du redest davon, wann ein Bit als gültig erkannt wird und wann nicht. 
Das stelle ich überhaupt nicht in Frage. Es geht mir um das was danach 
kommt! Was bedeutet dieses Bit? Ist es ein Startbit oder ist es eines 
der 8 Datenbits aus einem Byte dessen Beginn zu einem Zeitpunkt 
erfolgte, als die UART noch gar nicht auf der Leitung gehorcht hat.

Und bei einer UART ist es nun mal so, dass man einem Bit nicht ansehen 
kann, welches Bit (Startbit, Datenbit oder Stoppbit) es ist. D.h. man 
muss relativ willkürlich annehmen, dass das der erste eintrudelnde 
Low-Pegel ein Startbit ist. Diese Annahme muss aber nicht stimmen! Erst 
dann, wenn die Leitung zuvor mindestens über die Zeitspanne eines 
kompletten "UART-Bytes" (Start, Daten und Stoppbits zusammengenommen) 
auf Ruhepegel war, kann ich mit Sicherheit davon ausgehen, dass das 
nächste Low-Bit ein Startbit sein muss: Sender und Empfänger haben sich 
für dieses Zeichen synchronisiert. Und wenn diese Synchronisierung erst 
einmal erfolgt ist, dann benötigt man auch die Pause nicht mehr, damit 
sie sich für das nächste Zeichen erneut synchronisieren können. Sie 
werden wieder übereinstimmend dasselbe Bit als das Startbit anerkennen.

Das hat nichts damit zu tun, wie ein Empfänger jetzt seine Bits durch 
Oversampling von der Leitung holt(*), sondern ist sozusagen logisch 
gesehen schon eine Schicht höher angesiedelt.

(*) Und das ist auch das Asynchron in UART: Der Sender kann zu jedem 
Zeitpunkt mit einem Zeichen anfangen. Also asynchron zu jeglichem 
irgendwie geartetem sonstigen Takt. Das bedeutet aber nicht, dass die 
beiden sich überhaupt nie Synchronisieren. Während eines Zeichens sind 
die beiden synchron: Der Empfänger interpretiert den Leitungsstatus 
zeitlich synchron mit dem, was der Sender mit der Leitung macht. Während 
einer Zeichenübertragung sind die beiden synchron. Nach einem Zeichen 
ist diese Synchronisierung wieder aufgehoben und wird mit dem nächsten 
Startbit wieder hergestellt.

von Holler (Gast)


Lesenswert?

da core, Aufstart in eine laufende, lückenlose Sendung ist kaum möglich. 
Geht nur durch trail- und error mit framing-error Beobachtung.

Üblich war in den 80-90igern zur Modem-Zeit die Hardware-Flußkontrolle 
RTS/CTS bzw S2/M2. Damit gehts immer.

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

danke für die Antworten und Erklärungen. Ich dachte mir schon, dass es 
mit dem starten des Abfrageprogramms während des Sendens was zu tun hat, 
sonst hatte ich immer das senden durch einen interrupt angestoßen, da 
gab es keine Probleme, nun möchte ich durch den Interrupt nur die Kanäle 
auswählen aber immerfort senden.
Ich habe nun einen delay von 10ms eingebaut,  dann kann ich das 
Abfrageprogramm immer beenden und wieder starten, ohne Probleme.

Gruß
Pfeiffy

von Basti (Gast)


Lesenswert?

Hallo,
Ich beschäftige mich auch seit kurzem mit dem UART PC16550D, hab da auch 
ein Problem mit den Interrupts, wäre super wenn du mal in meinem 
BBeitrag reinschauen könnstest. Hab weiter oben gelesen:


Holler schrieb:
> Eine UART arbeitet in der Regel nicht als Statemachine die sich die
> erstbeste Flanke schnappt und losrennt. Bekannte UARTS (16450, 16550D)
> tasten das Signal ab. Wenn das Timing nicht passt (Stopp Bit nicht
> erkannt), setzen die UARTs ein Framing Error und versuchen das nächste
> Startbit zu finden, ebenfalls mit Überabtastung.


Karl Heinz Buchegger schrieb:
>> Bekannte UARTS (16450, 16550D)
>> tasten das Signal ab. Wenn das Timing nicht passt (Stopp Bit nicht
>> erkannt), setzen die UARTs ein Framing Error und versuchen das nächste
>> Startbit zu finden, ebenfalls mit Überabtastung.
>
> Was sie aber nciht finden werden, weil sie zum falschen Zeitpunkt
> beginnen, danach zu suchen.

Kannst dir ja mein Fehlerbild anschauen, ich denke dass es irgendwie 
dasselbe Problem sein kann.

Danke.


Beitrag "UART PC16550D Interrupt Fehler"

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.