Hallo, mein Usart empängt alles einwandfrei beim senden des ersten bytes wird das interrupt auch ausgelöst doch dies nur beim ersten => kann keine weiteren bytes versenden ich hoffe ihr könnt mir weiterhelfen. ************************************************************** #include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #include <avr/pgmspace.h> #include <stdio.h> // Function prototypes // int UART_putchar(char c); int UART_getchar(void); void UART_first_init(void); // Buffer sizes must be 2^n // #define TBUFSIZE 32 #define RBUFSIZE 32 #define TMASK (TBUFSIZE-1) #define RMASK (RBUFSIZE-1) // Static variables // volatile unsigned char tbuf[TBUFSIZE]; // TX buffer volatile unsigned char rbuf[RBUFSIZE]; // RX buffer volatile unsigned char t_in; // TX buffer in index volatile unsigned char t_out; // TX buffer out index volatile unsigned char r_in; // RX buffer in index volatile unsigned char r_out; // RX buffer out index SIGNAL(SIG_USART_RECV) { //****************** // RX interrupt handler // char c; c = UDR0; // Get received char rbuf[r_in & RMASK] = c; r_in++; } SIGNAL(SIG_USART_DATA) { //******************* // Data register empty interrupt handler. // Indicates that next char can be transmitted // if(t_in != t_out) { UDR0 = tbuf[t_out & TMASK]; t_out++; } else { UCSR0B &= ~(1<<UDRIE0); } } char tbuflen(void) { //**************** // Retrieve pending chars in TX buffer // return(t_in - t_out); } int UART_putchar(char c) { //********************* // Fills the transmit buffer, if it is full wait // while((TBUFSIZE - tbuflen()) <= 2); // Wait... // Add data to the transmit buffer, enable TXCIE // tbuf[t_in & TMASK] = c; t_in++; UCSR0B |= (1<<UDRIE0); //UCR |= (1<<UDRIE); // Enable UDR empty interrupt return(0); } char rbuflen(void) { // *************** // Retrive pending chars in RX buffer // return(r_in - r_out); } int UART_getchar(void) { //******************* // Retieves character from UART. This function is to be passed // to fdevopen // unsigned char c; while(rbuflen() == 0); // Wait... c = rbuf[r_out & RMASK]; r_out++; return(c); } void UART_first_init(void) { //*********************** // The function fdevopen(..) must contain as parameters the // corresponding ..putchar() and ..getchar() functions, defined before. // UCSR0B; UBRR0H = ((16000000UL/(38400 * 16L)) >> 8); UBRR0L = (16000000UL/(38400 * 16L)) - 1; // (Empfänger) | (Sender) UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); // ( 8 Bit Befehl ) UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); //UBRR = 25; // 19200 BPS //UCR = (1<<RXCIE)|(1<<TXEN)|(1<<RXEN); // 8 Databits, receive and transmit enabled, receive and transmit complete interrupt enabled fdevopen(UART_putchar, UART_getchar); sei(); // Global interrupt enable } int main(void) { //************ // unsigned char s[20]; UART_first_init(); // First init UART for(;;) { // Same function as printf() but the format string resides in flash // printf_P(PSTR("Type text in TX window, then press ENTER\r\n")); while(scanf("%s",s) == 0); // Get text printf_P(PSTR("\r\nYou entered '%s'\r\n"),s); } }
Ein Fehler: UBRR0H = ((16000000UL/(38400 * 16L)) >> 8); UBRR0L = (16000000UL/(38400 * 16L)) - 1; Die Formel sollte in beiden Fällen bis auf das ">>8" gleich sein (==>Makro verwenden!). Hat aber eher nichts mit deinem Problem zu tun. Ansonsten finde ich dein Programm etwas wirr, weil du teilweise Funktionen von hand implementierst, andererseits aber fertige Funktionen benutzt bzw. Funktionen verwendest, die nicht in deinem Quellcode vorkommen (sind die Teil der stdio.h?).
hallo, ja das programm hab ich ja von menem restlichen programm ausgelagert deswegen ein bisschen schlampig wollte sehen ob der fehler viel an meinem restlichen programm liegt aber das war es auch nicht. aber es wundert mich einfach wieso er den interrupt ein bzw 2 mal ausführt, beim 2 mal wird der interrupt deaktivert ... wird aber wieder aktiviert wenn in den puffer geschrieben wird... habe mir auch alle register angeschaut vor dem interrupt und nachdem er wieder aktiviert wird .. identisch :(
Also ich sehe da einiges unsauberes im Programm
rout,tin müssen nicht volatile sein
r_in & RMASK solltest du ersetzen durch module Arraygrösse bei 2^n wird
das dann auch ein AND ist aber wesentlich Fehlerunabhängiger
>return(r_in - r_out);
du willst doch mit Ringpuffer arbeiten? Da kann das auch negativ
werden!
In putchar und analog getchar machst du einfach r_out++; sicher
maskierst du noch beim Zugriff aber das ist ...
besonders wenn man damit den Abstand im Ringpuffer bestimmen will.
(r_in - r_out)
Ich würde vorschlagen du räumst erstmal in deinem Programmcode mit
diesen Schlampigkeiten auf.
Der interrupt wird 2x ausgeführt aufgrund der Doppelpufferung.
so da is mal der code so wie ich ihn bei mir hab ohne meiner meinung nach schlampigkeiten. das mit TX_BUF_MASK & tx_in find ich eig ganz praktisch :) das empfangen funktioniert auch einwandfrei nur halt beim senden wird der interrupt nur 2 mal aufgerufen und dann nie wieder obwohl das register auf empty steht und der interrupt auch aktiviert ist. das uart_getc ist zu vergessen benutz es eh nicht geh da genau so über einen interrupt.. uint8_t tx_buff[TX_BUF_SIZE]; uint8_t tx_in = 0; uint8_t tx_out = 0; uint8_t rn_buff[RN_BUF_SIZE]; uint8_t rn_in = 0; uint8_t rn_out = 0; /* Initialiesierung von Uart */ void uart_init(void){ // Setzen der Baud Rate UBRR0H = (BAUD_RATE >> 8); UBRR0L = BAUD_RATE; // (Empfänger) | (Sender) UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); // ( 8 Bit Befehl ) UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); fdevopen(uart_putc, uart_getc); } /* Senden aus dem Puffer */ SIGNAL(SIG_USART_DATA){ if(tx_in != tx_out) UDR0 = tx_buff[tx_out++ & TX_BUF_MASK]; else /* Sendebuffer ist leer, UDRE Interrupt deaktivieren */ UCSR0B &= ~(1<<UDRIE0); } /* Senden eines Zeichen */ void uart_putc(unsigned char c) { //Warten bis platz im Zwischenspeicher frei wird while( (RN_BUF_MASK - tx_in - tx_out) < 1) ; tx_buff[TX_BUF_MASK & tx_in++] = c; UCSR0B |= 1<<UDRIE0; }
1. du hast 2 volatile zu viel weggenommen 2.(RN_BUF_MASK - tx_in - tx_out) Wie schon erwähnt du erhöhst unsauber (ohne zu maskieren) die Zeichen gehen schneller in den Puffer als heraus d.h. z.B. RN_BUF_MASK=31 tx_in=40 (da du nicht maskierst) txout=2 31-40-2=mit sicherheit <1 Hör mit diesem Schlampigkeiten auf oder wiederhole sie nicht noch wenn du darauf hingewiesen wirst!
verwirr den armen nicht mit deinem volatile das ist meistens unwichtig. aber wenn man ne variable volatile macht dann schadet es auch nicht, kostet nur ein bisschen mehr rechenzeit. manche compiler erkennen sogar selbst wann eine variable volatile sein muss und wann nicht. also zu viele volatiles schaden nicht, verlängern nur die ausführzeit des programms
31-40-2=mit sicherheit <1 wenn das kleiner 1 is soll er solange warten bis es >1 dann weis er ja ob platz frei is oder nicht ah ich bin schon ganz verwirrt kannst du das den nicht kurz hincoden wie du es meinst ... steht grad total aufm schlauch
tx_out++ & TX_BUF_MASK
Müsste IMHO auch eher "++tx_out & TX_BUF_MASK" heissen.
(Der Übersicht wegen mache ich das gerne in zwei Zeilen.)
>RN_BUF_MASK - tx_in - tx_out
Dabei geht es doch "nur" darum, festzustellen, ob noch mindestens 1
Byte in den Puffer passt, oder?
"while (tx_in == tx_out);" sollte da sinnvoller sein, da die beiden
Variablen sowieo dauernd mit Puffergrösse-1 verundet werden.
Wolfram hat da schon ein schönes Rechenbeispiel geliefert.
> 31-40-2=mit sicherheit <1 > > wenn das kleiner 1 is soll er solange warten bis es >1 dann weis er > ja ob platz frei is oder nicht Warum soll er da warten? Wenn der Puffer 40 Zeichen gross ist, mit 31 Zeichen gefüllt wurde und erst 2 gesendet wurden, dann ist noch jede Menge Platz im Puffer. Schnapp dir Papier und Bleistift, mal dir einen Puffer auf tx_buf +---+---+---+---+---+---+--- ... ---+---+---+ | | | | | | | | | | +---+---+---+---+---+---+--- ... ---+---+---+ tx_in +-----+ | | +-----+ tx_out +-----+ | | +-----+ und spiel ein paar Fälle durch: Du spielst CPU und arbeitest dein Programm ab. Du darfst nur die Aktionen ausführen, die dir dein Program ansagt. Wenn dein Programm einen Vergleich vorschreibt, dann schaust du auf den Zettel, liest die entsprechenden Variablenwerte an und machst den Vergleich. Wenn dein Programm eine Zuweisung vorschreibt, dann korrigierst du am Zettel die entsprechenden Werte (daher Bleistift und nicht Kugelschreiber). Alles ganz genauso wie es auch dein µC macht. Und mach den Puffer nicht zu gross. Eine Puffergröße von 4 Byte ist für das Testen am Papier mehr als ausreichend. Es geht nicht um den Puffer an sich, sondern es geht darum dass du mal siehst, was dein Programm eigentlich macht. Du musst dir mal selbst ein paar Definitionen zurechtlegen. zb tx_in Index im Ringpuffer an dem das nächste zu schreibende Zeichen abgelegt wird tx_out Index im Ringpuffer welches das zuletzt gesendete Zeichen enthält /* Senden eines Zeichen */ void uart_putc(unsigned char c) { //Warten bis platz im Zwischenspeicher frei wird while( tx_in == tx_out ) ; tx_buff[ tx_in ] = c; tx_in = ( tx_in + 1 ) % TX_BUF_MASK; UCSR0B |= 1<<UDRIE0; } Jetzt ist sichergestellt, dass tx_in nur Werte im Bereich 0 bis TX_BUF_MASK enthalten kann. du musst dafür sorgen, dass tx_in und tx_out niemals den erlaubten Wertebereich verlassen. Alles andere ist ein sicherer Weg ins Chaos. Dann musst du dir natuerlich ueberlegen, wie du rbuflen() formulierst. Spiels einfach mal mit einer gedachten Buffe- groesse von 8 Bytes durch. tx_in kann kleiner als tx_out sein. D.h. aber nicht, dass der Buffer voll ist. Das heist nur, dass wieder am Anfang dieses Ringbuffers eingefügt wurde, während noch ein paar Zeichen aufs Senden warten. Der Buffer ist nur dann voll, wenn tx_in == tx_out Zumindest solltest du deinen Code dahin hintrimmen, dass diese Vorgabe immer erfüllt ist wenn tx_in != tx_out es gibt Platz im Buffer wenn tx_in == tx_out es gibt keinen Platz im Buffer Aber das wichtigste ist: Du musst tx_in und tx_out unter allen Umständen im erlaubten Wertebereich halten.
Ooops. Der letzte Teil haette es nicht mehr ins Forum machen sollen. Bitte alles nach 'Du musst dir mal selbst ein paar Definitionen zurecht legen' bitte ignorieren. Ich hab keine Ahnung ob der Code so jetzt noch zum Rest passt.
> wenn tx_in != tx_out es gibt Platz im Buffer > wenn tx_in == tx_out es gibt keinen Platz im Buffer Da gibt es aber Start-Probleme: Im ersten Moment sind tx_in und tx_out gleich (== 0 oder je nach Initialisierung). Besser ist es, entweder die freien Plätze im Puffer oder die zu sendenden Bytes zu zählen. Ist die Anzahl der freien Pufferplätze = 0, ist er voll... Ansonsten sollte man sich eine Funktion (oder Makro) ausdenken, das die Anzahl der freien Speicherplätze errechnet: l = ((tx_in>ty_out) ? (tx_in-tx_out) : (tx_out-tx_in))) & TX_BUF_MASK; (könnte so funktionieren... ausm Ärmel geschüttelt). Ist l<RN_BUF_MASK, dann ist (sollte noch) noch Platz vorhanden (sein)...
ich weis jetzt nicht ob ich meinen code anders sehe als ihr aber meiner meinung is es so das durch tx_buff[TX_BUF_MASK & tx_in++] = c; tx_in immer hochgezzählt wird und somit die gesamtanzahl der bytes die in den Puffer geschrieben worden sind ausgelesen wird tx_out wird immer hochgezählt wenn ein byte rausgeschrieben wurde tx_in: 60 tx_out: 40 => 20 Byte im puffer puffer: 30 puffer - (tx_in - tx_out) => 10 => 10 platz frei => fehler im porg das die klammer fählt => //warte bedingung while( (TX_BUF_MASK - (tx_in - tx_out)) < 1) ; sehe ich das jetzt so richtig von meinem eigen prog oder sieht ihr das anders
>> wenn tx_in != tx_out es gibt Platz im Buffer >> wenn tx_in == tx_out es gibt keinen Platz im Buffer > Da gibt es aber Start-Probleme: Im ersten Moment sind tx_in und > tx_out gleich (== 0 oder je nach Initialisierung). Kommt auf die Initialisierung an. Wenn ich mit tx_out = TX_BUF_MASK loslege, stimmt obiges. Ich wollte das auch mal so aus dem Ärmel geschüttelt, hab aber dann schnell gemerkt, dass ich das nicht hier direkt programmieren kann. Musste man aufmalen und mal ein Testprogramm auf nem PC machen (damit man auch mit einem Debugger vernuenftig ran kommt).
> tx_in immer hochgezzählt wird und somit die gesamtanzahl der > bytes die in den Puffer geschrieben worden sind ausgelesen wird Und irgendwann ist tx_in so gross (255), dass beim nächsten Addieren von 1, das Ding zu 0 wird. Dann ist tx_in plötzlich kleiner als tx_out. Was passiert dann? Wie gesagt: am Zettel aufmalen, mit Papier und Bleistift durchspielen.
aber wie gesgat ich hab mehr das problem das er den interrtupt nicht wieder auslöst er kommt also gar nich wieder da rein /* Senden aus dem Puffer */ SIGNAL(SIG_USART_DATA){ if(tx_in != tx_out) UDR0 = tx_buff[tx_out++ & TX_BUF_MASK]; else /* Sendebuffer ist leer, UDRE Interrupt deaktivieren */ UCSR0B &= ~(1<<UDRIE0); }
>tx_in immer hochgezzählt wird und somit die gesamtanzahl der bytes >die in den Puffer geschrieben worden sind ausgelesen wird >tx_out wird immer hochgezählt wenn ein byte rausgeschrieben wurde Gute Einwand, wenn tx_in unendlich groß werden könnte. Irgenwann gibt es aber einen Überlauf, und dann ist tx_in definitiv (für eine gewisse Zeit) kleiner als tx_out. Ich meinte mit "aus dem Ärmel gschüttelt" die Berechnung (hab noch nicht sooo oft mit "= ? :" gearbeitet).
stimmt da habt ihr recht ich schreib das schnell mal um so wie ihr es machen würdet :)
while( (RN_BUF_MASK - tx_in - tx_out) < 1); Hast du schonmal daüber nachgedacht was passiert wenn txin über läuft 31-0-255 was wird das für ein Datentyp? Ich habe da irgendwie leichte Probleme. Also wie war das Es wird in den grössten verwendeten Datentyp konvertiert. defines sind standardmäßig ohne Kennzeichnung int ? Das heisst wir rechnen mit int 31-0-255=-224 Warum läßt du die Variable durchlaufen und hältst nicht in ihr den direkten Pufferindex? Das würde auch die Fehlersuche sehr erleichtern.
> Ich meinte mit "aus dem Ärmel gschüttelt" die Berechnung (hab > noch nicht sooo oft mit "= ? :" gearbeitet). Sieht doch gut aus. Ich hab mich auch lange gegen ?: gewehrt. Solange man das nicht übertreibt, ist das aber echt praktisch. zb. in Argumentlisten: foo( i > j ? 3 : 1 ); Wenn man sich dran gewöhnt hat, liest sich das genauso leicht, wie if( i > j ) foo( 3 ); else foo( 1 ); Eventuell noch ein paar Klammern um die Bedingung, damit sie etwas rausleuchtet, und 'passt schon'. Nur rate ich davon ab, sowas mit komplexeren Bedingung zu machen. Das wird seeeeehr schnell unübersichtlich.
so hab das mal angepasst sollte so jetzt sein oder? torzdem immer noch das problem mit dem interrupt... :( #include "uart.h" uint8_t tx_buff[TX_BUF_SIZE]; uint8_t tx_in = 0; volatile uint8_t tx_out = 0; uint8_t rn_buff[RN_BUF_SIZE]; volatile uint8_t rn_in = 0; uint8_t rn_out = 0; uint8_t *rn_parameter[MESSAGE_BUF_SIZE]; uint8_t parameter = 0; uint8_t temp_parameter = 0; uint8_t temp = 0; void uart_putc(unsigned char c); uint8_t uart_getc(); /* Initialiesierung von Uart */ void uart_init(void){ // Setzen der Baud Rate UBRR0H = (BAUD_RATE >> 8); UBRR0L = BAUD_RATE; // (Empfänger) | (Sender) UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0)| (1<<TXCIE0); // ( 8 Bit Befehl ) UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); fdevopen(uart_putc, uart_getc); } /* Senden aus dem Puffer */ SIGNAL(SIG_USART_DATA){ if(tx_in != tx_out){ tx_out = ( tx_out + 1 ) & TX_BUF_MASK; UDR0 = tx_buff[tx_out]; }else /* Sendebuffer ist leer, UDRE Interrupt deaktivieren */ UCSR0B &= ~(1<<UDRIE0); } /* Senden eines Zeichen */ void uart_putc(unsigned char c){ uint8_t tmphead; tmphead = ( tx_in + 1 ) & TX_BUF_MASK; //Warten bis platz im Zwischenspeicher frei wird while( tmphead == tx_out ) ; tx_buff[ tmphead ] = c; tx_in = tmphead; UCSR0B |= 1<<UDRIE0; }
Hier mal zum Vergleich die Uartroutinen die ich verwende (Mega16, 8Mhz bis 500kBit)
mich wundert des weil den ir löss ich ja eig aus und eig mach ich ja alles richtig wird der ir nur 2 mal ausgelöst :(
also ich hab grad rumgespielt das problem tritt durch das deaktivern und aktivern des interrupts auf.. wenn ich ein belibiges zeichen sende und den interrupt laufen lasse geht das ohne probleme sobald ich ihn aber deaktiver und wieder aktivier wird er nicht mehr ausgeführt .. an was kann das liegen? SIGNAL(SIG_USART_DATA){ if(tx_in != tx_out){ tx_out = ( tx_out + 1 ) & TX_BUF_MASK; UDR0 = tx_buff[tx_out]; }else UDR0 = '.'; //UCSR0B &= ~(1<<UDRIE0); }
Sollte das: tx_out = ( tx_out + 1 ) & TX_BUF_MASK; UDR0 = tx_buff[tx_out]; nicht lieber andersherum stehen: UDR0 = tx_buff[tx_out]; tx_out = ( tx_out + 1 ) & TX_BUF_MASK; Übrigens müsste die Abfrage RN_BUF_MASK - tx_in - tx_out so funktionieren: RN_BUF_MASK - ((tx_in - tx_out) & TX_BUF_MASK)
ne des funtz schon da ich auch am anfag um eins erhöhe hab nur noch das dumme interrupt prob :(
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.