USART ISR se repite 4 veces

1

Hola,

Tengo un problema con la interrupción USART_RX_vect del ATMega 328p. La recepción funciona bien y puedo evaluar los bits enviados (por lo que no se debe a la velocidad en baudios), pero cada vez que envío un poco, el ISR se ejecuta 4 veces.

Entonces, un ISR como este:

ISR(USART_RX_vect) {
    uart_transmit('t');
    uart_flush();
}

Transmitirá {'t', 't', 't', 't'}

No tengo ni idea de por qué sucede esto, y espero que puedas ayudarme.

Mi main es un bucle vacío (por supuesto que ejecuto uart_setup ). Mi ISR es como el de arriba. Estoy usando avr-gcc en linux.

Esta es mi configuración de UART:

void uart_setup() {                                                                                                                                                                                                 
      UBRR0H = (BAUDRATE >> 8);                                                                                                                                                                                       
      UBRR0L = BAUDRATE;                                                                                                                                                                                              

      // Set 8-Bit mode                                                                                                                                                                                               
      setBit(UCSR0C, UCSZ01);                                                                                                                                                                                         
       setBit(UCSR0C, UCSZ00);                                                                                                                                                                                         

      setBit(UCSR0B, RXEN0); // Receiver enable                                                                                                                                                                       
      setBit(UCSR0B, TXEN0); // Transmitter enable                                                                                                                                                                    

      setBit(UCSR0B, RXCIE0); // Enable RX Interrupt                                                                                                                                                                  
      sei(); // Enable global interrupts                                                                                                                                                                              
  }       

void uart_transmit(unsigned char data)                                                                 
{                                                                                                      
    while (!( UCSR0A & (1<<UDRE0))); // wait while register is free                     
    UDR0 = data; // load data in the register                        
}         

void uart_flush( void ) {                                                                              
          unsigned char dummy;                                                                           
          while ( UCSR0A & (1<<RXC0) ) dummy = UDR0;                                                     
  }                                                                                                                                                                                                                                                                                                                                                   
    
pregunta Ardupi de

2 respuestas

3

Parece que el diseño de su código es tal que cuando se recibe un byte en el UART, desea deshacerse de ese byte y responder transmitiendo una "t".

El UART comparte un registro común de búfer de recepción / transmisión. Debido a que su rutina de recepción de UART está controlada por interrupciones, debe leer inmediatamente el carácter recibido antes de poner la respuesta en el búfer, de lo contrario, volverá a activar la interrupción de recepción cuando salga.

Tampoco hay ninguna razón para tener el código 'while' en la rutina uart_flush, ya que sabes que hay un carácter en el búfer basado en el hecho de que una interrupción te llevó a este punto. Solo lee el registro del búfer.

Aquí hay una versión simplificada de un ISR corregido sin las funciones:

ISR(USART_RX_vect) {
     unsigned char dummy;
     dummy = UDR0;                     // dump the rcvr buffer
     while (!( UCSR0A & (1<<UDRE0)));  // wait until the register is free                     
     UDR0 = data;                      // load xmt data in the register
}
    
respondido por el Glenn W9IQ
0

La función uart_flush() no tiene ningún propósito por lo que puedo ver, a menos que la esté utilizando para esperar a que se reciban todos los bytes. Creo que su problema es que está haciendo las cosas en orden inverso, está recibiendo la interrupción de Rx y luego escribe en el registro de datos UART y luego lee de él sin ninguna garantía de que la transmisión se haya completado. Creo que necesitas intercambiar el orden que llamas transmisión y descarga en tu ISR.

    
respondido por el pfl

Lea otras preguntas en las etiquetas