5 votos

¿Como leer datos enteros enviados a USART con interrupción?

Actualmente soy capaz de leer byte a byte de la USART con este código

ISR(USART_RX_vect)
{
    cli();
    while(!(UCSR0A&(1<<RXC0))){};
    // clear the USART interrupt  
    received = UDR0;

    if(pinState == 0)
    {
        OCR2A = received;
        pinState = 1;
    }
    else if(pinState == 1)
    {
        OCR2B = received;
        pinState = 2;
    }
    else
    {
        OCR0A = received;
        pinState = 0;
    } 
    sei();
}

Pero ahora voy a enviar 4 bytes de datos que únicamente es necesario para mi aplicación. Yo no podía entender cómo se lee 4 bytes a la vez, ya que la interrupción se activa para cada byte. Gracias por el esfuerzo adelantado.

Para hacerlo más claro voy a explicar brevemente lo que pinState es. Yo soy el envío de 3 bytes de datos y quiero que el 1. byte para ir pin 3 pwm 2. byte pin 11 pwm y 3. byte a pin6 pwm. Como se puede ver en cada interrupción no soy gettin 3 bytes, pero 1 byte en lugar. Así que pinState cosa está en pie sólo para ese propósito.

11voto

Bernd Puntos 61

El método convencional para tratar con multi-byte recibe en una rutina de interrupción es la instalación de una cola circular. Como cada byte recibido es que se coloca en la siguiente ranura disponible en la cola. Este vendría a sustituir su único byte guardar el código que tienes ahora.

El lado de salida de la cola circular que se sondea el contenido disponible por su línea principal de código que desea utilizar los datos recibidos. Cuando comenzamos a lidiar con múltiples flujos de bytes en una interfaz en serie, a menudo es conveniente hacer un "protocolo" que permite que el receptor final para ser capaz de rastrear donde la partida de cada lote de datos se inicia. Hay muchas maneras de hacer esto. Una forma de seleccionar un único valor de byte para el inicio de la tanda. Otra manera es establecer el MSB del primer byte del lote y, a continuación, siga con el resto de los bytes en el lote con el MSB se borra.

** Algunos comentarios acerca de su ISR **

  1. Por lo general es una mala práctica al lugar de votación lazos dentro de una rutina de servicio de interrupción. Usted quiere mantener el ISR de ejecución de tiempo tan corto como sea posible. No sé cuál es la intención del bucle de sondeo es, pero usted debe estudiar acerca de la eliminación de eso.

  2. Generalmente no es necesario estar poniendo interrumpir deshabilitar y volver a habilitar dentro de un ISR. La mayoría de los Mcu automáticamente deshabilitar las interrupciones cuando el ISR es especificado y, a continuación, restaurar el estado anterior, cuando el retorno de interrupción se ejecuta.

  3. No está claro lo que el estado de los pines de la lógica está haciendo dentro de la ISR. Que no se parece en absoluto aplicable para el mantenimiento de una USART interrupción.

10voto

Dan Laks Puntos 5744

Usted no mencionó que el microcontrolador se usa, pero es probable que no importa. USART periféricos generalmente funcionan exactamente como usted ha descubierto: un byte a la vez. Sin embargo, esto no es una limitación.

Basado en el fragmento de código que has publicado en tu pregunta, usted está tratando de ejecutar algunas de las funciones con cada byte recibido. Lo que los limita a un byte de operaciones. Lo que si, por el contrario, se utiliza el ISR sólo para rellenar una matriz de bytes? Luego, después de un cierto número de bytes que se había llegado, luego de leer los bytes e interpretar su significado - de preferencia en el bucle principal de su código, no el ISR.

Tenga cuidado de hacer mucho trabajo en un ISR. Especialmente las llamadas a las funciones dentro de la ISR función. Cada fabricante de silicio y el compilador es diferente, por supuesto, pero las llamadas a funciones dentro de ISRs a menudo puede conducir a extremadamente lentos, ineficientes código. La mayoría de sus cálculos y el manejo de los datos que debe suceder en el ciclo principal. ISRs deben ser utilizados para el establecimiento de indicadores y realizar operaciones rápidas. En general, usted quiere salir de la ISR tan rápidamente como usted puede.

6voto

Camil Staps Puntos 7589

Justo hoy se me ocurrió exactamente en la misma posición, y escribí un programa a lo largo de las líneas de lo que Michael Karas sugiere en su respuesta, el uso de un buffer circular. He utilizado un PIC18, por lo que el código no compila, pero muestra claramente esta idea y debe ser fácil de puerto de este código de AVR, ...

Me declaró que algunas de las variables globales:

#define EUSART_BUFFER_SIZE 2048
char eusart_rx_buffer[EUSART_BUFFER_SIZE];   // the actual buffer, now 2048 bytes long
uint16_t eusart_rx_buffer_rd = 0;            // the current read position
uint16_t eusart_rx_buffer_wr = 0;            // the current write position

Esto supone stdint.h se incluye el uint16_t tipo.

La idea es:

  • En el ISR, cuando se recibe un byte, lo almacenamos en eusart_rx_buffer[eusart_rx_buffer_wr] y el incremento de la posición de escritura.
  • Cuando queremos leer los datos, se puede leer en eusart_rx_buffer_rd hasta eusart_rx_buffer_wr.

Por supuesto, cuando más de 2048 bytes se almacenan en el mismo tiempo, el búfer se sobrescribirán y se perderá los datos. Hay algunos trucos que puede utilizar para evitar que a pesar de. Usted puede cambiar EUSART_BUFFER_SIZE para satisfacer sus necesidades. Un valor más bajo, por supuesto, requiere menos memoria de datos.

Ahora, en mi ISR, tengo:

if (PIR1bits.RCIF) {                                  // EUSART data received
    eusart_rx_buffer[eusart_rx_buffer_wr++] = RCREG;  // Store the received data
    if (eusart_rx_buffer_wr >= EUSART_BUFFER_SIZE)    // Increment write pointer
        eusart_rx_buffer_wr = 0;
    PIR1bits.RCIF = 0;                                // Clear interrupt flag
}

Por supuesto, en un AVR este código tendrá un aspecto ligeramente diferente, pero la idea es la misma.

Entonces, ¿por dónde quieres leer los datos, puedes hacer algo como:

while (eusart_rx_buffer_rd != eusart_rx_buffer_wr) {   // While there's data in the buffer
    do_sth(eusart_rx_buffer[eusart_rx_buffer_rd++]);   // Do something with it
    if (eusart_rx_buffer_rd >= EUSART_BUFFER_SIZE)     // Increase read pointer
        eusart_rx_buffer_rd = 0;
}

Este código fue escrito para PIC18 utilizando el compilador XC8, pero la mayoría de que es el estándar de C y puede ser copiado directamente o portado fácilmente.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X