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.