1

ATmega162 USART を起動して実行しようとしています。このコードは、私が期待していることを正確に実行します。

#define F_CPU 14745600UL
#define UBRR_1 F_CPU / 16 / 9600 - 1
#define UBRR_2 F_CPU / 16 / 31250 - 1

#include <inttypes.h>

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

int main(){
  uint16_t ubrr1 = UBRR_1;

  UBRR0H = (uint8_t)(ubrr1 >> 8);
  UBRR0L = (uint8_t)ubrr1;
  UCSR0B = _BV(TXEN0);
  UCSR0C = _BV(URSEL0) | _BV(UCSZ00) | _BV(UCSZ01);

  uint16_t ubrr2 = UBRR_2;

  UBRR1H = (uint8_t)(ubrr2 >> 8);
  UBRR1L = (uint8_t)ubrr2;
  UCSR1B = _BV(RXEN1);
  UCSR1C = _BV(URSEL1) | _BV(UCSZ10) | _BV(UCSZ11);

  DDRB = _BV(PB0) | _BV(PB1);

  PORTB |= _BV(PB0);

  while (1){
    PORTB ^= _BV(PB0);
    _delay_ms(50);

    // byte received on usart 1
    if ((UCSR1A & _BV(RXC1)) != 0){

      // usart 0 ready to write
      if ((UCSR0A & _BV(UDRE0)) != 0){
        uint8_t b = UDR1;
        UDR0 = b;
      }
    }
  }

  return 0;
}

つまり、2 つの USART を異なるボー レートで初期化し、USART1 から読み取り、USART0 に書き込みます。よく働く。はい、_delay_ms() がタイミングを乱していることはわかっていますが、この例では問題なく動作します。ここで、USART1 で RX 割り込みを有効にして適切なベクターを追加するとすぐに、メイン ループの実行が停止します (少なくとも LED は点滅しません)。

#define F_CPU 14745600UL
#define UBRR_1 F_CPU / 16 / 9600 - 1
#define UBRR_2 F_CPU / 16 / 31250 - 1

#include <inttypes.h>

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

int main(){
  uint16_t ubrr1 = UBRR_1;

  UBRR0H = (uint8_t)(ubrr1 >> 8);
  UBRR0L = (uint8_t)ubrr1;
  UCSR0B = _BV(TXEN0);
  UCSR0C = _BV(URSEL0) | _BV(UCSZ00) | _BV(UCSZ01);

  uint16_t ubrr2 = UBRR_2;

  UBRR1H = (uint8_t)(ubrr2 >> 8);
  UBRR1L = (uint8_t)ubrr2;
  UCSR1B = _BV(RXEN1);
  UCSR1C = _BV(URSEL1) | _BV(UCSZ10) | _BV(UCSZ11);

  DDRB = _BV(PB0) | _BV(PB1);

  // enable usart1 rx interrupt
  UCSR1B |= _BV(RXCIE1);

  PORTB |= _BV(PB0);

  // enable interrupts
  sei();

  while (1){
    PORTB ^= _BV(PB0);
    _delay_ms(50);
  }

  return 0;
}

ISR(USART1_RXC_vect){
  uint8_t byte = UDR1;

  if ((UCSR0A & _BV(UDRE0)) != 0){
    UDR0 = byte;
  }
}

最も奇妙な部分は、プログラムの動作を停止させるのはsei();and行ではなく、ISR の存在です。UCSR1B |= _BV(RXCIE1);その関数をコメント アウトするとすぐに、メイン ループが正常に実行されます。どこかでフラグを逃したのですか?

4

1 に答える 1

0

これは、M161C ヒューズ ビット (拡張ヒューズ バイト内) がプログラムされたことが原因である可能性があります。これにより、ATmega162 が ATmega161 互換モードになり、デバイスの割り込みベクタ テーブルのレイアウトが異なります (コンパイラはこれを認識しません)。詳細については、57 ページのリンクの説明を参照してください。-mmcu=atmega161 でコンパイルし、問題が解決するかどうかを確認することで、これをテストできます。

UDR1 レジスタが IO レジスタ マップの別の場所にあるため、ATmega162 ではなく (ほとんど同じように見える) ATmega16 でこのコードを実行すると、同様の動作が発生する可能性があります。つまり、RXC 割り込みフラグは決してクリアされ、ハンドラーは永久に再入力されます。avr-objdump で逆アセンブルすると、コンパイラが使用しているレジスタ値を確認できます。

于 2013-10-19T14:11:51.917 に答える