Uso de la interrupción UDRIE0 en ATmega168

0

Solo tengo un conocimiento limitado en interrupciones.

Esto es lo que entiendo sobre las siguientes funciones de ISR

ISR(USART_RX_vect) se llamará cuando haya nuevos datos disponibles en el búfer de recepción (RXC0 de USCR0A se establecerá en 1) y se borrará cuando se lean los datos

ISR(USART_UDRE_vect) será llamado cuando UDRE0 se convierta en 1, lo que indica que el búfer de transmisión está vacío y listo para recibir datos

Configuré un código de interrupción UART como se muestra a continuación, no estoy seguro de que esta sea la forma correcta en que debería verse la función ISR pero funciona

/*
 * uart_interrupt.c
 *
 * Created: 12-10-2018 04:54:04 PM
 * Author : Athul
 */ 
#define F_CPU 1000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
//#include <util/setbaud.h>

#define BAUD 9600
#define SIZE 500
int i = 0, j = 0;

uint8_t data_int;

/* For U2X0 = 0 */
uint16_t UBRR0_value = ((F_CPU / (4L * BAUD)) - 1)/2;

/* For U2X0 = 1 */
//uint16_t UBRR0_value = ((F_CPU / (8L * BAUD)) - 1)/2;


void uart_init(void)
{
    /* For a baud rate of 9600 (F_CPU = 1000000), error is 7% when U2X0 = 0. Writing this bit to one will
     reduce the divisor of the baud rate divider from 16 to 8 effectively doubling the 
     transfer rate for asynchronous communication and reduce error to 0.2% */
    UCSR0A |= (1 << U2X0);

    /*set (global) interrupt enable bit*/
    sei();

    /* transmit enable, receive enable & RX Complete Interrupt Enable */
    UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);

    /* 8 bit mode */
    UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);

    /* Baud rate registers */
    UBRR0H = UBRR0_value >> 8;
    UBRR0L = UBRR0_value;

}

void uart_tx(uint8_t data)
{
    /*wait till USART Receive Complete*/
    loop_until_bit_is_set(UCSR0A, UDRE0); // same as while(!(UCSR0A & (1 << UDRE0)));
    UDR0 = data;
}

uint8_t uart_rx(void) {

    /*wait till USART Data Register Empty*/
    loop_until_bit_is_set(UCSR0A, RXC0); // same as while(!(UCSR0A & (1 << RXC0)));
    return UDR0;
}

void printString(uint8_t *ptr)
{
    while(*ptr != '
//USART Data Register Empty Interrupt Enable
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0) | (1 << UDRIE0);

ISR(USART_RX_vect)
{
    data_int = UDR0;
}

ISR(USART_UDRE_vect)
{
    UDR0 = data_int;
}
') { uart_tx(*ptr); ptr++; } } /*Interrupt sub-routine for RX Complete Interrupt Enable*/ ISR(USART_RX_vect) { data_int = UDR0; loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = data_int; } int main(void) { /*Initialize uart*/ uart_init(); /*Test*/ uint8_t *p = "Hello"; printString(p); /*Set PORTB pins as output*/ DDRB = 0XFF; /*event loop*/ while (1) { /*Toggle PORTB pins*/ PORTB = 0XFF; _delay_ms(100); PORTB = 0X00; _delay_ms(100); } }

Para saber cómo implementar UDRIE0 , hice los siguientes cambios,

#define SIZE 64
int i = 0, j = 0;

uint8_t data_int[SIZE];

ISR(USART_RX_vect)
{
    data_int[i] = UDR0;
    i++;
    if(i > 64)
    {
        i = 0;
    }
}

ISR(USART_UDRE_vect)
{
    UDR0 = data_int[j];
    j++;
    if(j == 64)
    {
        UCSR0B &= ~(1 << UDRIE0); //disable UDRIE0 interrupt
    }
}

Sigue imprimiendo los datos que ingresé por última vez

Luego decidí crear una matriz y almacenar los caracteres recibidos en ella y el ISR(USART_UDRE_vect) leería cada carácter y lo transmitiría.

/*
 * uart_interrupt.c
 *
 * Created: 12-10-2018 04:54:04 PM
 * Author : Athul
 */ 
#define F_CPU 1000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
//#include <util/setbaud.h>

#define BAUD 9600
#define SIZE 500
int i = 0, j = 0;

uint8_t data_int;

/* For U2X0 = 0 */
uint16_t UBRR0_value = ((F_CPU / (4L * BAUD)) - 1)/2;

/* For U2X0 = 1 */
//uint16_t UBRR0_value = ((F_CPU / (8L * BAUD)) - 1)/2;


void uart_init(void)
{
    /* For a baud rate of 9600 (F_CPU = 1000000), error is 7% when U2X0 = 0. Writing this bit to one will
     reduce the divisor of the baud rate divider from 16 to 8 effectively doubling the 
     transfer rate for asynchronous communication and reduce error to 0.2% */
    UCSR0A |= (1 << U2X0);

    /*set (global) interrupt enable bit*/
    sei();

    /* transmit enable, receive enable & RX Complete Interrupt Enable */
    UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);

    /* 8 bit mode */
    UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);

    /* Baud rate registers */
    UBRR0H = UBRR0_value >> 8;
    UBRR0L = UBRR0_value;

}

void uart_tx(uint8_t data)
{
    /*wait till USART Receive Complete*/
    loop_until_bit_is_set(UCSR0A, UDRE0); // same as while(!(UCSR0A & (1 << UDRE0)));
    UDR0 = data;
}

uint8_t uart_rx(void) {

    /*wait till USART Data Register Empty*/
    loop_until_bit_is_set(UCSR0A, RXC0); // same as while(!(UCSR0A & (1 << RXC0)));
    return UDR0;
}

void printString(uint8_t *ptr)
{
    while(*ptr != '
//USART Data Register Empty Interrupt Enable
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0) | (1 << UDRIE0);

ISR(USART_RX_vect)
{
    data_int = UDR0;
}

ISR(USART_UDRE_vect)
{
    UDR0 = data_int;
}
') { uart_tx(*ptr); ptr++; } } /*Interrupt sub-routine for RX Complete Interrupt Enable*/ ISR(USART_RX_vect) { data_int = UDR0; loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = data_int; } int main(void) { /*Initialize uart*/ uart_init(); /*Test*/ uint8_t *p = "Hello"; printString(p); /*Set PORTB pins as output*/ DDRB = 0XFF; /*event loop*/ while (1) { /*Toggle PORTB pins*/ PORTB = 0XFF; _delay_ms(100); PORTB = 0X00; _delay_ms(100); } }

Imprime " hola " y nada más.

¿Alguien puede decir por qué no funciona? ¿Un pequeño ejemplo de UDRIE0 si es posible?

También el compilador da una advertencia. %código% ¿Qué significa esto?

    
pregunta Athul

1 respuesta

-1

Las interrupciones son administradas por hardware y se activan inmediatamente cuando ocurre cualquier tipo de evento, por ejemplo. cuando el registro de datos está vacío, la transmisión de datos está completa, etc.

Si implementa la subrutina ISR para un determinado tipo de interrupción, un código de aplicación en ejecución se interrumpe inmediatamente cuando se dispara la interrupción y se ejecuta esta subrutina, es decir, Un salto largo en la memoria del programa. Antes de ejecutar la subrutina, todos los registros relevantes se insertan en una pila y se restauran cuando finaliza la subrutina. Después de atender la interrupción, el código de la aplicación interrumpida continúa desde la dirección donde se interrumpió.

Un código de sub-rutinas debe ser lo más pequeño posible y debe ejecutarse rápidamente, por lo que no debe haber retrasos o bucles largos. Si desea procesar los datos UART recibidos, debe colocarlos en un búfer en la subrutina y procesarlos en el ciclo principal.

En el caso de microcontroladores atmel, los indicadores de interrupción, por ejemplo. UDRE, se borran automáticamente cuando finalizan las subrutinas. No hay necesidad de eliminarlos por software.

Espero que mi explicación de las interrupciones sea clara y te ayude a escribir el código correcto.

    
respondido por el Lubo

Lea otras preguntas en las etiquetas