Forum: Mikrocontroller und Digitale Elektronik Interruptgesteuerte übertragung Serielle Schnittstelle ATmega128L


von Hans K. (losti85)


Lesenswert?

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

von crazy horse (Gast)


Lesenswert?

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:-)

von Falk B. (falk)


Lesenswert?

Siehe Interrupt

von Hans K. (losti85)


Lesenswert?

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 :(

von Peter D. (peda)


Lesenswert?


von ... .. (docean) Benutzerseite


Lesenswert?

oder nimm die:
http://homepage.hispeed.ch/peterfleury/avr-software.html#libs

(Warnungen wegen SIGNAL() einfach ignorieren)

von Hans K. (losti85)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Hans K. (losti85)


Lesenswert?

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
Noch kein Account? Hier anmelden.