Hallo! Die Funktion der Ringbuffer von Fleury hab ich verstanden. Doch an welcher Stelle kommt sinnvollerweise die Abfrage, ob der Buffer gefüllt ist? Und müsste nicht in die Rx-ISR eine Abfrage, ob das String-Ende-anzeigende-Zeichen empfangen wurde? Zur Info: ISR(UART1_RECEIVE_INTERRUPT) { unsigned char tmphead; unsigned char data; unsigned char usr; unsigned char lastRxError; usr = UART1_STATUS; data = UART1_DATA; lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) ); tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK; /* calculate buffer index */ if ( tmphead == UART1_RxTail ) { lastRxError = UART_BUFFER_OVERFLOW >> 8; /* error: receive buffer overflow */ } else { UART1_RxHead = tmphead; /* store new index */ UART1_RxBuf[tmphead] = data; /* store received data in buffer */ } UART1_LastRxError = lastRxError; }
Stephan schrieb: > Doch an welcher Stelle kommt sinnvollerweise die Abfrage, ob der Buffer > gefüllt ist? Die Stelle ist hier:
1 | tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK; /* calculate buffer index */ |
2 | if ( tmphead == UART1_RxTail ) |
Stephan schrieb: > Und müsste nicht in die Rx-ISR eine Abfrage, ob das > String-Ende-anzeigende-Zeichen empfangen wurde? Wozu? Das interessiert die Empfangsroutine überhaupt nicht.
Moment.. wodurch erfährt die Welt ausserhalb der ISR, dass etwas zum Auslesen vorhanden ist?
D.h., durch ständiges Gucken, ob sich DIE Variable verändert hat?
Ja, so ist es. Wobei ein FIFO erst dann wirklich Sinn macht, wenn man eben nicht dauernd nachsehen kann, ob was da ist. Sondern nur ab und zu mal...
Aber wie groß ist die Pause zwischen "ab und zu"? Wenn ich an anderer Stelle im Programm eine *duck, räusper* Totzeit habe, zB 10ms für die Wandlung eines ADC-Wertes, denn ist der Buffer ungünstigstenfalls ratzfatz übervoll?! Schickt es sich, die Abfrage von einem Timer zu "pollen"?
Stephan schrieb: > Aber wie groß ist die Pause zwischen "ab und zu"? Das kommt drauf an, wie viel der Sender in einem Rutsch sendet, wie groß der Buffer ist, mit welcher Baudrate gesendet wird und was das restliche Programm sonst noch so zu tun hat. > Wenn ich an anderer > Stelle im Programm eine *duck, räusper* Totzeit habe, zB 10ms für die > Wandlung eines ADC-Wertes, denn ist der Buffer ungünstigstenfalls > ratzfatz übervoll?! Na ja. Ein ADC Wert dauert keine 10ms. Und bei einer moderaten Baudrate lassen sich in 10ms auch nicht so wahnsinnig viele Zeichen übertragen. 10ms sind für einen mit 1Mhz getakteten µC schon eine sehr lange Zeit. In dieser zeit kann er immerhin rund 9000 Instruktionen ausführen. Bei 10Mhz Taktfrequenz sinds schon ca 90tausend Instruktionen. Das reicht dann auch noch für einen Kaffeplausch zwischendurch :-) > Schickt es sich, die Abfrage von einem Timer zu > "pollen"? Und was machst du dann mit den gepollten Zeichen? richtig. du wirst sie irgendwo zwischenspeichern. Da kannst du auch gleich den Bufferspeicher im Ringbuffer erhöhen. Die Funktion des Ringbuffers an dieser Stelle ist es, dem restlichen Programm ein wenig Zeit zu verschaffen, so dass eine mal etwas längere Programmausführung ohne Nachsehen an den UART Routinen ob was da ist, nicht gleich zum Verlust von Zeichen führt. Das diese Zeit nicht endlos ausgedehnt werden kann, ist auch klar. Denn irgendwo müssen die Zeichen zwischendurch geparkt werden - und irgendwann ist jeder Speicher voll. Dann bleibt nur noch ein Handshake nachzurüsten und dem Sender die Redeerlaubnis zu entziehen oder das Problem mit einem Protokoll zu regeln. Was denkst du eigentlich, warum hier immer alle aufheulen, wenn jemand ein Programm präsentiert, in dem es an allen Ecken und Enden nur so von _delay_ms wimmelt? Es ist nun mal der falsche Weg, wenn man ein Programm schreibt, welches 'scheinbar' mehrere Dinge gleichzeitig überwacht und/oder ausführt.
Abgesehen davon, dass 10ms wirklich ne große Totzeit sind: Bei 38400Baud haste in 10ms 38 Zeichen Empfangen, machste den Buffer also 64 groß. UART ist kein D-Zug ;)
Stephan, der admin hat Dir erklärt, wie man die Überlaufgefahr entschärfen kann. Die Abfrage, ob im Ringpuffer Daten auf die Verwertung warten, plaziert man üblicherweise in die Hauptschleife des Hauptprogramms. Dort kommt der MC immer nur dann vorbei, wenn er gerade nix anderes zu tun hat. ABER: Es kann passieren, dass dann schon mehr als eine Botschaft im Ringpuffer steht. Das "Verwertungsprogramm" kann das nicht erkennen und behandelt die Botschaften, als wäre es eine einzige. Wenn das zu Problem führt, dann kann man z.B. folgendes machen: Man baut einen zweiten Ringpuffer ein, in dem man von jeder eingehenden Botschaft die Länge speichert. Das "Verwertungsgprogramm" kann dort nachgucken, wieviele Botschaften im Empfangs-Ringpuffer stehen, wie lang jede einzelne von ihnen ist und kann dann immer nur so viele Bytes aus dem Empfangspuffer verwerten, wie es der Länge der Botschaft entspricht. Das ist natürlich nicht die einzige Lösungsmöglichkeit; man kann auch an jede Botschaft einen NUL-Character anhängen, um das Ende zu markieren. Nur darf das NUL-Zeichen dann nicht als Datenbyte in der Botschaft vorkommen. Das kann man nur dadurch sicher vermeiden, dass man jedes Datenbyte als zwei Hex-Characters übermittelt. Man muss eben immer betrachten, welche Möglichkeit mit allen Vor- und Nachteilen am besten zum Programm passt. Die Lösung mit dem zweiten Ringpuffer hat sich in meinen Programmen sehr bewährt. Ciao, mare_crisium
Der UART-FIFO speichert einfach nur. Er wertet kein Protokoll aus. Es könnte ja sein, daß ein Block Binärdaten übertragen wird. Das Main holt sich dann jedes Byte ab in einen Paketpuffer und prüft auf das jeweilige Protokoll. Der weitere Puffer ist notwendig, damit auf dem Paket geparst werden kann. In der FIFO kann ja ein Paket genau auf dem Wrap Around liegen, dann kann man nicht mit strcmp(), atoi() usw. parsen. Peter
Peter Dannegger schrieb: > Der UART-FIFO speichert einfach nur. Er wertet kein Protokoll aus. Es > könnte ja sein, daß ein Block Binärdaten übertragen wird. Man könnte es natürlich noch ein wenig anders formulieren: Der Ringbuffer ist ein - wie der Name schon sagt und der TO auch richtig erkannt hat - Buffer, d. h. er speichert einfach nur zwischen. Von "Protokoll auswerten" hat niemand etwas gesagt...
Harald M. schrieb: > ABER: Es kann passieren, dass dann schon mehr als eine Botschaft im > Ringpuffer steht. Das "Verwertungsprogramm" kann das nicht erkennen und > behandelt die Botschaften, als wäre es eine einzige. > > Wenn das zu Problem führt, dann kann man z.B. folgendes machen: Man baut > einen zweiten Ringpuffer ein, in dem man von jeder eingehenden Botschaft > die Länge speichert. Woher weiß denn das UART-Empfangsmodul die Länge der Botschaften, wenn das "Verwertungsprogramm" es nicht erkennen kann? Aus dem Timing?
@Fabian, damit hast Du allerdings recht. In meinen Programmen stelle ich die Botschaftslänge fest, indem ich in der Empfangsroutine die Charcters bis zum NUL-Zeichen zähle. Das ist tatsächlich "doppelt gemoppelt". @peda, nein, der TO erwähnt "Protokoll auswerten" nicht, aber seine Frage schien mir darauf hinauszulaufen. Sozusagen eine vorauseilende Erklärung ;-). Ciao, mare_crisium
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.