#include #include #ifndef SIGNAL #include #endif // SIGNAL #include "suart.h" // Folgende Zeile einkommentieren, falls FIFO verwendet werden soll #include "fifo.h" #define F_CPU 1000000 #define BAUDRATE 38400 #define nop() __asm volatile ("nop") #ifdef SUART_TXD #define SUART_TXD_PORT PORTA #define SUART_TXD_DDR DDRA #define SUART_TXD_BIT PA5 static volatile uint16_t outframe; #endif // SUART_TXD #ifdef SUART_RXD #define SUART_RXD_PORT PORTA #define SUART_RXD_PIN PINA #define SUART_RXD_DDR DDRA #define SUART_RXD_BIT PA6 static volatile uint16_t inframe; static volatile uint8_t inbits, received; #ifdef _FIFO_H_ #define INBUF_SIZE 4 static uint8_t inbuf[INBUF_SIZE]; fifo_t infifo; #else // _FIFO_H_ static volatile uint8_t indata; #endif // _FIFO_H_ #endif // SUART_RXD // Initialisierung für einen ATmega8 // Für andere AVR-Derivate sieht dies vermutlich anders aus: // Registernamen ändern sich (zB TIMSK0 anstatt TIMSK, etc). void uart_init() { uint8_t tifr = 0; uint8_t sreg = SREG; cli(); // Mode #4 für Timer1 // und volle MCU clock // IC Noise Cancel // IC on Falling Edge TCCR1A = 0; TCCR1B = (1 << WGM12) | (1 << CS10) | (0 << ICES1) | (1 << ICNC1); // OutputCompare für gewünschte Timer1 Frequenz OCR1A = (uint16_t) ((uint32_t) F_CPU/BAUDRATE); #ifdef SUART_RXD SUART_RXD_DDR &= ~(1 << SUART_RXD_BIT); SUART_RXD_PORT |= (1 << SUART_RXD_BIT); TIMSK0 |= (1 << ICIE1); tifr |= (1 << ICF1) | (1 << OCF1B); #else TIMSK0 &= ~(1 << ICIE1); #endif // SUART_RXD #ifdef SUART_TXD tifr |= (1 << OCF1A); SUART_TXD_PORT |= (1 << SUART_TXD_BIT); SUART_TXD_DDR |= (1 << SUART_TXD_BIT); outframe = 0; #endif // SUART_TXD TIFR1 = tifr; SREG = sreg; #ifdef _FIFO_H_ fifo_init (&infifo, inbuf, INBUF_SIZE); #endif // _FIFO_H_ } // TRANSMITTER #ifdef SUART_TXD void uart_putc (const char c) { do { sei(); nop(); cli(); // yield(); } while (outframe); // frame = *.P.7.6.5.4.3.2.1.0.S S=Start(0), P=Stop(1), *=Endemarke(1) outframe = (3 << 9) | (((uint8_t) c) << 1); TIMSK0 |= (1 << OCIE1A); TIFR1 = (1 << OCF1A); sei(); } #endif // SUART_TXD #ifdef SUART_TXD SIGNAL (SIG_OUTPUT_COMPARE1A) { uint16_t data = outframe; if (data & 1) SUART_TXD_PORT |= (1 << SUART_TXD_BIT); else SUART_TXD_PORT &= ~(1 << SUART_TXD_BIT); if (1 == data) { TIMSK0 &= ~(1 << OCIE1A); } outframe = data >> 1; } #endif // SUART_TXD // RECEIVER #ifdef SUART_RXD SIGNAL (SIG_INPUT_CAPTURE1) { uint16_t icr1 = ICR1; uint16_t ocr1a = OCR1A; // Eine halbe Bitzeit zu ICR1 addieren (modulo OCR1A) und nach OCR1B uint16_t ocr1b = icr1 + ocr1a/2; if (ocr1b >= ocr1a) ocr1b -= ocr1a; OCR1B = ocr1b; TIFR1 = (1 << OCF1B); TIMSK0 = (TIMSK0 & ~(1 << ICIE1)) | (1 << OCIE1B); inframe = 0; inbits = 0; } #endif // SUART_RXD #ifdef SUART_RXD SIGNAL (SIG_OUTPUT_COMPARE1B) { uint16_t data = inframe >> 1; if (SUART_RXD_PIN & (1 << SUART_RXD_BIT)) data |= (1 << 9); uint8_t bits = inbits+1; if (10 == bits) { if ((data & 1) == 0) if (data >= (1 << 9)) { #ifdef _FIFO_H_ _inline_fifo_put (&infifo, data >> 1); #else indata = data >> 1; #endif // _FIFO_H_ received = 1; } TIMSK0 = (TIMSK0 & ~(1 << OCIE1B)) | (1 << ICIE1); TIFR1 = (1 << ICF1); } else { inbits = bits; inframe = data; } } #endif // SUART_RXD #ifdef SUART_RXD #ifdef _FIFO_H_ int uart_getc_wait() { return (int) fifo_get_wait (&infifo); } int uart_getc_nowait() { return fifo_get_nowait (&infifo); } #else // _FIFO_H_ int uart_getc_wait() { while (!received) {} received = 0; return (int) indata; } int uart_getc_nowait() { if (received) { received = 0; return (int) indata; } return -1; } #endif // _FIFO_H_ #endif // SUART_RXD