2017-01-09 1 views
-3

저는 ATmega2560으로 놀고있을 때 최근에 문제를 만났습니다. 실제로 그 문제가 무엇인지 이해하지 못합니다.UART 인터럽트를 사용하여 글로벌 플래그를 제어하는 ​​ATmega2560

여기 내 코드입니다.

주 :

#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(); 
} 

문제입니다, 내가 USART 일부 datas를 받았을 때, 나는 RxFlag을 설정하려고하는 메인 루프에서 활성화 된 경우 문 수 . 하지만 _delay_ms() 또는 printf() 일 수있는 if 문 앞에 함수의 주석을 제거 할 때까지 작동하지 않았습니다.

의미가 없습니다. 내가 기억하는 것은 내가 그 함수들을 필요로하지 않고 여전히 전역 변수들이 메인 루프에 영향을 미치도록 설정할 수 있다는 것이다. 또는 내가 놓친 세부 사항이 있습니까? 알아내는 데 약간의 단서를주세요. 혼란 스럽습니다.

+0

외부 링크를 사용하지 말고 여기에 코드를 게시하십시오. –

+3

ISR에있는 동안은 더 나쁜 생각입니다 ... 혹시 ... 그 형식을 비 인터럽트 코드로 복사 한 것 같습니다. – LPs

+0

인터럽트가 작동하는 방식에 대한 몇 가지 중요한 오해가있는 것처럼 보입니다. 코드가 누락되었습니다. [ask]를 읽고 조언을 따르십시오! – Olaf

답변

0

확실하지는 않겠지 만 오류로 인해 문제가 설명 될 수 있습니다.

RXFlag의 선언은 포함되어 있지 않지만 사용자가 선언하지 않은 것으로 추정됩니다. volatile. 그렇게하지 않으면 컴파일러는 해당 변수에 어떤 일이 발생할지 모든 것을 알고 있다고 가정 할 수 있습니다. 특히 main()이 다른 함수를 호출하지 않으면 RxFlag의 값이 절대로 변경되지 않는다는 것을 알고 있습니다. 따라서 루프 밖으로 이동하여 표현식을 최적화 할 수 있습니다. 실제로는 다음과 같이 코드를 변경하는 것 : main() 다른 함수를 호출하는 경우

#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; 

     } 
    } 
} 

그러나, 다음 컴파일러가 전화를 통해 레지스터에 RxFlag을 유지하기 위해 노력하고 포기한다. 다른 함수는 RxFlag가 보유하고있는 레지스터를 변경할 수 있습니다. 스택이나 뭔가에 밀어 넣어야합니다. 다시 읽기는 코드와 시간이 더 저렴하므로 루프를 돌 때마다 읽습니다.

이 버그에 대한 올바른 수정 프로그램은 주 스레드와 ISR간에 공유되는 모든 변수를 volatile으로 선언하는 것입니다.

+0

gcc의 경우, AVR 레지스터의 절반이 * callee-saved *입니다. gcc는 최적화 할 때 gcc를 사용하고 함수 호출에서도 레지스터에 값을 보관할 수 있습니다. 함수 호출도 인라인 될 수 있으므로 옵티마이 저가 호출로서 발생하지 않습니다. – JimmyB

관련 문제