Forum: Mikrocontroller und Digitale Elektronik Probleme mit UART


von Thomas (Gast)


Lesenswert?

Hi,

ich hab Probleme bei der UART Übertragung. Empfangen alleine klappt, 
senden alleine auch, nur beides zusammen haut nicht hin.

Das empfangen mach ich per Daten-empfangen-Interrupt. Das senden ohne 
Interrupt in der main in der main(). Controller Atmega48

Hab leider den kompletten Code jetzt nicht zur Hand, sonst würd ich den 
auch mal schnell posten.

Hier nur ein paar Ausschnitte:

void uart_init()
{

DDRB |= (1 << PB2) | (1 << PB4) | (1<<PB1);

/* Aktivieren des Empfängers, des Senders und des "Daten 
empfangen"-Interrupts */
UCSR0B = (1<<RXCIE0) | (1<<RXEN0)|(1<<TXEN0);

/* baud rate*/
UBRR0H = (unsigned char) (UBRR>>8);
UBRR0L = (unsigned char) UBRR;

/* frame format: 8data, 2stop bit*/
UCSR0C =  (1 << USBS0) | (3 << UCSZ00);
}


void uart_transmit()
{
while(!(UCSR0A & (1<<UDRE0)))
{
}
UDR0 = AD_WERT_AKKU;
}


ISR(USART_RX_vect)
{
static unsigned char state = STATE_IDLE;

  c = UDR0;

  switch (state)
         ..............
         ...............
         ............usw.
}


Irgendwie scheinen die sich gegenseitig zu stören.... Sieht jemand den 
Fehler?




von Karl heinz B. (kbucheg)


Lesenswert?

Aus den paar Code-Fetzen kann man nicht wirklich was rauslesen.
Das was du gepostet hast, ist soweit ok.

von Thomas (Gast)


Lesenswert?

In ca. ner Stunde bin ich Zuhause, dann poste ich den ganzen Code.

Können die(empfangen und senden) sich denn irgendwie gegenseitig stören?

Vielleicht liegt es an meiner STATE, die ist ziemlich lang. Wenn ich ihm 
nur zwei Byte über die serielle schicke klappt auch beides zusammen.

Nur bei 16Bytes vom einen Controller zum anderen tauchen die Probleme 
auf. Und dabei sieht es so aus, das die ersten 16Byte empfangen werden, 
danach aber nix mehr.

von Karl heinz B. (kbucheg)


Lesenswert?

ALte Regel:
Interrupt Service Funktionen so kurz wie möglich. Während eine ISR
läuft sind alle Interrupts gesperrt.

Normalerweise holt man in der ISR einfach nur das Zeichen ab und
stellt es in einen Buffer (Queue). Verarbeitet werden die Daten
dann erst in der Hauptschleife in der main().

Wenn du dich an dieses einfache Schema hältst, kann eigentlich nichts
schief gehen.

von Christian S. (kriki)


Lesenswert?

1. Wie schauts mit der Gegenseite aus ? Auch ein Mega oder was hängt 
dort dran?

2. Probier mal, wenn du vor dem Senden den RX-Int abdrehst, TXCIE an und 
auf Tx-Complete wartest, und dann den RX-Int wie an, Tx aus.

Könnte sein, dass wenn ein Interrupt von RX kommt, das dir die Daten von 
UDRE verschmeisst.

von Thomas (Gast)


Lesenswert?

Ja, das ist anscheinend das Problem. Der UDR0 Wert.

Wenn ich Daten Empfange schreibe ich ja das erste Byte aus UDR0 in eine 
Variable und verarbeite diese mit einer STATE. Beim zweiten Empfangen 
Interrupt springt er dann in die entsprechende STATE und verarbeitet 
wieder UDR0. Das passiert 16 mal, also 16 empfangene Bytes.

Zwischendurch wird aber mal die Senden Routine aufgerufen. Da dort auch 
UDR0 verarbeitet wird, stimmen dann die Werte in der Empfangen Routine 
nicht mehr.

Könnte höchstens mit einem Interrupt arbeiten, welches am Anfang des 
Interrupts ausgeschaltet und nach 16 empfangenen Bytes wieder 
eingeschaltet wird.

Oder gibt es noch ne andere Möglichkeit?

von inoffizieller WM-Rahul (Gast)


Lesenswert?

Dass der Inhalt des "Sende-UDR0" nichts (aber auch überhaupt nichts!) 
mit dem Inhalt des "Empfangs-UDR0" zu tun hat, ist dir klar, oder?
Das sind zwei Register, die über die gleiche Adresse angesprochen 
werden. Wobei man das eine nur beschreiben und das andere nur lesen 
kann.

Eine State-Machine gehört nicht in eine ISR! Dafür sollte die 
Hauptschleife genug Platz und Zeit bieten. (Schliesse mich somit 
Karl-Heinz an.)
Dass dein gepostetes Programm etwas spärlich ausfällt, hat Karl-Heinz ja 
auch schon "bemängelt".

Was soll dein Programm machen bzw. wie sieht dein Protokoll aus?
Je nach Protokoll würde ich in der Empfangs-ISR ein Flag setzen, dass 
entweder bei jedem empfangenen Byte gesetzt wird, oder dann gesetzt 
wird, wenn alle 16 Bytes empfangen wurden. Die zweite Variante erfordert 
auf jeden Fall einen Puffer... Dann könnte die State-Machine aber auch 
anders aussehen...

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

>Dass der Inhalt des "Sende-UDR0" nichts (aber auch überhaupt nichts!)
>mit dem Inhalt des "Empfangs-UDR0" zu tun hat, ist dir klar, oder?

Doch doch, eigentlich schon. Aber das Programm funktioniert nur nicht, 
sobald ich in der Sende-Routine UDR0 veränderen.

Hab es jetzt mal mit nem Senden_Interrupt versucht. Haut aber auch nicht 
hin.

Das Programm ist nun dabei. ist wahrscheinlich dann einfacher 
nachzuvollziehen.

von inoffizieller WM-Rahul (Gast)


Lesenswert?

>UCSR0B = (1<<RXCIE0)|(1<<RXEN0)|(1<<TXEN0) | (1 << UDRIE0);
Wenn du UDRIE0 setzt, springt der Controller dauernd in die 
USART-Transmit-ISR.

Besser:
.
.
.

AD_WERT_AKKU = ADCH;
UDR0 = AD_WERT_AKKU;
UCSR0B |= (1 << UDRIE0);
.
.
.

ISR(USART_UDRE_vect)
{
  UCSR0B &= ~(1 << UDRIE0);
}

Und Kommentare würden die Lesbarkeit erhöhen...

von Thomas (Gast)


Lesenswert?

Ja, mit Kommentaren hab ich es nicht so. Werd ich aber gleich mal 
ändern.

Klappt so auch nicht, sobald UDR0 mit dem AD-Wert überschrieben wird.

Wenn ich diese Zeile "//UDR0 = AD_WERT_AKKU; "ausblende, dann geht der 
Empfang. Wenn sie mit ausgeführt wird, läuft er nicht.

von inoffizieller WM-Rahul (Gast)


Lesenswert?

"c" würde ich noch ein "voltile" bei der Deklaration spendieren.
Eigentlich solltest du allen Variablem, die du in ISR und woanders 
benutzt, das volatile spendieren.

Wenn du den Funktionen c als Parameter übergeben würdest, wäre die 
State-Abfrage etwas kürzer.... (eher ein Schönheitsproblem...)

von Thomas (Gast)


Lesenswert?

Gut.

Aber woran mag es liegen, dass diese einzelne Zeile das Empfangen 
komplett lahm legt, wenn die Inhalte von UDR0 beim Senden + Empfangen 
nichts miteinander zu tun haben?

von Thomas (Gast)


Lesenswert?

Also es muss daran liegen, dass ich dem UDR0 zum senden einen Wert 
zuweise.

Sobald dieses irgendwo im Programm geschieht, funktioniert das Empfangen 
nichbt mehr....

von Karl heinz B. (kbucheg)


Lesenswert?

Eher nicht.
Was du siehst sind die Auswirkungen eines anderen Problems.
Ich steig aber noch nicht komplett durch den Code durch.
Werde mich in der Nacht mal dazusetzen und das mit realer Hardware
durchprobieren. Ich hab allerdings keinen Mega48, nur einen Mega16.
Sollte aber keinen Unterschied machen.

von Thomas (Gast)


Angehängte Dateien:

Lesenswert?

Das wäre echt super!

Hab den Code noch mal angehangen und etwas ausführlicher beschrieben + 
übersichticher gestaltet.

Schon mal vielen Dank!

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.