La mejor manera de encontrar el retraso entre recibir datos de USART

2

Escribo un código (para Atmega168P) para recibir datos de la interrupción USART como se muestra a continuación:

ISR     (USART_RX_vect)
{
    unsigned char count=0;      
    unsigned char coder[13];    
    int over_uart=0;

    for (count=0;count<13;count++)
    {
        while (!recive_485)
        {
            over_uart++;                
            wdt;
            if (over_uart>=20000)   {   
                coder[0]=0;     
                count=14;       
                over_uart=0;    
                break;  }
        }
        coder[count]=UDR0;
    }
}

Cada vez que recibo 13 bytes de datos y los coloco en coder array.

Utilizo una variable over_uart para calcular el tiempo entre cada byte recibido. Si over_uart>=20000 significa que:

El progreso de la recepción es el inicio, pero tenemos un problema en las líneas que no obtienen el siguiente byte en 20000ms. Y finalice el último comando y busque el nuevo 13byte que recibirá de la línea.

¿Cualquier organismo conoce una forma optimizada de encontrar el retraso entre recibir datos de USART (sin la ayuda de over_uart variable)?

  

EDIT :

Corrijo el problema en mi código y elimino la demora de colocación en ISI como un golpe:

ISR     (USART_RX_vect)
{
    coder[count]=UDR0;
    if (coder[count] == 20)
        UartFlag=True;
    else
        count++;
}

Y en la función Main :

while (1)
    {
        if (UartFlag)
        {
            DoSomthing();
            count=0;
            UartFlag=Fulse;
        }
    }
    
pregunta combo_ci

4 respuestas

3

Date cuenta de que la rutina de interrupción es solo el código al que debes saltar, nada más. Por lo tanto, su código es totalmente una mala interpretación:

  • Sus variables más deben ser estáticas. En su código son locales apilados que se recrean en cada interrupción. también debido al flujo de código indeterminado causado por interrupciones, tiene que deshabilitar posibles optimizaciones en variables vulnerables declarando como "volátiles".

  • No hagas ese tipo de bucles allí. Date cuenta que cada interrupcion etrance es la parte del bucle de recopilación de datos.

Para resolver el problema, tu mejor disparo es usar un temporizador de hardware. En cada llamada de interrupción, tome una lectura de un temporizador que se restablece con el código de salida de la interrupción anterior. Por lo tanto, puede determinar fácilmente si hay un desbordamiento y cuidarlo.

    
respondido por el Ayhan
3

Parece que estás diseñando algún tipo de protocolo de comunicación que garantiza la integridad de los datos. Su criterio de integridad consiste en recibir una cantidad esperada de datos en un tiempo limitado.

Si bien este enfoque es técnicamente posible, le aconsejo que considere enfoques más estándar (por ejemplo, el envío de paquetes con un byte de inicio y una suma de comprobación). Dichos enfoques no tienen restricciones de tiempo (en su lugar, simplemente analiza un flujo continuo de bytes) y se pueden hacer arbitrariamente robustos (con una suma de comprobación lo suficientemente larga, prácticamente se garantiza que nunca recibirá un paquete dañado).

La confianza en el tiempo para las verificaciones de integridad de los datos es muy pobre. Su enfoque le fallará inevitablemente una vez que su sistema necesite recibir más datos o su código crezca lo suficientemente complejo como para introducir demoras internas que no podrá predecir.

También, si se apega a un protocolo estándar como HDLC , XMODEM o MIN , es probable que encuentre bibliotecas que lo implementan ya, ahorrándole una buena cantidad de tiempo.

    
respondido por el Dmitry Grigoryev
3

Aquí hay una versión del código pseudo para su ISR que no entra en estado de espera en el ISR y no requiere cambios en ninguna otra parte de su programa.

La premisa básica es que el ISR mantiene una copia local del búfer de recepción. Una vez que este búfer tiene un total de 13 caracteres dentro del límite de tiempo, luego pasa el búfer al código principal a través de un búfer global llamado rcv_buff y genera un semáforo llamado data_ready

Para determinar si ha recibido 13 caracteres dentro del límite de tiempo, utiliza la función time () que devuelve el tiempo en segundos desde la época. Si time () no está disponible en su biblioteca, puede crear una función similar desde un reloj del sistema.

ISR:
     // declare local_count,local_buff, last_time as local static variables
     // rcv_buff and data_ready are globals for main()

     local_count++;                   // bump receive counter
     local_buff[local_count-1]=UDR0;  // save in local buffer
                                      // time() returns time in secs (since epoch)
     if time()-last_time>20 then {    // over time limit, empty local buffer
          local_count=0;              // reset the local character counter
          local_buff=''; }            // flush the local buffer
     last_time = time();              // save current time in secs for next pass
     data_ready=False;                // squelch the semaphore
     if (local_count==13) then {      // we have 13 characters, pass to main code
          local_buff[local_count)=
ISR:
     // declare local_count,local_buff, last_time as local static variables
     // rcv_buff and data_ready are globals for main()

     local_count++;                   // bump receive counter
     local_buff[local_count-1]=UDR0;  // save in local buffer
                                      // time() returns time in secs (since epoch)
     if time()-last_time>20 then {    // over time limit, empty local buffer
          local_count=0;              // reset the local character counter
          local_buff=''; }            // flush the local buffer
     last_time = time();              // save current time in secs for next pass
     data_ready=False;                // squelch the semaphore
     if (local_count==13) then {      // we have 13 characters, pass to main code
          local_buff[local_count)=%pre%  // ensure string ends with null
          rcv_buff=local_buff;        // pass the local buffer to main
          data_ready = True;          // raise the semaphore for main
          local_count=0;              // reset local buffer for next packet
          local_buff='';  }           // flush the local buffer
// ensure string ends with null rcv_buff=local_buff; // pass the local buffer to main data_ready = True; // raise the semaphore for main local_count=0; // reset local buffer for next packet local_buff=''; } // flush the local buffer

Editar: Se limpió la indexación del búfer para la compatibilidad con C. Comentarios mejorados

    
respondido por el Glenn W9IQ
1

es probable que desee comprender cómo funcionan las interrupciones en general antes de sumergirse en ellas. Una vez que lo hagas, es probable que tengas que volver a escribir tu ISR completamente.

con eso dicho, una forma de hacer lo que quieres hacer es algo como esto:

  current_time = time_now(); //stamp current time
  time_elapsed = current_time - previous_time; //calculate the time difference
  previous_time = current_time;  //update previous time

requiere un marco totalmente diferente al que tienes ahora, por cierto.

    
respondido por el dannyf

Lea otras preguntas en las etiquetas