¿por qué este código no recibe la cadena? (solo recibe el primer carácter)

0

Quiero recibir una cadena con atmega8 que es enviada por otro atmega8. El remitente envía la cadena solo una vez, pero en el receptor solo se recibe el primer carácter. No puedo entender cual es el problema? gracias por tu ayuda. Este es el código.

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{ 
   while ( !(UCSRA & (1<<RXC)));

   for (i=0; i<8; i++) {
     data = UDR;  
     if (data != '
// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{ 
   while ( !(UCSRA & (1<<RXC)));

   for (i=0; i<8; i++) {
     data = UDR;  
     if (data != '%pre%') {
       mass[i]=data; 
     }

     while ( !(UCSRA & (1<<RXC)));   
   }
   lcd_puts(mass);
   delay_ms(500);
   lcd_clear();
}  
') { mass[i]=data; } while ( !(UCSRA & (1<<RXC))); } lcd_puts(mass); delay_ms(500); lcd_clear(); }

y mientras que el bucle está vacío. Intento usar la interrupción para recibir.

    
pregunta mary

1 respuesta

2

Las interrupciones están diseñadas para hacer un poco de trabajo y luego salir. Puede pensar en ellos como un complemento de la estructura solo de bucle principal. Por ejemplo:

void main(void)
{
    //startup initialization
    while(1)
    {
        if(flag1)
        {
            flag1 = 0;
            //do something triggered by flag1
        }
        if(flag2)
        {
            flag2 = 0;
            switch(flag2_state)
            {
            case 0:
                //do action0 from flag2
                break;
            case 1:
                //do action1 from flag2
                break;
            //etc.
            default:
                //correct an invalid state
                break;
            }
            flag2_state++;
        }
        //etc.
    }
}

Observe cómo el controlador de flag2 hace cosas diferentes cada vez que se activa, pero siempre deja para permitir que el resto del código siga funcionando. Esta es la diferencia entre ejecutar en "metal desde cero" como usted lo está haciendo, y ejecutar en un administrador de tareas multiproceso como el que tendría como parte de un sistema operativo como Windows, Mac o Linux. Una vez que entiendas eso, entonces podemos introducir interrupciones:

void main(void)
{
    //startup initialization
    while(1)
    {
        if(flag1)
        {
            flag1 = 0;
            //do something triggered by flag1
        }
        //etc.
    }
}
interrupt [flag2] void flag2_isr(void)
{
    flag2 = 0;
    switch(flag2_state)
    {
    case 0:
        //do action0 from flag2
        break;
    case 1:
        //do action1 from flag2
        break;
    //etc.
    default:
        //correct an invalid state
        break;
    }
    flag2_state++;
}

Aquí hago algunas suposiciones sobre la sintaxis, pero creo que entiendes la idea. Todo el punto de las interrupciones es reducir la latencia de ciertos eventos, o en otras palabras, el tiempo que lleva manejarlos.

En el primer ejemplo, si flag1 y flag2 se activaran inmediatamente después de verificar flag2 , y flag1 tardara mucho tiempo en procesarse, entonces flag2 tendría que esperar tanto. incluso empezar Eso podría no ser aceptable.

En el segundo ejemplo, flag2 se maneja inmediatamente, incluso si flag1 aún se está procesando. Pero es mucho más importante dejar el ISR porque bloquea completamente el ciclo principal para que no haga nada.

Físicamente, una interrupción es una llamada de función que el hardware realiza automáticamente en respuesta a flag2 . Debido a que esto puede suceder en cualquier momento sin previo aviso, debe diseñar bien la interacción para evitar algunos errores extraños. (La palabra clave volatile es realmente útil aquí) También es más importante que antes borrar flag2 , o la llamada a la función volverá a suceder, una y otra vez, quemando la máquina de estados como si no hubiera existido. , y bloqueando el bucle principal casi como si no estuvieras abandonando el ISR en absoluto.

Una vez que entiendas eso, puedo explicar que la razón por la que el código de bloqueo (tu ejemplo original) funciona en un sistema operativo multitarea (hay varias formas de hacerlo; esta es solo una de ellas) es que el sistema operativo tiene una interrupción invisible para el usuario que se activa desde un temporizador. Esto puede hacer todo tipo de cosas que se basan en un intervalo de tiempo, además de cambiar de tareas. Para hacer el cambio, simplemente guarde el puntero de la pila (¿en qué contexto estoy ejecutando?) En una biblioteca administrada por el sistema operativo y cargue una diferente de la misma biblioteca. Ahora, cuando el ISR se va, va a una tarea diferente. Por lo tanto, cada tarea se puede escribir como si fuera la única cosa en ejecución. No es así porque no tienes ese conmutador de contexto.

    
respondido por el AaronD

Lea otras preguntas en las etiquetas