#include <avr/io.h> #include <stdio.h> #ifndef NDEBUG # if !defined(F_DEBUG_UART) && !defined(F_CPU) # error F_DEBUG_UART frequency or F_CPU frequency should be defined! # endif # ifndef F_DEBUG_UART # define F_DEBUG_UART F_CPU # endif # ifndef DEBUG_NUART # error DEBUG_NUART should be defined! # endif # define __CONC3(X, Y, Z) X ## Y ## Z # define _CONC3(X, Y, Z) __CONC3(X, Y, Z) // _CONC3(UDRE, DEBUG_NUART,) does not works # define _UDRE (_CONC3(UDR, E, DEBUG_NUART)) # define _UDR (_CONC3(UDR, DEBUG_NUART,)) # define _UBRRH (_CONC3(UBRR, DEBUG_NUART, H)) # define _UBRRL (_CONC3(UBRR, DEBUG_NUART, L)) # define _UCSRA (_CONC3(UCSR, DEBUG_NUART, A)) # define _UCSRB (_CONC3(UCSR, DEBUG_NUART, B)) # define _UCSRC (_CONC3(UCSR, DEBUG_NUART, C)) # define _RXEN (_CONC3(RXEN, DEBUG_NUART,)) # define _TXEN (_CONC3(TXEN, DEBUG_NUART,)) # define _UCSZ0 (_CONC3(UCSZ, DEBUG_NUART, 0)) # define _U2X (_CONC3(U2X, DEBUG_NUART,)) # define DEBUG_UART_SUPPORT() \ static int debug_uart_putchar(char c, FILE *stream); \ static FILE mystdout = FDEV_SETUP_STREAM(debug_uart_putchar, NULL, _FDEV_SETUP_WRITE); \ static int debug_uart_putchar(char c, FILE *stream) \ { \ while (0 == (_UCSRA & (1<<_UDRE))) ; \ _UDR = c; \ return (0); \ } /* 8 bits data, 1 stop bit, 9600 kbps, async */ # define INIT_DEBUG_UART() do { \ stdout = &mystdout; \ _UCSRC = 0x06; \ _UCSRA = 0x00; \ _UCSRB = 0x18; /* receive, transmit, no interrupts */ \ uint16_t ubrr = (F_DEBUG_UART/16/9600-1); \ _UBRRL = (unsigned char)ubrr; \ _UBRRH = (unsigned char)(ubrr>>8); \ } while (0) # define DEBUG_UART_PRN(...) printf(__VA_ARGS__) #else # define DEBUG_UART_SUPPORT() # define INIT_DEBUG_UART() # define DEBUG_UART_PRN(...) #endifSave it into debug_uart.h, for example.
What you need to use it, it's only defining F_DEBUG_UART or F_CPU, DEBUG_NUART and calling 3 macros: DEBUG_UART_SUPPORT() on module level (it generates code, so call it only once!), INIT_DEBUG_UART() to init UART and DEBUG_UART_PRN(...) where you need message printing. The example is:
#define F_DEBUG_UART 7372800 #define DEBUG_NUART 0 #include "debug_uart.h" DEBUG_UART_SUPPORT(); int main(void) { INIT_DEBUG_UART(); DEBUG_UART_PRN("Hello world, %d\n", 99); ... so on ...F_DEBUG_UART is the exact amount of the system oscillator frequency to calculate UART baud rate. Default value is equals to F_CPU, but it's possible, that you have value of fosc = 7.3728MHz (see AVR Datasheet about "Examples of UBRR settings") and you use in the Makefile F_CPU value as 8MHz - if you use 8MHz for UBRR calculation too, you will get errors in transmission! So use for F_DEBUG_UART exact values only!
DEBUG_NUART defined number of UART. If you define NDEBUG, all macros will be empty - you don't need to delete it's calls. For more information see help on WinAVR.