Hardware Handshake mit AVR

Gast #2633359
Lesenswert?

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!
Gast #2633459
Lesenswert?

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
}
(Firma: fritzler-avr.de) #2633561
Lesenswert?

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.
Gast #2634090
Lesenswert?

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!
#2634225
Lesenswert?

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.
Gast #2634246
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren