#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#define F_CPU 16000000
#define BUFFER_SIZE 20
#define Black 30
#define Red 31
#define Green 32
#define Yellow 33
#define Blue 34
#define Magenta 35
#define Cyan 36
typedef struct {
char buffer[BUFFER_SIZE];
volatile uint8_t in_idx;
volatile uint8_t out_idx;
} ring_buffer_t;
ring_buffer_t rx_ring;
ring_buffer_t tx_ring;
void init_ring_buffers() {
rx_ring.in_idx = 0;
rx_ring.out_idx = 0;
tx_ring.in_idx = 0;
tx_ring.out_idx = 0;
}
// interrupcion de recepcion uart
ISR (USART0_RX_vect) {
// comprueba si hay espacio en el buffer
if (!(((rx_ring.in_idx + 1) & (BUFFER_SIZE - 1)) == (rx_ring.out_idx))) {
rx_ring.buffer[rx_ring.in_idx++] = UDR0; // almacena el dato recibido en el buffer
rx_ring.in_idx &= BUFFER_SIZE - 1; // ajusta el indice de entrada al tamano del buffer
}
}
// interrupcion de transmision uart
ISR (USART0_UDRE_vect) {
UDR0 = tx_ring.buffer[tx_ring.out_idx++]; // envia el dato desde el buffer
tx_ring.out_idx &= (BUFFER_SIZE - 1); // ajusta el indice de salida al tamano del buffer
if (tx_ring.out_idx == tx_ring.in_idx) {
UCSR0B &= ~(1 << UDRIE0); // deshabilita la interrupcion si el buffer esta vacio
}
}
void UART_Init(uint8_t com, uint32_t baudrate, uint8_t size, uint8_t parity, uint8_t stop) {
// arreglos de punteros a los registros uart
uint32_t *UBRRH_ptr[] = {&UBRR0H, &UBRR1H, &UBRR2H, &UBRR3H};
uint32_t *UBRRL_ptr[] = {&UBRR0L, &UBRR1L, &UBRR2L, &UBRR3L};
uint8_t *UCSRB_ptr[] = {&UCSR0B, &UCSR1B, &UCSR2B, &UCSR3B};
uint8_t *UCSRC_ptr[] = {&UCSR0C, &UCSR1C, &UCSR2C, &UCSR3C};
uint8_t *UBRR_ptr[] = {&UBRR0, &UBRR1, &UBRR2, &UBRR3};
uint32_t ubrr = 0;
// verificar que el numero de uart sea valido
if (com > 3) {
com = 0;
}
// configurar los registros uart
//*UBRRH_ptr[com] = (unsigned char)(((F_CPU*10/16/baudrate+5)/10-1) >> 8); // configurar ubrrh
//*UBRRL_ptr[com] = (unsigned char)((F_CPU*10/16/baudrate+5)/10-1); // configurar ubrr
*UBRR_ptr[com] = F_CPU / (16 * baudrate) - 1;
*UCSRB_ptr[com] = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0); // configurar rxen, txen y rxcie en ucsrb
if (size == 9) {
*UCSRC_ptr[com] |= (1 << UCSZ02); // configurar tamano de datos en ucsrc para 9 bits
size = 8; // ajustar el tamano a 8 bits
}
size = size - 5; // ajustar el tamano para el registro ucsrc
*UCSRC_ptr[com] &= ~(1 << UCSZ01); // limpiar los bits ucsz01 y ucsz00
*UCSRC_ptr[com] &= ~(1 << UCSZ00);
*UCSRC_ptr[com] |= (size << UCSZ00); // configurar el tamano de datos en ucsrc
if (parity != 0) {
*UCSRC_ptr[com] |= (1 << UPM01) | (parity << UPM00); // configurar la paridad en ucsrc
}
*UCSRC_ptr[com] &= ~(1 << USBS0); // limpiar el bit usbs0
*UCSRC_ptr[com] |= ((stop - 1) << USBS0); // configurar el numero de bits de parada en ucsrc
}
// funcion para enviar un caracter por uart
void UART_putchar(char dato) {
// esperar hasta que haya espacio en el buffer
while (((tx_ring.in_idx + 1) & (BUFFER_SIZE - 1)) == (tx_ring.out_idx)) {
;
}
// guardar el dato en el buffer
tx_ring.buffer[tx_ring.in_idx++] = dato;
tx_ring.in_idx &= (BUFFER_SIZE - 1);
// habilitar la interrupcion de registro de datos vacio si esta deshabilitada
UCSR0B |= (1 << UDRIE0);
}
// funcion para verificar si hay datos disponibles en el buffer de recepcion
uint8_t UART0_available(void) {
// verificar si el buffer no esta vacio
if (rx_ring.in_idx != rx_ring.out_idx) {
return 1; // si hay datos disponibles, devolver 1
} else {
return 0; // si no hay datos disponibles, devolver 0
}
}
// funcion para leer un caracter del buffer de recepcion
char UART0_getchar(void) {
// esperar hasta que haya datos disponibles en el buffer
while (rx_ring.in_idx == rx_ring.out_idx) {
// esperar activamente
}
char c = rx_ring.buffer[rx_ring.out_idx++]; // leer el caracter del buffer y actualizar el indice de salida
rx_ring.out_idx &= (BUFFER_SIZE - 1);
// devolver el caracter leido
return c;
}
// funcion para enviar una cadena de caracteres por uart
void UART_puts(char *str) {
// mientras no se haya llegado al final de la cadena
while (*str) {
// enviar el caracter actual
UART_putchar(*str);
// mover el puntero al siguiente caracter
str++;
}
}
// funcion para capturar una cadena de caracteres desde uart
void UART0_gets(char *str) {
int index = 0;
char c;
do {
c = UART0_getchar();
if (c == 8 && index > 0) {
// retrocede un caracter, imprime un espacio y retrocede de nuevo
UART_puts("\b \b");
index--; // decrementa el indice para borrar el ultimo caracter en la siguiente iteracion
} else if (c >= ' ' && index < BUFFER_SIZE - 1) {
UART_putchar(c);
str[index++] = c;
}
} while (c != 13); // continua hasta que se presiona enter
str[index] = '\0'; // asegura que la cadena termina con un caracter nulo
}
// funcion para convertir un numero a cadena de caracteres
void itoa(char* str, uint16_t number, uint8_t base) {
int digits = 0;
uint16_t tempNumber = number;
while (tempNumber >= base) {
digits++;
tempNumber /= base;
}
str[digits + 1] = '\0';
while (digits != 0) {
if ((number % base) > 9) {
str[digits] = number % base + 'A' - 10;
} else {
str[digits] = number % base + '0';
}
number /= base;
digits--;
}
if ((number % base) > 9) {
str[digits] = number % base + 'A' - 10;
} else {
str[digits] = number % base + '0';
}
}
// funcion para convertir una cadena de caracteres a un numero
uint16_t atoi(char *str) {
uint16_t valor = 0;
while (*str >= '0' && *str <= '9') {
valor *= 10;
valor += *str;
valor -= '0';
str++;
}
return valor;
}
void clear() {
UART_puts("\033[2J");
gotoxy(0, 0);
}
void gotoxy(uint8_t x, uint8_t y) {
char xStr[3], yStr[3];
xStr[0] = '0' + x / 10;
xStr[1] = '0' + x % 10;
xStr[2] = '\0';
yStr[0] = '0' + y / 10;
yStr[1] = '0' + y % 10;
yStr[2] = '\0';
UART_putchar('\033');
UART_putchar('[');
UART_puts(yStr);
UART_putchar(';');
UART_puts(xStr);
UART_putchar('H');
}
void setColor(uint8_t color) {
UART_putchar('\033');
UART_putchar('[');
UART_putchar('0');
UART_putchar(';');
char colorStr[3];
itoa(colorStr, color, 10);
UART_puts(colorStr);
UART_putchar('m');
}
int main(void) {
uint8_t com = 0;
uint32_t baud = 250000;//57600;//38400;//19200;//14400;//9600;
uint8_t size = 8;
uint8_t par = 0;
uint8_t SB = 1;
char cad[20];
uint16_t num;
init_ring_buffers();
UART_Init(com, baud, size, par, SB);
sei();
while (1) {
gotoxy(2, 2);
setColor(Yellow);
UART_puts("ingresa un numero:");
gotoxy(22, 2);
setColor(Green);
UART0_gets(cad);
num = atoi(cad);
itoa(cad, num, 16);
gotoxy(5, 3);
setColor(Blue);
UART_puts("hex: ");
UART_puts(cad);
itoa(cad, num, 2);
gotoxy(5, 4);
UART_puts("bin: ");
UART_puts(cad);
UART0_getchar();
clear();
init_ring_buffers();
}
}