Forum: Mikrocontroller und Digitale Elektronik Hardware Handshake mit AVR


von Handshaker (Gast)


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!

von Handshaker (Gast)


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
}

von Benjamin U. (utzus)


Lesenswert?

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

von Handshaker (Gast)


Lesenswert?

Oh da hast du natürlich recht.
Macht ja erst evtl. Probleme wenn mehr Bits gesetzt werden.

von Benjamin U. (utzus)


Lesenswert?

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,

von Mw E. (Firma: fritzler-avr.de) (fritzler)


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.

von Handshaker (Gast)


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!

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Neuere AVR haben nen PinChange IRQ (PCINT) an jedem Pin ;)
Ansonsten musste den RTS Pin periodisch pollen oder an den INTx 
anschließen.

von Karl H. (kbuchegg)


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.

von Handshaker (Gast)


Lesenswert?

Ok
Dann werd ichs wohl mit nem externen INT machen.
Der ATmega32 besitzt ja soweit ich laut Datenblatt seh (noch) keinen 
PinChange IRQ.

von Handshaker (Gast)


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

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
Noch kein Account? Hier anmelden.