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?
Aus den paar Code-Fetzen kann man nicht wirklich was rauslesen. Das was du gepostet hast, ist soweit ok.
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.
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.
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.
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?
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...
>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.
>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...
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.
"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...)
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?
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....
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.