Archiv verlassen und diese Seite im Standarddesign anzeigen : UART-Senden mit dem Interrupt in AVR
Hallo,
ich muss folgende Aufgabe erledigen: 9 über CAN empfangene Bytes an UART senden. Soweit ist diese Funktionalität erledigt bis auf einen Punkt: Datenkonsistenz des Puffer.
Code hier:
volatile UINT8 uart_tx_flag = 1;
UINT8 uart_tx_buffer[9]
void user_application()
{
if (uart_tx_flag == 1)
{
uart_tx_flag = 0;
UCSR0B |= (1 << UDRIE0); // UDRE Interrupt einschalten
}
}
ISR(USART0_UDRE_vect)
{
;// 9 Bytes von uart_tx_buffer[] mit dem Interrupt senden
uart_tx_flag = 1;
}
Das Problem ist, beim UART-Senden darf uart_tx_buffer[] nicht von CAN aktualisiert werden, also Interrupts abschalten, aber das UART-Senden selber braucht auch Interrupts. Beim atomaren Zugriff finde ich auch keine gute Lösung.
Kann jemand Hinweise geben?
Gruss
Senmeis
Felix Weiss
10.10.2008, 11:35
Hallo Senmeis,
du kannst auch das UDRE Flag abfragen, wenn die ISR alle deaktiviert sind. Schreibe eine 1 rein und das Flag wird zurückgesetzt.
In deinem Quellcode ist uart_tx_flag (fast) immer 1, sobald Daten gesendet wurden!
Du musst den Interrupt deaktivieren, wenn keine Daten mehr anstehen!
Wie sieht deine CAN-Routine aus?
Nimm doch eine Variable, die zu sendenden Bytes angibt, Can gibt die Bytes an und schreibt nur, wenn 0Bytes im Puffer.
Wenn Bytes >0 wird der UDRE Interrupt aktiviert und deaktiviert sich bei Bytes=0 selber.
Wenn der Uart mehr Daten wegschaufelt, als der CAN liefert reicht auch ein einfacher Ringbuffer. Hat da GCC nicht schon ne passende Bibo, oder solls klein werden???
Grüße Felix
Hallo,
Den Interrupt wird sicherlich in der ISR(USART0_UDRE_vect) abgeschaltet nachdem alle Bytes von uart_tx_buffer[] ausgesendet werden.
Meinst Du die Variable "can_rx_buffer_full" wie folgendes?
volatile UINT8 uart_tx_flag = 1, can_rx_buffer_full = 0;
UINT8 uart_tx_buffer[9], can_rx_buffer[9];
ISR(CANIT_vect)
{
if (CAN-Nachricht angekommen)
can_rx_buffer_full = 1;
}
void user_application()
{
if (uart_tx_flag == 1 && can_rx_buffer_full == 1)
{
uart_tx_flag = 0;
can_rx_buffer_full = 0;
for (i = 0; i < 9; i++)
uart_tx_buffer[i] = can_rx_buffer[i];
UCSR0B |= (1 << UDRIE0); // UDRE Interrupt einschalten
}
}
ISR(USART0_UDRE_vect)
{
;// 9 Bytes von uart_tx_buffer[] mit dem Interrupt senden
uart_tx_flag = 1;
}
Gruss
Senmeis
Felix Weiss
21.10.2008, 23:25
Wie du schon erwähnst, den Interrupt auf jeden Fall noch in der ISR deaktivieren!
ISR(USART0_UDRE_vect)
{
Wenn Puffer nicht leer{
-> hole nächstes Byte aus Puffer und sende es
} sonst{
-> Deaktiviere UDRE Interrupt
-> pufferBelegt=0;
}
}
Du solltest noch aufpassen, dass eine neue Nachricht deine gerade kopierende nicht überschreibem kann ( Interrupt geht ja vor!)
Für solche Sachen implementiert man ganz gerne einen FIFO. Macht wenig Aufwand und erledigt viele Probleme dieser Art. Gibt für AVR glaube auch schon fertige Bibliotheken in AVRGCC, ist aber auch schnell selbst geschrieben.
Deine Variante sollte trotzdem funktionieren ;)
Grüße Felix
Hallo,
vielen Dank.
Eigentlich gibt es nur zwei Puffer: uart_tx_buffer[] und can_rx_buffer[]. Um die Daten beim Kopieren zu schützen, habe ich Interrupts absichtlich abgeschaltet und wieder eingeschaltet, s. Code unten. Vorraussetzung ist, CAN-Daten dürfen verloren gehen. Sonst noch Probleme mit meinem Code?
void user_application()
{
if (uart_tx_flag == 1 && can_rx_buffer_full == 1)
{
cli(); // Interrupts abschalten
uart_tx_flag = 0;
can_rx_buffer_full = 0;
for (i = 0; i < 9; i++)
uart_tx_buffer[i] = can_rx_buffer[i];
sei(); // Interrupts einschalten
UCSR0B |= (1 << UDRIE0); // UDRE Interrupt einschalten
}
}
Gruss
Senmeis
Hi,
ich würde auch zum Ringpuffer raten. Einfach 2^n bytes bereithalten und zwei Zeiger durch simples maskieren rundschlagen lassen. Ein Zeiger zum beschreiben, einer zum lesen. Es wird gelesen und verarbeitet solange die Zeiger unterschiedliche Adressen aufweisen. Ist der Puffer leer, so zeigen die auf die gleiche Adresse.
So was ist "ein klassischer dreizeiler".
Gruß
Elmar
Powered by vBulletin® Version 4.1.12 Copyright ©2012 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.