Hallo Leute! Ich habe vor einen Hardware Handshake mit einer UART Schnittstelle eines AVR zu realisieren. Als Handshake-Leitungen nehm ich CTS und RTS. Hardware existiert schon alles. Falls Computer zum Empfang bereit ist setzt er RTS und falls AVR bereit ist setzt er CTS. Falls nun beim AVR der Eingangsbuffer voll ist soll CTS abfallen. Als Ansteuerprogramm der UART-Schnittstelle verwende ich folgendes Programm: http://www.rn-wissen.de/index.php/UART_mit_avr-gcc und davon die Interrupt-Variante. Ich hätte nun die Abfrage der RTS-Leitung in diese ISR (USART_UDRE_vect) Routine und in dieser ISR (USART_RXC_vect) würde ich nun den Füllstand des Eingangsbuffers abfragen. Aber wo soll ich nun den Ausgang für CTS setzen? In einer ISR soll man ja sowas nicht. Oder wie würdet ihr sowas am besten lösen? Schonmal Danke im Vorraus!
Habs nun so wie beschrieben programmiert. geht so. Es bleibt nur das Problem mit dem setzen von CTS (Ausgangspin) in der ISR. Ich hab auch schon überlegt es mit Flags zu lösen. Aber dann bräuchte ich ja auch wieder eine Funktion die das Flag pollt. Weiß denn keiner wie man sowas am besten löst? Hier noch das Programm:
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include "uart.h" |
4 | #include "fifo.h" |
5 | |
6 | #define RTS_PORT PORTD
|
7 | #define RTS_DDR DDRD
|
8 | #define RTS_PIN PIND
|
9 | #define RTS_P PD2
|
10 | |
11 | #define CTS_PORT PORTD
|
12 | #define CTS_DDR DDRD
|
13 | #define CTS_P PD4
|
14 | |
15 | #define UART_BAUD_RATE 19200L
|
16 | #define UART_BAUD_CALC(UART_BAUD_RATE,F_CPU) ((F_CPU)/((UART_BAUD_RATE)*16L)-1)
|
17 | |
18 | #define BUFSIZE_IN 0x40 // Pufferlänge für Empfang
|
19 | static uint8_t inbuf[BUFSIZE_IN]; |
20 | static fifo_t infifo; |
21 | |
22 | #define BUFSIZE_OUT 0x40 // Pufferlänge für Senden
|
23 | static uint8_t outbuf[BUFSIZE_OUT]; |
24 | static fifo_t outfifo; |
25 | |
26 | // UART initialisieren
|
27 | void uart_init (void) { |
28 | |
29 | RTS_DDR &= ~(1<<RTS_P); // RTS ist Eingang |
30 | CTS_DDR |= (1<<CTS_P); // CTS ist Ausgang |
31 | |
32 | // TX (senden), RX (empfangen) und Interruptauslösung für eingehende Daten einschalten
|
33 | UCSRB |= (1<<TXEN) | (1<<RXEN) | (1<<RXCIE); |
34 | |
35 | // Asynchron, 8N1
|
36 | UCSRC |= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1); |
37 | |
38 | uint8_t sreg = SREG; |
39 | cli(); |
40 | |
41 | // Baudrate auswählen
|
42 | UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8); |
43 | UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU); |
44 | |
45 | // enfernen evtl. vorhandener ungültiger Werte
|
46 | do { |
47 | UDR; |
48 | } while(UCSRA & (1<<RXC)); |
49 | |
50 | // Rücksetzen von Receive und Transmit Complete-Flags
|
51 | UCSRA = (1<<RXC) | (1<<TXC); |
52 | |
53 | SREG = sreg; |
54 | |
55 | // FIFOs für Ein- und Ausgabe initialisieren
|
56 | fifo_init (&infifo, inbuf, BUFSIZE_IN); |
57 | fifo_init (&outfifo, outbuf, BUFSIZE_OUT); |
58 | }
|
59 | |
60 | // Empfangene Zeichen werden in Eingabe-FIFO gespeichert und warten dort
|
61 | ISR (USART_RXC_vect) { |
62 | |
63 | fifo_put (&infifo, UDR); |
64 | if(infifo.count >= BUFSIZE_IN) { |
65 | CTS_PORT |= (1<<CTS_P); |
66 | }
|
67 | }
|
68 | |
69 | // Ein Zeichen aus Ausgabe-FIFO lesen und ausgeben
|
70 | // Ist das Zeichen fertig ausgegeben, wird ein neuer IRQ getriggert
|
71 | // Ist der FIFO leer, deaktiviert die ISR ihren eigenen IRQ
|
72 | ISR (USART_UDRE_vect) { |
73 | |
74 | if((outfifo.count > 0) && (!(RTS_PIN & (1<<RTS_P)))) |
75 | UDR = fifo_get_nowait (&outfifo); |
76 | else
|
77 | UCSRB &= ~(1<<UDRIE); |
78 | }
|
79 | |
80 | // Senden eines Zeichens
|
81 | int uart_putc (const uint8_t c) { |
82 | |
83 | int ret = fifo_put (&outfifo, c); |
84 | UCSRB |= (1<<UDRIE); |
85 | return ret; |
86 | }
|
87 | |
88 | // Senden eines Strings
|
89 | void uart_puts (const char *s) { |
90 | |
91 | while (*s) { // so lange *s != NULL |
92 | uart_putc(*s); |
93 | s++; |
94 | }
|
95 | }
|
96 | |
97 | // liest ein Zeichen aus dem FIFO ohne zu warten
|
98 | // gibt 0 zurück falls FIFO leer ist
|
99 | uint8_t uart_getc_nowait (void) { |
100 | |
101 | uint8_t data = (uint8_t) fifo_get_nowait (&infifo); |
102 | CTS_PORT &= ~(1<<CTS_P); |
103 | return data; |
104 | }
|
105 | |
106 | // liest ein Zeichen aus dem FIFO
|
107 | // wartet falls FIFO leer ist
|
108 | uint8_t uart_getc_wait (void) { |
109 | |
110 | uint8_t data = (uint8_t) fifo_get_wait (&infifo); |
111 | CTS_PORT &= ~(1<<CTS_P); |
112 | return data; |
113 | }
|
Hi, warum hast du Bedenken ein Bit in der ISR zu setzen? Mir fallen grad keine Gründe dagegen ein. Geht schnell, blockiert nicht. Grüße
Oh da hast du natürlich recht. Macht ja erst evtl. Probleme wenn mehr Bits gesetzt werden.
Hmm, das ist vermutlich Ansichtssache. Die ISR soll halt so kurz wie möglich sein und so lang wie nötig. Was muss das muss :D Aber so die ein oder andere LED kann man in einer ISR schon mal togglen. Schönen Abend,
Die Kürze ist eher darauf bezogen, dass dort keine Warteschleifen, waits und größere Berechnungen stattfinden sollten (Stringoperationen, division, floats). Bissel Bitwackeln ist kein Problem. Kannst sogar alle Ports umschalten und das juckt nicht weiter.
Ein Problem ist mir bei obigem Code aufgefallen. Falls RTS vom Computer deaktiviert wird und nach einer Zeit wieder aktiviert wird werden die ganzen Daten aus dem Ausgangsbuffer erst gesendet, wenn ein weiteres Zeichen gesendet wird (es muss erst ein neuer ISR (USART_UDRE_vect) getriggert werden). Weiß da jemand wie man sowas am besten löst? Besten Dank schonmal!
Neuere AVR haben nen PinChange IRQ (PCINT) an jedem Pin ;) Ansonsten musste den RTS Pin periodisch pollen oder an den INTx anschließen.
Noch was if(infifo.count >= BUFSIZE_IN) { das könnte unter Umständen ein bischen zu spät sein. Du musst damit rechnen, dass nach dem Setzen von CTS noch ein bischen was reinkommen kann, je nachdem wie auf der Gegenstelle die konkrete Situation ist. Dein AVR hat ja zb auch einen 1 Byte Hardware-Buffer, wenn du ein Zeichen wegschickst. D.h. selbst wenn du vor jedem Raussenden immer das RTS überprüfst, kann es sein, dass die Gegenstelle nach dem Setzen der Leitung noch 1 Zeichen bekommt. An deiner Empfangsseite ist es nicht anders. Wenn du deine CTS auf 'Halt' ziehst, kann es passieren, dass noch was reinkommt. Das solltest du berücksichtigen und CTS nicht erst dann auf 'Halt' stellen, wenn deine FIFO schon auf Knirsch voll ist.
Ok Dann werd ichs wohl mit nem externen INT machen. Der ATmega32 besitzt ja soweit ich laut Datenblatt seh (noch) keinen PinChange IRQ.
Karl Heinz Buchegger schrieb: > Noch was > > if(infifo.count >= BUFSIZE_IN) { > > das könnte unter Umständen ein bischen zu spät sein. Du musst damit > rechnen, dass nach dem Setzen von CTS noch ein bischen was reinkommen > kann, je nachdem wie auf der Gegenstelle die konkrete Situation ist. > Dein AVR hat ja zb auch einen 1 Byte Hardware-Buffer, wenn du ein > Zeichen wegschickst. D.h. selbst wenn du vor jedem Raussenden immer das > RTS überprüfst, kann es sein, dass die Gegenstelle nach dem Setzen der > Leitung noch 1 Zeichen bekommt. An deiner Empfangsseite ist es nicht > anders. Wenn du deine CTS auf 'Halt' ziehst, kann es passieren, dass > noch was reinkommt. Das solltest du berücksichtigen und CTS nicht erst > dann auf 'Halt' stellen, wenn deine FIFO schon auf Knirsch voll ist. Ok werde ich berücksichtigen! Danke für den Tipp
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.