/* * uart.c * * Created on: 01.12.2012 * Author: mikrocontroller.net * web: http://www.mikrocontroller.net * sub Author: Pascal Gollor (www.pgollor.de) */ #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include "uart.h" #include "fifo.h" // erklärt im Artikel "FIFO mit avr-gcc" // FIFO-Objekte und Puffer für die Ein- und Ausgabe #define BUFSIZE_IN 0x0F uint8_t inbuf[BUFSIZE_IN]; fifo_t infifo; #define BUFSIZE_OUT 0xFF uint8_t outbuf[BUFSIZE_OUT]; fifo_t outfifo; void uart_init (unsigned long baudrate) { uint8_t sreg = SREG; uint16_t ubrr = (uint16_t) ((uint32_t) F_CPU/(16UL*baudrate) - 1); UBRRH = (uint8_t) (ubrr>>8); UBRRL = (uint8_t) (ubrr); // Interrupts kurz deaktivieren cli(); // UART Receiver und Transmitter anschalten, Receive-Interrupt aktivieren // Data mode 8N1, asynchron UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE); UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); // Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) do { // UDR auslesen (Wert wird nicht verwendet) UDR; } while (UCSRA & (1 << RXC)); // Rücksetzen von Receive und Transmit Complete-Flags UCSRA = (1 << RXC) | (1 << TXC); // Global Interrupt-Flag wieder herstellen SREG = sreg; // FIFOs für Ein- und Ausgabe initialisieren fifo_init (&infifo, inbuf, BUFSIZE_IN); fifo_init (&outfifo, outbuf, BUFSIZE_OUT); } // Empfangene Zeichen werden in die Eingangs-FIFO gespeichert und warten dort ISR (USART_RXC_vect) { _inline_fifo_put (&infifo, UDR); } // Ein Zeichen aus der Ausgabe-FIFO lesen und ausgeben // Ist das Zeichen fertig ausgegeben, wird ein neuer SIG_UART_DATA-IRQ getriggert // Ist die FIFO leer, deaktiviert die ISR ihren eigenen IRQ. ISR (USART_UDRE_vect) { if (outfifo.count > 0) UDR = _inline_fifo_get (&outfifo); else UCSRB &= ~(1 << UDRIE); } int uart_putc (const uint8_t c) { int ret = fifo_put (&outfifo, c); UCSRB |= (1 << UDRIE); return ret; } void uart_puts (const char *s) { do { uart_putc (*s); } while (*s++); } int uart_getc_nowait (void) { return fifo_get_nowait (&infifo); } uint8_t uart_getc_wait (void) { return fifo_get_wait (&infifo); } //------------------------------------------------------------------------------ void usart_write_P (const char *Buffer,...) { va_list ap; va_start (ap, Buffer); int format_flag; char str_buffer[10]; char str_null_buffer[10]; char move = 0; char Base = 0; int tmp = 0; //char by; uint8_t by; char *ptr; //Ausgabe der Zeichen for(;;) { by = pgm_read_byte(Buffer++); if(by==0) break; // end of format string if (by == '%') { by = pgm_read_byte(Buffer++); if (isdigit(by)>0) { str_null_buffer[0] = by; str_null_buffer[1] = '\0'; move = atoi(str_null_buffer); by = pgm_read_byte(Buffer++); } switch (by) { case '%': usart_write_char('%'); break; case 's': ptr = va_arg(ap,char *); while(*ptr) { usart_write_char(*ptr++); } break; case 'b': Base = 2; goto ConversionLoop; case 'c': //Int to char format_flag = va_arg(ap,int); usart_write_char (format_flag++); break; case 'i': Base = 10; goto ConversionLoop; case 'o': Base = 8; goto ConversionLoop; case 'x': Base = 16; //**************************** ConversionLoop: //**************************** itoa(va_arg(ap,int),str_buffer,Base); int b=0; while (str_buffer[b++] != 0){}; b--; if (b<move) { move -=b; for (tmp = 0;tmp<move;tmp++) { str_null_buffer[tmp] = '0'; } //tmp ++; str_null_buffer[tmp] = '\0'; strcat(str_null_buffer,str_buffer); strcpy(str_buffer,str_null_buffer); } usart_write_str (str_buffer); move =0; break; } } else { usart_write_char ( by ); } } va_end(ap); } //----------------------------------------------------------------------------