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 | }
|