2017-01-09 6 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(); 
} 

問題であり、Iは、USARTからいくつかの件のデータを受信したときに、私はRxFlagを設定しようとしたそのメインループ中の活性ザif文缶。しかし、_delay_ms()やprintf()のようなif文の前に関数のコメントを外すまでは機能しませんでした。

意味がありません。私が覚えているのは、これらの関数は必要なく、メイン変数に影響するグローバル変数を設定できることです。それとも、私が逃した詳細はありますか?私はそれを理解するためのいくつかの手がかりを与えてください、私は混乱しています。

+0

外部リンクではなく、ここにコードを掲載してください。 –

+3

ISRの中では悪い考えです...今まで...私はあなたがその形式を非割り込み駆動コードにコピーしたと思います。 – LPs

+0

割り込みの仕組みに関するいくつかの大きな誤解があるようです。そしてコードがありません。 [ask]を読んでアドバイスに従ってください! – Olaf

答えて

0

これは明確ではありませんが、これはあなたの問題を説明していると思われますので、エラーである可能性があります。

RXFlagの宣言は含まれていませんが、あなたはそれをvolatileと宣言していないと推測します。そうしない限り、コンパイラは、その変数に何が起こるかすべてを知っていると想定することができます。特に、main()が他の関数を呼び出さない限り、RxFlagの値は決して変更されないことがわかります。したがって、ループの外側に移動することによってifの式を最適化することができます。実際に、それは次のようにコードを変更しています:

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

     } 
    } 
} 

main()が別の関数を呼び出す場合は、コンパイラは、その呼び出しを超えるレジスタにRxFlagを維持しようと断念。他の関数は、RxFlagが保持されているレジスタを変更する可能性があります。スタックなどにプッシュする必要があります。それをもう一度読むことは、コードと時間が安くなるので、ループの回りを回るたびに読み込まれます。

このバグの正しい修正は、メインスレッドとISRの間で共有される変数をすべてvolatileとして宣言することです。

+0

gccの場合、AVRレジスタの半分は* callee-saved *です。そして、gccは最適化時にgccを利用し、関数呼び出しを越えてもレジスタに値を保持します。関数呼び出しもインライン化されるため、オプティマイザは呼び出しとして実行されることさえありません。 – JimmyB

関連する問題