libcw/study/serial/arduino_xmt_rcv/main.c

124 lines
2.3 KiB
C
Raw Normal View History

#define BAUD 38400
#include <util/setbaud.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#if defined(__AVR_ATmega2560__)
#define SERIAL_RX_ISR USART0_RX_vect
#elif defined(__AVR_ATmega328__)
#define SERIAL_RX_ISR USART_RX_vect
#else
#error Unknown target processor
#endif
void uart_putchar(char c);
void on_error( const char* msg, uint8_t code )
{
uart_putchar('0' + code );
uart_putchar(':');
for(; *msg; ++msg )
uart_putchar(*msg);
}
// Basic UART setup code from here:
// https://appelsiini.net/2011/simple-usart-with-avr-libc/
void uart_init(void)
{
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= _BV(U2X0);
#else
UCSR0A &= ~(_BV(U2X0));
#endif
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); // 8-bit data
UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0); // Enable RX and TX and RX intertupt enable
}
void uart_putchar(char c)
{
loop_until_bit_is_set(UCSR0A, UDRE0); // Wait until data register empty.
UDR0 = c;
}
void uart_putchar_alt(char c)
{
UDR0 = c;
loop_until_bit_is_set(UCSR0A, TXC0); // Wait until transmission ready.
}
char uart_getchar(void)
{
loop_until_bit_is_set(UCSR0A, RXC0); // Wait until data exists.
return UDR0;
}
#define BUF_N (64) // size of receive buffer
// Note that 'buf_i_idx' must be declared volatile or the
// the compare in the main loop will not work.
volatile int buf_i_idx = 0; // receive buffer input index
int buf_o_idx = 0; // receive buffer output index
// Receive buffer
char buf[ BUF_N ];
ISR(SERIAL_RX_ISR)
{
// receive the incoming byte
buf[ buf_i_idx ] = uart_getchar();
// advance the buffer input index
buf_i_idx = (buf_i_idx + 1) % BUF_N;
}
int main (void)
{
char c;
cli(); // mask all interupts
uart_init(); // setup UART data format and baud rate
sei(); // re-enable interrupts
// set pin 5 of PORTB for output
DDRB |= _BV(DDB5);
uart_putchar('a');
for(;;)
{
// if there are bytes waiting in the receive buffer
if( buf_o_idx != buf_i_idx )
{
// get the waiting byte
c = buf[buf_o_idx];
// advance the buffer output index
buf_o_idx = (buf_o_idx+1) % BUF_N;
// transmit the buffer input index as an asii char.
c += 1;
PORTB ^= _BV(PORTB5);// toggle LED
// transmit
uart_putchar(c);
}
}
}