Guten Morgen Forum, ich hätte da ein paar Anfängerfrage zu Peter Fleurys UART Lib. Ich stehe da derzeitg auf dem Schlauch. Wäre nett, wenn mir hierbei jemand weiterhelfen könnte. Grüße 1) Meine erste Frage wäre, warum man eigentlich lastRxError verwendet bzw. einsetzt wird. FE ist ja ein Fehler des Empfangsrahmen und DOR der Empfängerüberlauf. Ist das wirklich nötig? /* read UART status register and UART data register */ usr = UART0_STATUS; // UCSR0A data = UART0_DATA; // UDR0 /* */ #if defined( AT90_UART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #elif defined( ATMEGA_USART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #elif defined( ATMEGA_USART0 ) lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); #elif defined ( ATMEGA_UART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #endif 2) Im Empfangs-Interrupt ist weder tmptail noch noch UART_TxTail initialisiert. Zudem verstehe ich nicht ganz warum noch ein Bit -And mit UART_RX_BUFFER_MASK (Buffer_Size -1) bei tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK; verwendet wird. Ich verstehe hier nicht ganz die Vorgehensweise und warum die Buffergröße 2^x sein muss. 3) Last but not least wäre da noch die Sache mit dem Rechts-shift bei lastRxError = UART_BUFFER_OVERFLOW >> 8; UART_BUUFER_OVERFLOW wird mit 0x0200 initialisiert, warum? Und weshalb der Rechts-shift? SIGNAL(UART0_RECEIVE_INTERRUPT) /*********************************************************************** ** Function: UART Receive Complete interrupt Purpose: called when the UART has received a character ************************************************************************ **/ { unsigned char tmphead; unsigned char data; unsigned char usr; unsigned char lastRxError; /* read UART status register and UART data register */ usr = UART0_STATUS; data = UART0_DATA; /* */ #if defined( AT90_UART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #elif defined( ATMEGA_USART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #elif defined( ATMEGA_USART0 ) lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); #elif defined ( ATMEGA_UART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #endif /* calculate buffer index */ tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; if ( tmphead == UART_RxTail ) { /* error: receive buffer overflow */ lastRxError = UART_BUFFER_OVERFLOW >> 8; }else{ /* store new index */ UART_RxHead = tmphead; /* store received data in buffer */ UART_RxBuf[tmphead] = data; } UART_LastRxError = lastRxError; }
Klaus schrieb: > 1) Meine erste Frage wäre, warum man eigentlich lastRxError verwendet > bzw. einsetzt wird. Eigentlich sollte man die immer benutzen. Aber wie es eben im Leben so ist: Meistens tut man es nicht. Diese Fehler sind selten und da man meistens programmtechnisch eh nichts dagegen tun kann, lässt man es eben. > FE ist ja ein Fehler des Empfangsrahmen und DOR der > Empfängerüberlauf. Ist das wirklich nötig? Frame Error deutet darauf hin, dass entweder * bei den Übertragungsparametern keine Einigkeit zwischen Sender und Empfänger herrscht * oder sich die UART beim ersten Zeichen nicht richtig synchronisieren konnte Empfängerüberlauf bedeutet einfach nur, dass dein Programm zu lange getrödelt hat und zu lange in einem Interrupt steckte, so dass der Receive Interrupt die UART nicht schnell genug leeren konnte. > 2) Im Empfangs-Interrupt ist weder tmptail noch noch UART_TxTail > initialisiert. Dazu müsste man jetzt den kompletten Code sehen. Aber denk daran: Globale Variablen werden sowieso automatisch mit 0 initialisiert. > Zudem verstehe ich nicht ganz warum noch ein Bit -And mit > UART_RX_BUFFER_MASK (Buffer_Size -1) bei > > tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK; > > verwendet wird. Weil er hier einen Ring bauen will: tmphead soll beispielsweise nacheinander die Werte annehmen 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, .... Also im Kreis alle Wert von 0 bis 7 (das sind 8 Werte) und dann wieder bei 0 beginne > Ich verstehe hier nicht ganz die Vorgehensweise und > warum die Buffergröße 2^x sein muss. Genau aus dem Grund: Damit er hier ein AND benutzen kann und nicht den Rest einer Division bestimmen muss. > 3) Last but not least wäre da noch die Sache mit dem Rechts-shift bei > > lastRxError = UART_BUFFER_OVERFLOW >> 8; > > UART_BUUFER_OVERFLOW wird mit 0x0200 initialisiert, warum? Weil er das so haben will > Und weshalb > der Rechts-shift? Weil das Ziel als unsigned char keine 16 Bit aufnehmen kann. Wharscheinlich braucht er die Konstante UART_BUFFER_OVERFLOW nach an anderer Stelle im Code, dort aber als 16 Bit Wert.
Hallo Karl-Heinz, vielen Dank für deine Antwort! Ahhh, ok. Bei einer Buffergröße von 8 tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; wäre das dann also 0000 0111 & 0000 0001 = 0000 0001 und so weiter Vielen Dank! Gruß
Hallo, ich hab mir die Lib von Peter Fleury nochmals zu Gemüte geführt und dabei haben sich nochmal ein paar Fragen aufgetan. Es wäre nett, wenn mir hierbei jemand weiterhelfen könnte. Ich habe immer noch Verständnisprobleme bei den Fehlermeldungen... /* ** high byte error return code of uart_getc() */ #define UART_FRAME_ERROR 0x0800 /* Framing Error by UART */ #define UART_OVERRUN_ERROR 0x0400 /* Overrun condition by UART */ #define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ #define UART_NO_DATA 0x0100 /* no receive data available */ UART_FRAME_ERROR 0x0800 1000 0000 0000 (2048dec) UART_OVERRUN_ERROR 0x0400 100 0000 0000 (1024dec) UART_BUFFER_OVERFLOW 0x0200 10 0000 0000 (512dec) UART_NO_DATA 0x0100 1 0000 0000 (256dec) In der ISR wir ja zunächst mal überprüft ob im 7 Bit großen UCSR0A Register ein Frame Error oder ein Empfängerüberlauf aufgetreten ist. lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); Tritt ein Overflow auf... if ( tmphead == UART_RxTail ) { /* error: receive buffer overflow */ lastRxError = UART_BUFFER_OVERFLOW >> 8; wird 10 0000 0000 >> 8 in 00 0000 0010 umgewandelt. Was in uart_getc vor sich geht verstehe ich nicht so ganz. unsigned int uart_getc(void) { unsigned char tmptail; unsigned char data; if ( UART_RxHead == UART_RxTail ) { return UART_NO_DATA; /* no data available */ } /* calculate /store buffer index */ tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK; UART_RxTail = tmptail; /* get data from receive buffer */ data = UART_RxBuf[tmptail]; return (UART_LastRxError << 8) + data; Zunächst wird data als unsigned char deklariert. Also 7 Bit groß (0..255). Dann am Ende der Funktion, wird return (UART_LastRxError << 8) + data; der Fehler und data zurückgegeben. Was wird hier eigentlich gemacht? ich versteh das nicht. In der Test-Demo wird nun c als unsigned int deklariert. Also 32 Bit ( 0 - 4.294.967.295 ). Ich versteh das noch nicht so ganz... if ( c & UART_NO_DATA ) ...wenn UART_RxHead == UART_RxTail dann wird von uart_getc() UART_NO_DATA zurückgegeben, also 0x0100. 0x0100 & 0x0100 --> send Uart hat keine Daten! Hier versteh ich nicht ganz, wie er das hier... if ( c & UART_FRAME_ERROR ) if ( c & UART_OVERRUN_ERROR ) if ( c & UART_BUFFER_OVERFLOW ) ...vergleichen kann. Aber wahrscheinlich hängt das mit meinem Verständnisproblem von ... return (UART_LastRxError << 8) + data; ... zusammen. Wenn der Rückgabewert von uart_getc() fehlerfrei ist, wird der unsigned in mit Hilfe eines Cast in... uart_putc( (unsigned char)c ); ...unsigned char umgewandelt un ausgegeben. Viel Grüße, Klaus
Klaus schrieb: > Zunächst wird data als unsigned char deklariert. Also 7 Bit groß > (0..255). > Dann am Ende der Funktion, wird > > return (UART_LastRxError << 8) + data; > > der Fehler und data zurückgegeben. Was wird hier eigentlich gemacht? ich > versteh das nicht. Ist doch ganz einfach: Der Return Wert der Funktion ist unsigned int. Also 16 Bit Das nächste Zeichen ist ein unsigned char, also 8 Bit An dieser Stelle nimmt er den Fehlercode, so einer existiert (ansonsten eben 0), schiebt ihn um 8 Bits nch rechts und baut in die unteren 8 Bits noch das nächste Zeichen rein. Der Return-Wert der Funktion hat also 16 Bit, also 2 Byte Das höherwertige Byte davon ist ein Fehlercode Das niederwertige Byte ist das nächste Zeichen > In der Test-Demo wird nun c als unsigned int deklariert. Also 32 Bit No. 16 Bit. > if ( c & UART_NO_DATA ) > > ...wenn UART_RxHead == UART_RxTail dann wird von uart_getc() > UART_NO_DATA zurückgegeben, also 0x0100. 0x0100 & 0x0100 --> send Uart > hat keine Daten! Genau. Wenn die Funktion also UART_NO_DATA liefert, dann gab es keinen Fehler oder sonst was, sondern es ist einfach nichts da, was die Funktion hätte liefern können. Auf deutsch: Das Eingangs-Postfach ist leer. > Hier versteh ich nicht ganz, wie er das hier... > > if ( c & UART_FRAME_ERROR ) > > > if ( c & UART_OVERRUN_ERROR ) > > > if ( c & UART_BUFFER_OVERFLOW ) > > ...vergleichen kann. Warum soll er das nicht können? UART_FRAME_ERROR und all die anderen #define sind so gebaut, dass man sie mit dem unsigned int, den die Funktion liefert, einfach nur verunden muss und dann das entsprechende Fehlerbit im höherwertigen Byte übrig bleibt. Ist es gesetzt (und damit das Verundungsergebnis ungleich 0) dann wird der entsprechende if-Zweig genommen > Wenn der Rückgabewert von uart_getc() fehlerfrei ist, wird der unsigned > in mit Hilfe eines Cast in... > > uart_putc( (unsigned char)c ); > > > ...unsigned char umgewandelt un ausgegeben. Genau. Was er im Grunde macht: Er befreit das 'Konglomerat' aus Fehlercodes und emfangenen Zeichen vom Fehlercode, so dass nur das Zeichen übrig bleibt. Er 'strippt' das High-Byte vom c weg. Das High-Byte war aber genau der Fehlercode. Hier wird der unsigned int nicht als Integer-Zahl im eigentlichen Sinne benutzt, sondern als Transport-'Container', mit dem er 2 Bytes aus der Funktion herausschafft. Er hätte sich auch eine Struktur
1 | struct get_Result |
2 | {
|
3 | unsigned char ErrorCode; |
4 | unsigned char nextCharacter; |
5 | };
|
machen können. Aus Gründen, die nur Peter kennt, hat er sich dagegen entschieden und die beiden unsigned char in einem unsigned int händisch zusammengefasst.
Hallo Karl-Heinz, DANKE für deine Antwort. Es wird langsam etwas klarer. Bei einem auftretenden Fehler wird in der Demo ja die Nachricht in den SRAM-Flash geschrieben. Wenn allerdings das Programm läuft, kann ich programmtechnisch ja eh nicht mehr eingreifen. Ich selbst möchte auch ein kleines Programm schreiben, dass die empfangenen Daten vom UART empfängt und auswertet. Ich glaube ich habe das langsam verstanden. Der Ringpuffer, fängt die Daten die vom UART reingeschossen kommen auf und sagt: Nicht so schnell kommt erstmal zu mir und lasst das Programm mal seine restlichen Aufgaben erledigen! Der Puffer ist begrenzt groß und jedes Zeichen wird entsprechend ihrer Ankunft nacheinander in den FIFO abgelegt. Den FIFO muss man etwas losgelöst vom eigentlichen Programm sehen. Erst durch die Funktion uart-getc() holt man sich die Daten zur Bearbeitung. Wenn man bspw. einen String "ABCDEFGHI\r" untersuchen will, schreibt man mit Hilfe der ISR die Zeichen in den Buffer. Ist der Buffer voll, so kommen neue Daten und überschreiben die alten. Mit Hilfe von uart_get() kann man die Daten aus dem Ringbuffer holen und bearbeiten bzw. interpretieren. In meinem Programm kann ich die einzelnen Zeichen wieder in einen Puffer schreiben und auswerten. Bspw. kann ich A als Terminator festlegen und sagen, das wenn "A" detektiert wird die Zeichen bis '\r' ein den lokalen Puffer geschrieben werden. Dann kann ich sie weiterverarbeiten, etc. Wichtig ist das der FIFO nicht zur Analyse oder Interpretation von Daten eingesetzt wird. Zudem muss das Programm so schnell wie möglich die Daten aus dem FIFO holen, so dass keine Daten überschrieben werden. Passt das soweit? In meiner Anwendung will ich die Daten permanent analysieren. Meine Strings sind 100 Zeichen lang. Ich habe zunächst einmal die FLeury Demo verwendet und meine Strings am Hyperterminal dargestellt. Klappt soweit ganz gut. Wenn ich allerdings... if(c & UART_NO_DATA) uart_puts("Keine Daten"); schreibe, erscheint am Hyperterminal eine ganze Reihe "Keine Daten" und dazwischen wieder einer meiner Strings. Dann wieder "Keine Daten", wieder einer meiner Strings, uns so weiter und so fort. Was geht da vor sich? Ist das die "Dauer" bis in meinem Puffer wieder Daten geschrieben werden?
Klaus schrieb: > ganz gut. Wenn ich allerdings... > > if(c & UART_NO_DATA) > uart_puts("Keine Daten"); > > schreibe, erscheint am Hyperterminal eine ganze Reihe "Keine Daten" und > dazwischen wieder einer meiner Strings. Dann wieder "Keine Daten", > wieder einer meiner Strings, uns so weiter und so fort. Was geht da vor > sich? Ganz einfach: Die Übertragung dauert viel länger als die Zeitspanne, in denen dein µC das 'Postfach' abfrägt. Wenn du alle 10 Minuten zu deinem Postfach gehst, der Postler aber nur am Vormittag kommt und ab und zu auch mal am Nachmittag, dann wirst du auch die meiste Zeit mit einem 'keine Post da' in deine Wohnung zurückkehren. Aber: WEnn du mal 1 oder 2 Tage keine Zeit hast, die Post aus dem Postfach zu holen, dann speichert dein Postfach die Briefe in der Zwischenzeit. Und genau das gleiche macht auch diese Ringbuffersteuerung. Wenn dein Programm kurzfristsig anderweitig beschäftigt ist, weil er zb einen String zusammenstellt um ihn zu versenden, dann werden die in der Zwischenzeit über die UART hereinkommenden Zeichen im Ringbuffer zwischengespeichert. Solange bis dein Programm wieder Zeit hat, sich erneut um das Postfach zu kümmern. Und noch eine Analogie greift: Wenn du 2 Monate auf Weltreise bist, dann wird dein Postfach irgendwann voll, weil ja keiner mehr die Post rausholt. Und dann wird es spannend was dann passiert. Beim Ringbuffer werden dann halt alte, noch nicht verarbeitete Daten überschrieben. Das ist genauso gut oder genauso schlecht, als ob diese neuen Daten nicht mehr in den Ringbuffer geladen werden würden. Denn Fehlerfall ist es auf jeden Fall.
Die Vgl. sind klasse, dass kann ich mir auf jeden Fall so merken. Eine Frage noch: Da man programmtechnisch bei den Fehlern eh nichts mehr tun kann, hab ich in meinem Programmteil diese #define UART_FRAME_ERROR #define UART_OVERRUN_ERROR #define UART_BUFFER_OVERFLOW #define UART_NO_DATA einfach weggelassen. Wenn mein Programm zu spät auf die im FIFO befindlichen Daten zugreift, werden sie ja eh überschrieben. Im Anhang hab ich nun den abgeänderten Code von Peter Fleury. Die Nullen, wenn keine Daten vorhanden, filtere ich zuvor raus und erhalte somit meine gewünschten Strings. Kann man das so lassen oder sollte ich noch was beachten/verbessern? VG
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.