Hallo Leute habe mal wieder eine Frage,
ich habe da ein Problem mit der Serielle Schnittstelle des Atmega128L
bzw das Problem ist noch immer nicht gelöst. Ich übertrage Daten vom
Mikrocontroller an den PC. Das ganze würde ich gerne Interruptgesteurt
machen und nicht mit der Funktion die im Manuel des Mikrocontrollers
beschrieben ist:
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) )
;
/* Put data into buffer, sends the data */
UDR = data;
}
Hier habe ich das Problem das der Mikrocontroller für meine Application
immer zu lange wartet und mein Main Programm nicht mehr schnell genug
abgearbeitet wird.
Jetzt habe ich mir eine Lösung überlegt bei der ich den Buffer Empty
Interrupt vom UDR Register benutze. Ich sperre den Buffer Empty
interrupt einfach wenn ich nicht mehr zum senden habe und gebe Ihn frei
wenn ich wieder etwas übertragen will und schreibe in der ISR ein Byte
in das UDR Register. (Hierzu habe ich noch eine Frage wird der Interrupt
durchgehend ausgelöst oder nur wenn das UDRE Bit gesetzt bzw entfernt
wird?). Mit dieser Lösung funktioniert das ganze soweit recht gut es ist
aber nicht sehr gut da so manchmal bytes verloren gehen. Hat jemand
vieleicht einen besseren Lösungsvorschlag für das Übertragen von Daten
über die Serielle Schittstelle vom Mikrocontroller zum PC auf
Interruptbasis
Danke im Vorraus
Grus Hans
ja. Richte einen transmit-(Ring)Buffer ein, Grösse nach deinem Bedarf. Die Grundfunktion putchar muss dann darein schreiben, nicht direkt in die UART. Zur Verwaltung brauchst du einen Schreib- und einen Lesepointer sowie einen Bytecounter. Der Uart-Interrupt holt sich dann je ein Byte aus dem Buffer, falls noch was zu senden ist. Und vom Hauptprogrogramm aus kannst du ohne nenneswerten Zeitverlust schreiben, bis dein Buffer voll ist (dann wirds wieder langsamer:-)
Hallo danke für die schnelle antwort. habe den buffer implementiert es gehen aber trotzdem noch immer ein paar bytes verloren bzw die bytes kommen nicht am pc an. und nach dem ich den interrupt gespeert und wieder frei geschaltet habe werden überhaupt keine bytes mehr übermittelt dabei ändern sich miene variablen ja nicht wenn ich den buffer empty interrupt ausschalten :(
oder nimm die: http://homepage.hispeed.ch/peterfleury/avr-software.html#libs (Warnungen wegen SIGNAL() einfach ignorieren)
Hi habe das Problem immer noch ich kann euch ja mal meinen Programmcode
hierrein posten und sagen wann bytes verloren gehen. Habe das meiner
Meinung nach genauso implementiert wie in der api die docean gepostet
hat:
ISR(USART1_UDRE_vect)
{
//Byte aus Ringbuffer nehmem und Lesezeiger hochsetzten
UDR1 =
zwischenspeichermikropcz->buffer[zwischenspeichermikropcz->read++];
//Wieviele Bytes wurden bislang übertragen
sizez ++;
//Falls Ringbuffer am Ende wieder bei Position 0 lesen
if(zwischenspeichermikropcz->read ==
RingbufferSize){zwischenspeichermikropcz->read = 0;}
//Sind soviele Bytes gesendet wie im Ringbuffer drinstehen ?
if(sizez == zwischenspeichermikropcz->size)
{
//Disable Buffer Empty Interrupt
zwischenspeichermikropcz->size = 0;
sizez=0;
UCSR1B &= ~( 1 << UDRIE1 );
}
}
So das Funktioniert auch super ohne einen Fehler. Mein Problem ist jetzt
aber das ich die Übertragung an einer stelle kurze Zeit unterbrechen
möchte. Wenn ich jetzt hingehe und an dieser stelle einfach den
Interrupt Disable UCSR1B &= ~( 1 << UDRIE1 ); . Und ihn dann kurze zeit
wieder einschalte UCSR1B |= ( 1 << UDRIE1 ); wird überhaupt nichts mehr
übertragen. Hat jemand eine Idee Woran das liegt. Selbst wenn ich in dem
Zeitraum meinen Buffer fuelle können doch keine Daten verloren gehen
oder mache ich da etwas falsch?.
Danke Hans
Hans Klemer wrote: > ISR(USART1_UDRE_vect) > ... Ja, sone Codepfitzelchen nützen in der Regel garnichts. Dazu gibt es ja extra den Dateianhang, daß man was Compilierbares posten kann. > UDR1 = > zwischenspeichermikropcz->buffer[zwischenspeichermikropcz->read++]; Solchemonstervariablennamensindwohldeinepersönlichenote,machenaberdas lesenfürnenanderenunheimlichschwer. > Interrupt Disable UCSR1B &= ~( 1 << UDRIE1 ); . Und ihn dann kurze zeit > wieder einschalte UCSR1B |= ( 1 << UDRIE1 ); Man kann nicht einfach so Interupts freigeben und sperren, was ist, wenn er schon gesperrt ist? Du mußt daher erstmal CLI machen, dann testen ob er schon gesperrt ist, dann sperren und wieder SEI, damit Test und Sperre atomar sind. Und eben nur wieder freigeben, wenn er nicht schon gesperrt war. Peter
Hi danke für die Antwort funktioniert jetzt :). Hab auch deine Anregung mit dem Kontrolieren beachtet. Wie kann ich den am besten den Empfangsinterrupt abschalten auch wenn dan die bytes verloren gehen. Würde das jetzt geschätzt mit UCSR1B &= ~(1<<RXEN1); machen oder gibt es da eine bessere möglichkeit. Danke im Voraus Gruß Hans
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.