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?
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.
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.