#ifndef UART_H
#define UART_H
#include <avr/io.h>
#ifndef UART_BUFFER_SIZE
#define UART_BUFFER_SIZE 128
#endif
// Ring buffer - struct with an array, head and tail
typedef volatile struct uart_ringbuf
{
uint8_t buffer[UART_BUFFER_SIZE];
uint8_t head;
uint8_t tail;
} uart_ringbuf_t;
// Add data to ring buffer, returns false (0) on full
uint8_t uart_ringbuf_push(uart_ringbuf_t* buf, uint8_t v);
// Tries to remove data from ring buffer, returns false (0) on empty
uint8_t uart_ringbuf_trypop(uart_ringbuf_t* buf, uint8_t* out);
// Returns the ammount of data in the buffer
uint8_t uart_ringbuf_length(uart_ringbuf_t* buf);
// initializes that uart registers for sending and receiving
void uart_init(uint32_t baudrate, uint8_t doublespeed);
// Read char from buf, returns 0 if empty
uint8_t uart_read();
// Add string to buffer and start sending if not started already
void uart_send(char* str);
// Add string to buffer and start sending if not started already
void uart_sendn(char* str, uint8_t n);
// Add char to buffer and start sending if not started already
void uart_sendc(char c);
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
// Ring buffer
// ========== ========== ========== ========== ========== ==========
// Add data to ring buffer, returns false (0) on full
uint8_t uart_ringbuf_push(uart_ringbuf_t* buf, uint8_t v)
{
uint8_t n = buf->head + 1; // next pos
if (n >= UART_BUFFER_SIZE) // loop to start
n = 0;
if (n == buf->tail) // buf full?
return 0;
buf->buffer[buf->head] = v; // write new data
buf->head = n; // write new pos
return 1;
}
// Tries to remove data from ring buffer, returns false (0) on empty
uint8_t uart_ringbuf_trypop(uart_ringbuf_t* buf, uint8_t* out)
{
if (buf->head == buf->tail) // buf empty?
return 0;
uint8_t n = buf->tail + 1; // next pos
if (n >= UART_BUFFER_SIZE) // loop to start
n = 0;
*out = buf->buffer[buf->tail]; // write new data
buf->tail = n; // write new pos
return 1;
}
// Returns the ammount of data in the buffer
uint8_t uart_ringbuf_length(uart_ringbuf_t* buf)
{
if (buf->head == buf->tail) // empty buf
return 0;
else if (buf->tail < buf->head) // tail behind head
return (UART_BUFFER_SIZE - buf->head + buf->tail);
else return buf->tail - buf->head; // tail after head
}
// Uart
// ========== ========== ========== ========== ========== ==========
// Receive buffer
uart_ringbuf_t rxBuf;
// Send buffer
uart_ringbuf_t txBuf;
// Send status
volatile uint8_t txStatus = 0;
// If txBuf has chars start sending them
void uart_internal_sendchar()
{
// check if buffer has data
uint8_t tosend;
if (uart_ringbuf_trypop(&txBuf, &tosend))
{
txStatus = 1; // sending data
UDR0 = tosend; // add char to send buffer
}
// no data left to send
else txStatus = 0;
}
// Returns the value for UBRRn for the chosen baudrate and U2Xn (double speed)
uint16_t uart_ubrrn_from_baud(uint32_t baudrate, uint8_t u2xn)
{
if (u2xn)
{
switch (baudrate)
{
case 2400: return 832;
case 4800: return 416;
case 9600: return 207;
case 14400: return 138;
case 19200: return 103;
case 28800: return 68;
case 38400: return 51;
case 57600: return 34;
case 76800: return 25;
case 115200: return 16;
case 230400: return 8;
case 250000: return 7;
case 500000: return 3;
case 1000000: return 1;
default: return 16; // 115200
}
}
switch (baudrate)
{
case 2400: return 416;
case 4800: return 207;
case 9600: return 103;
case 14400: return 68;
case 19200: return 51;
case 28800: return 34;
case 38400: return 25;
case 57600: return 16;
case 76800: return 12;
case 115200: return 8;
case 230400: return 3;
case 250000: return 3;
case 500000: return 1;
case 1000000: return 0;
default: return 8; // 115200
}
}
// initializes that uart registers for sending and receiving
void uart_init(uint32_t baudrate, uint8_t doublespeed)
{
// init buffers
rxBuf.head = 0; rxBuf.tail = 0;
txBuf.head = 0; txBuf.tail = 0;
// set double speed mode
if (doublespeed)
UCSR0A |= (1 << U2X0);
// Enable transmiter and receiver
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
// Enable interrupts
UCSR0B |= (1 << TXCIE0) | (1 << RXCIE0);
// Set baudrate
UBRR0 = uart_ubrrn_from_baud(baudrate, doublespeed);
}
// Read char from buf, returns 0 if empty
uint8_t uart_read()
{
uint8_t c;
if (uart_ringbuf_trypop(&rxBuf, &c))
return c;
return 0;
}
// Add string to buffer and start sending if not started already
void uart_send(char* str)
{
while (*str != '\0') // while not '\0'
uart_ringbuf_push(&txBuf, *str++);
if (!txStatus) // if not sending, start sending
uart_internal_sendchar();
}
// Add string to buffer and start sending if not started already
void uart_sendn(char* str, uint8_t n)
{
for (int i = 0; i < n; i++) // send n ammount of chars
uart_ringbuf_push(&txBuf, str[i]);
if (!txStatus) // if not sending, start sending
uart_internal_sendchar();
}
// Add char to buffer and start sending if not started already
void uart_sendc(char c)
{
// send a single char
uart_ringbuf_push(&txBuf, c);
if (!txStatus) // if not sending, start sending
uart_internal_sendchar();
}
// ISR
// ========== ========== ========== ========== ========== ==========
// Interrupt on receive
ISR(USART_RX_vect)
{
uart_ringbuf_push(&rxBuf, UDR0);
}
// Interrupt on send
ISR(USART_TX_vect)
{
uart_internal_sendchar();
}
#include <avr/io.h>
#include <avr/interrupt.h>
#define KEYBOARD_ROW_FIRSTPIN PD2
#define KEYBOARD_ROW_COUNT 4
#define KEYBOARD_COL_FIRSTPIN PC0
#define KEYBOARD_COL_COUNT 4
// keyboard chars
uint8_t btn_chars[KEYBOARD_ROW_COUNT][KEYBOARD_COL_COUNT] =
{
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
// current keyboard state
uint8_t btn_state[KEYBOARD_ROW_COUNT][KEYBOARD_COL_COUNT] = {{0}};
// last keyboard state
uint8_t btn_laststate[KEYBOARD_ROW_COUNT][KEYBOARD_COL_COUNT] = {{0}};
// initialize the keyboard
void keyboard_init()
{
DDRD |= _BV(PD2) | _BV(PD3) | _BV(PD4) | _BV(PD5);
PORTD |= _BV(PD2) | _BV(PD3) | _BV(PD4) | _BV(PD5);
DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3));
PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3);
}
void keyboard_update()
{
for (uint8_t y = 0; y < KEYBOARD_ROW_COUNT; y++)
{
PORTD &= ~(_BV(KEYBOARD_ROW_FIRSTPIN + y));
for (uint8_t x = 0; x < KEYBOARD_COL_COUNT; x++)
{
btn_laststate[y][x] = btn_state[y][x];
btn_state[y][x] = !(PINC & _BV(KEYBOARD_COL_FIRSTPIN + x));
}
PORTD |= (_BV(KEYBOARD_ROW_FIRSTPIN + y));
}
}
int main()
{
uart_init(115200, 1);
sei();
keyboard_init();
while (1)
{
keyboard_update();
for (uint8_t y = 0; y < KEYBOARD_ROW_COUNT; y++)
for (uint8_t x = 0; x < KEYBOARD_COL_COUNT; x++)
if (btn_state[y][x] && !btn_laststate[y][x])
uart_sendc(btn_chars[y][x]);
}
return 0;
}