2017-01-09 2 views
-3

J'ai récemment rencontré un problème lorsque je jouais avec un ATmega2560, et je ne comprends vraiment pas ce qui ne va pas.ATmega2560 utilisant l'interruption UART pour contrôler le drapeau global

Voici mon code.

principale:

#include "Definitions.h" 

int main(void) { 
    Initialization(); 
    while (1) { 
     //_delay_ms(1); // or printf... 
     //wait for RXC flag 
     if (RxFlag) { 
      //wait for new byte in 
      //PORTB &= ~(1 << PB7); 
      PORTB |= (1 << PB7); 
      rxcount = 0; 
      UDR0 = 'R'; 
      RxFlag = false; 
      TxFlag = false; 
     } 
    } 
} 

IRQ:

#include "Definitions.h" 

ISR(USART0_RX_vect) { 
    while(!(UCSR0A & (1 << RXC0))) 
    //wait for RXC flag 
     ; 
    /* Loop-back test */ 
    //PORTB |= (1 << PB7); 
    //test_data = UDR0; 
    TxFlag = true; 
    //enableUDRI0(); 
    //PORTB &= ~(1 << PB7); 
    //PORTB |= (1 << PB7); 
    RxBuffer[rxcount++] = UDR0; 
    if(!(rxcount < RX_BUF_SZ)) { 
     //rxcount = 0; 
     PORTB |= (1 << PB7); 
     RxFlag = true; 
    } 
} 

ISR(USART0_UDRE_vect) { 
    while(!(UCSR0A & (1 << UDRE0))) 
    //wait for udr to be empty 
     ; 
    /* Loop-back test */ 
    UDR0 = 0x30 + rxcount; 
    disableUDRI0(); 
} 

Le problème est, quand j'ai reçu des données de USART, j'ai essayé de mettre un RxFlag qui peut l'instruction if actif dans la boucle principale . Mais cela n'a pas fonctionné jusqu'à ce que je décommente la fonction avant if-statement qui peut être un _delay_ms() ou un printf().

Cela n'a aucun sens. Ce dont je me souviens, c'est que je n'ai pas besoin de ces fonctions et que les variables globales peuvent toujours affecter la boucle principale. Ou y a-t-il des détails que j'avais manqués? S'il vous plaît donnez-moi quelques indices pour comprendre, je suis confus.

+0

Veuillez poster votre code ici et non via des liens externes. –

+3

Un moment dans un ISR est la pire idée ... jamais ... Je suppose que vous avez copié cette forme d'un code non-interrompu. – LPs

+0

On dirait qu'il y a quelques fausses conceptions sur le fonctionnement des interruptions. Et il y a un code manquant. Lisez [ask] et suivez les conseils! – Olaf

Répondre

0

Il n'est pas possible d'être défini, mais je pense que cela explique votre problème, donc c'est peut-être l'erreur. Vous n'incluez pas la déclaration de RXFlag, mais je suppose que vous ne le déclarez pas volatile. Si vous ne le faites pas, le compilateur peut supposer qu'il sait tout de ce qui va arriver à cette variable. En particulier, il sait que, à moins que main() n'appelle d'autres fonctions, la valeur de RxFlag ne changera jamais. Il peut donc optimiser l'expression if en la déplaçant en dehors de la boucle. En effet, il change votre code comme ceci:

#include "Definitions.h" 

int main(void) 
{ 
    register bool x; 

    Initialization(); 

    x = RxFlag; 

    while (1) 
    { 
     //wait for RXC flag 
     if (x) //wait for new byte in 
     { 
      //PORTB &= ~(1 << PB7); 
      PORTB |= (1 << PB7); 
      rxcount = 0; 
      UDR0 = 'R'; 
      RxFlag = false; 
      TxFlag = false; 

     } 
    } 
} 

Cependant, si main() appelle une autre fonction, le compilateur donne à essayer de garder RxFlag dans un registre sur cet appel. L'autre fonction pourrait changer le registre dans lequel RxFlag est maintenu. Il devrait le pousser sur la pile ou quelque chose. Le lire à nouveau est moins cher en code et en temps et donc il le lira chaque fois qu'il fait le tour de la boucle.

La correction correcte pour ce bogue est de déclarer toutes les variables qui sont partagées entre le thread principal et le ISR comme volatile.

+0

Avec gcc, la moitié des registres AVR sont * sauvegardés à l'aide d'un calle *. Et gcc en fait usage lors de l'optimisation et peut garder des valeurs dans les registres même à travers les appels de fonction. Un appel de fonction peut également être en ligne, de sorte que, pour l'optimiseur, il ne se produit même pas en tant qu'appel. – JimmyB