Guten Morgen, ich habe den Auftrag bekommen mich mal mit XON/XOFF zu beschäftigen und durch meine Internetsuche habe ich auch schon herausgefunden wofür es gut ist dennoch habe ich nicht wirklich etwas gefunden was mir bei der Programmierung helfen könnte. Mir ist unklar ob XON/XOFF eine feste Funktion ist oder ob man sie einbinden muss. Ich benutze den ATmega 128 und möchte mit einem PC kommunizieren. Ich bin für jede art von Info über XON/XOFF sehr dankbar. MFG Philipp
Hast Du auch da schon geschaut: http://de.wikipedia.org/wiki/Xon#Software-Flusskontrolle.2C_Software-Handshake.2C_Software-Protokoll_oder_X-ON.2FX-OFF Da steht eigentlich ausreichend genau beschrieben, wie es funktioniert...
Ja da war ich auch schon aber es hat mir nicht sehr viel geholfen. Somit wusste ich zwar wofür XON/XOFF benötigt wird aber nicht wie man es in seinem Programm implementiert! Könnte mir jemand ein Beispielprogramm in Verbindung mit XON/XOFF zukommen lassen?
Philipp wrote: > Ja da war ich auch schon aber es hat mir nicht sehr viel geholfen. Somit > wusste ich zwar wofür XON/XOFF benötigt wird aber nicht wie man es in > seinem Programm implementiert! > > Könnte mir jemand ein Beispielprogramm in Verbindung mit XON/XOFF > zukommen lassen? Du mußt in Deinem Programm einen Empfangspuffer einrichten, in den die empfangenen Zeichen zwischengespeichert werden (z.B. ein Fifo); dort mußt Du den "Füllgrad" beobachten, durch eine geeignete Funktion, die Dir meldet, wenn der Puffer z.B. zu 95% gefüllt ist; sobald diese Situation auftritt, sendest Du das X-Off-Zeichen zum Sender; dieser reagiert darauf und unterbindet weiteres Senden, solange, bis Du das X-On-Zeichen sendest. Das tust Du z.B. dann, wenn der Füllgrad 80% beträgt (hängt aber stark von der Applikation ab). Zu beachten ist die Reaktionsgeschwindigkeit des Senders bzw. wieviele Zeichen er noch senden könnte, wenn Du X-Off abgeschickt hast. Insofern muß ein Empfangspuffer immer noch Platz für einige Zeichen haben, auch wenn das X-Off abgeschickt wurde; je nach Sendegeschwindigkeit und Puffergröße muß also dieser "95%-Wert" angepaßt werden: je kleiner der Puffer und je höher die Bitrate und je größer die Reaktionszeit des Senders, umso kleiner dieser Prozentwert.
Da ist doch nichts schweres daran: Wenn dein Programm möchte, dass die Gegenstelle aufhört zu senden, dann schickt es das Zeichen XOFF über die Leitung. Wenn dein Programm dann wieder Zeichen aufnehmen kann, schickt es XON. Das einzige worauf du aufpassen musst, ist dass nach dem Senden von XOFF noch ein/zwie Zeichen kommen können (je nachdem wie schnell die Gegenstelle auf den XOFF reagiert). Mehr ist das nicht. Bsp: Dein Programm hat einen Input-Buffer in dem es zunächst die empfangenen Zeichen zwischenspeichert. Jetzt ist dein Programm anderweitig beschäftig und hat keine Zeit die Zeichen aus diesem Buffer abzuholen -> der Buffer füllt sich zusehends. Ist der Buffer zu 80% gefüllt, so schickt die Empfangsroutine einen XOFF. Daraufhin stellt die Gegenstelle das Senden ein und dein Programm läuft nicht Gefahr, dass der Buffer überläuft. (Dazu implementiert man die Empfangsroutine am besten in eine ISR, die beim Empfang eines Zeichens aufgerufen wird). Irgendwann hat dann dein Hauptprogramm wieder Zeit die empfangenen Zeichen abzuholen. Die Funktion die ein Zeichen aus dem Buffer holt, überprüft auch noch, ob ein XOFF gesendet wurde und wenn die Bufferauslastung durch das Abholen von Zeichen wieder unter 10% gesunken ist, sendet sie einen XON an die Gegenstelle. Selbes Spielchen in der umgekehrten Richtung: Wenn die Empfangsroutine einen XOFF empfängt, heist das, das die Gegenstelle möchte, dass dein Programm das Senden einstellt. Kriegt deine Empfangsroutine einen XOFF, dann setzt sie ein Flag, das der Senderoutine verbietet das nächste Zeichen zu senden. Empfängt sie ein XON, dann setzt sie dieses Flag wieder zurück. Wie das im Detail implementiert wird, hängt stark von deiner momentanen Architektur ab. Das Prinzip ist aber immer: Du redest mit deinem Freund. Plötzlich ruft dein Freund: "Warte mal" (XOFF), macht irgendwas anderes und wenn er wieder aufnahmebereit ist, ruft er dir zu: "OK, weiter" (XON)
Soweit so gut aber macht er das automatisch? Also führt er automatisch den XOFF befehl aus wenn der Puffer voll ist? Wenn ja kann man dem Programm sagen das wenn der Puffer zu 50% voll ist das er dann das XOFF zeichen sendet? Du hast auch gesagt "(Dazu implementiert man die Empfangsroutine am besten in eine ISR, die beim Empfang eines Zeichens aufgerufen wird)" kannst du mir das vielleicht etwas genauer erklären?
Mein hauptsächliches Problem besteht darin das ich nicht weiß WIE ich ein XON/XOFF Zeichen sende also die Syntax für diese Funktion.
>Soweit so gut aber macht er das automatisch? ... >Mein hauptsächliches Problem besteht darin das ich nicht weiß WIE ich >ein XON/XOFF Zeichen sende also die Syntax für diese Funktion. Es gibt keine "Syntax" für diese Funktion. Das wirst du komplett selber programmieren müssen. Oliver
Das sind einfach zwei ASCII-Steuerzichen, wie es im Wikipedia-Artikel steht, die werden genau wie jeder andere Buchstabe gesendet: "DC1 (oft als X-ON bezeichnet, engl. für Transmission ON, Zeichencodierung 11hex, PC-Tastatur: Strg-Q) und DC3 (oft als X-OFF bezeichnet, engl. für Transmission OFF, Zeichencodierung 13hex PC-Tastatur: Strg-S)." Ascii-Tabelle hier: http://de.wikipedia.org/wiki/ASCII
Vielen Dank erstmal für die schnellen Antworten sie haben mir echt geholfen jetzt wäre nur noch ein Beispiel-Programm das I-Töpfelchen! Mit freundlichen Grüßen und Dank Philipp
Philipp wrote: > Soweit so gut aber macht er das automatisch? Also führt er automatisch > den XOFF befehl aus wenn der Puffer voll ist? Wenn ja kann man dem > Programm sagen das wenn der Puffer zu 50% voll ist das er dann das XOFF > zeichen sendet? > > Du hast auch gesagt "(Dazu implementiert man die Empfangsroutine > am besten in eine ISR, die beim Empfang eines Zeichens > aufgerufen wird)" kannst du mir das vielleicht etwas genauer erklären? Dann solltest du dich mal grundsätzlich mit der Funktion der UART beschäftigen: * Wie sendet man Zeichen, welche Möglichkeiten gibt es dafür * Wie empfängt man Zeichen, welche Möglichkeiten gibt es dafür In beiden Fällen gibt es die Straightforward Sede und Empfangsfunktionen, die in das Hauptprogramm eingebaut werden. Die etwas ausgefuchstere Version ist es, wenn beides über Interrupts gesteuert abläuft. Und genau die brauchst du. Schau dir mal die UART Library von Peter Fleury an (danach googeln). Wenn ich mich richtig erinnere arbeitet die über Interrupts.
Oder die procyon avrlib. Die bietet interrupts und buffer, nur eben kein xon/xoff. Das musst du dann noch selber dranbasteln. Oliver
Allerdings: Wenn man eine bestehende Lib studieren muss, ist es wohl besser das ganze neu zu schreiben. Bis man raus hat, wo mann eingreifen muss, hat man das auch schon neu gemacht und dann weiss man was man hat :-) Eine bestehende Lib studieren, wie die Dinge gemacht werden ist aber immer eine gute Idee.
Christoph Db1uq wrote: > Das sind einfach zwei ASCII-Steuerzichen, wie es im Wikipedia-Artikel > steht, die werden genau wie jeder andere Buchstabe gesendet Wobei ich mich immer schon mal gefragt habe: Wie wird das gehandhabt? Angenommen mein Gegenüber schickt einen XOFF, möchte also von mir nicht 'belästigt' werden. Jetzt komm ich aber selber in Zeit/Speichernot und will ihm einen XOFF schicken. Darf ich das dann? Sein XOFF steht ja immer noch und eigentlich besteht ja Sendeverbot. Mir ist schon klar, dass die Antwort logischerweise nur 'ja, ich darf senden' lauten kann. Aber eigenartigerweise wird diese Thematik nie irgendwo erwähnt :-) Das Senden von XON, XOFF muss immer den kurzen Weg durch alle Buffer nehmen und auch ein bestehender XOFF von der Gegenstelle wird ignoriert. Ansonsten könnte man sich leicht in einen Deadlock hineinmanövrieren.
>Darf ich das dann? Sein XOFF steht ja immer >noch und eigentlich besteht ja Sendeverbot. Es besteht nur ein Sendeverbot für Daten. xon/xoff selber sind aber keine Daten, sondern Steuerzeichen. So würde ich das interpretieren ... Das braucht aber heutzutage eh keiner mehr. Oliver
Philipp wrote:
> Hat nicht jemand ein beispiel Programm für mich?
Sag blos du hast in den vergangenen Stunden die 3 Variablen
und 5 Zeilen zusätzlichen Code nicht hingekriegt?
Eine (ungetestete) Implementierung einer gebufferten UART
Empfangseinheit ohne XON/XOFF könnte zb. so aussehen:
1 | #define BUFFER_LEN 20
|
2 | |
3 | char Buffer[BUFFER_LEN]; |
4 | |
5 | volatile uint8_t NextWriteBufferPos; |
6 | volatile uint8_t NextReadBufferPos; |
7 | volatile uint8_t CharsInBuffer; |
8 | |
9 | void SendImmidate( char c ) |
10 | {
|
11 | while (!(UCSRA & (1<<UDRE))) |
12 | ;
|
13 | |
14 | UDR = c; |
15 | }
|
16 | |
17 | // wird aufgerufen, wenn ein Zeichen von der UART empfangen wurde
|
18 | ISR( USART_RXC_vect ) |
19 | {
|
20 | Buffer[NextBufferPos] = UDR; |
21 | |
22 | NextWriteBufferPos = NextWriteBufferPos + 1 ) % BUFFER_LEN; |
23 | CharsInBuffer++; |
24 | }
|
25 | |
26 | char GetUartChar() |
27 | {
|
28 | if( CharsInBuffer == 0 ) |
29 | return 0; |
30 | |
31 | char NextChar = Buffer[NextReadBufferPos]; |
32 | NextReadBufferPos = ( NextReadBufferPos + 1 ) % BUFFER_LEN; |
33 | CharsInBuffer--; |
34 | |
35 | return NextChar; |
36 | }
|
Wird ein Zeichen empfangen, wird die Interrupt Funktion aufgerufen welche das Zeichen in einen Buffer stellt. Das Hauptprogramm nutzt die Funktion GetUartChar() um sich die Zeichen dann in aller Gemütsruhe aus diesem Buffer zu holen. Soweit so gut. Jetzt kann es natürlich passieren, dass das Hauptprogramm die Zeichen nicht abholt. D.h. die Empfangsfunktion prüft, ob der Buffer sich füllt und wenn eine kritische Grenze überschritten wird, dann schickt sie an die Gegenstelle einen XOFF. Die Aufhebung erfolgt in der Zeichen-Abhol-Funktion. Wurde ein Xoff gesendet und sinkt der Füllgrad wieder unter eine Grenze, dann wird mit einem XON der Gegenstelle wieder signalisiert, dass sie weitersenden darf. Und genau das wird straightforward, so wie es in einigen Postings vorher und auf dem Wiki Artikel erklärt wurde, dazu implementiert.
1 | #define XON 0x11
|
2 | #define XOFF 0x13
|
3 | |
4 | #define BUFFER_LEN 20
|
5 | #define HIGH_WATER 15
|
6 | #define LOW_WATER 5
|
7 | |
8 | char Buffer[BUFFER_LEN]; |
9 | |
10 | volatile uint8_t NextWriteBufferPos; |
11 | volatile uint8_t NextReadBufferPos; |
12 | volatile uint8_t CharsInBuffer; |
13 | volatile uint8_t XoffSent; |
14 | |
15 | void SendImmidate( char c ) |
16 | {
|
17 | while (!(UCSRA & (1<<UDRE))) |
18 | ;
|
19 | |
20 | UDR = c; |
21 | }
|
22 | |
23 | // wird aufgerufen, wenn ein Zeichen von der UART empfangen wurde
|
24 | ISR( USART_RXC_vect ) |
25 | {
|
26 | Buffer[NextBufferPos] = UDR; |
27 | |
28 | NextWriteBufferPos = NextWriteBufferPos + 1 ) % BUFFER_LEN; |
29 | CharsInBuffer++; |
30 | |
31 | if( CharsInBuffer == HIGH_WATER ) { |
32 | SendImmidate( XOFF ); |
33 | XoffSent = 1; |
34 | }
|
35 | }
|
36 | |
37 | char GetUartChar() |
38 | {
|
39 | if( CharsInBuffer == 0 ) |
40 | return 0; |
41 | |
42 | char NextChar = Buffer[NextReadBufferPos]; |
43 | NextReadBufferPos = ( NextReadBufferPos + 1 ) % BUFFER_LEN; |
44 | CharsInBuffer--; |
45 | |
46 | if( XoffSent && CharsInBuffer < LOW_WATER ) { |
47 | SendImmidiate( XON ); |
48 | XoffSent = 0; |
49 | }
|
50 | |
51 | return NextChar; |
52 | }
|
Die Sendeeinheit ist sogar noch einfacher: In der Empfangsroutine wird zusätzlich noch überprüft ob von der Gegenstelle ein XON oder XOFF gekommen ist. Wenn ja wird einfach nur ein Flag gesetzt. In der Zeichen-Sende-Funktion wird noch getestet, ob das Senden zulässig ist, und fertig:
1 | #define XON 0x11
|
2 | #define XOFF 0x13
|
3 | |
4 | #define BUFFER_LEN 20
|
5 | #define HIGH_WATER 15
|
6 | #define LOW_WATER 5
|
7 | |
8 | char Buffer[BUFFER_LEN]; |
9 | |
10 | volatile uint8_t NextWriteBufferPos; |
11 | volatile uint8_t NextReadBufferPos; |
12 | volatile uint8_t CharsInBuffer; |
13 | volatile uint8_t XoffSent; |
14 | volatile uint8_t CanSend; |
15 | |
16 | void SendImmidate( char c ) |
17 | {
|
18 | while (!(UCSRA & (1<<UDRE))) |
19 | ;
|
20 | |
21 | UDR = c; |
22 | }
|
23 | |
24 | // wird aufgerufen, wenn ein Zeichen von der UART empfangen wurde
|
25 | ISR( USART_RXC_vect ) |
26 | {
|
27 | char c = UDR; |
28 | |
29 | if( c == XON ) { |
30 | CanSend = 1; |
31 | return; |
32 | }
|
33 | if( c == XOFF ) { |
34 | CanSend = 0; |
35 | return; |
36 | }
|
37 | |
38 | Buffer[NextBufferPos] = UDR; |
39 | |
40 | NextWriteBufferPos = NextWriteBufferPos + 1 ) % BUFFER_LEN; |
41 | CharsInBuffer++; |
42 | |
43 | if( CharsInBuffer == HIGH_WATER ) { |
44 | SendImmidate( XOFF ); |
45 | XoffSent = 1; |
46 | }
|
47 | }
|
48 | |
49 | char GetUartChar() |
50 | {
|
51 | if( CharsInBuffer == 0 ) |
52 | return 0; |
53 | |
54 | char NextChar = Buffer[NextReadBufferPos]; |
55 | NextReadBufferPos = ( NextReadBufferPos + 1 ) % BUFFER_LEN; |
56 | CharsInBuffer--; |
57 | |
58 | if( XoffSent && CharsInBuffer < LOW_WATER ) { |
59 | SendImmidiate( XON ); |
60 | XoffSent = 0; |
61 | }
|
62 | |
63 | return NextChar; |
64 | }
|
65 | |
66 | void SendUartChar( char c ) |
67 | {
|
68 | while( !CanSend ) |
69 | ;
|
70 | SendImmidate( c ); |
71 | }
|
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.