タイマーを使用してISRの変数を更新する方法


8

Timer3の周波数をカウンターで確認しようとしています。揮発性として宣言されたカウンターの値はISRでインクリメントされ、毎秒合計がメインループに表示され、値はゼロにリセットされます。

タイマーは正しく設定されています。(3Hzタイマーを選択すると、LEDが点滅します)

問題

カウンターはインクリメントされません。出力は次のとおりです。

Setup Completed
tick: 1
tick: 0
tick: 0
tick: 0

コード

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);

  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B = 20; // 800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();

  Serial.println("Setup completed");
}

void loop()
{
  if (millis() % 1000 == 0)
  {
    Serial.print(" tick: ");
    Serial.println(cont);
    cont = 0;
  }
}

ISR(TIMER3_COMPB_vect)
{
  //digitalWrite(13, digitalRead(13) ^ 1);
  cont++;
}

EDIT このタイマーは、加速度計からanlog値を読み取り、floatの配列に格納するために使用されます。しかし、現時点では、このアップデートの問題に行き詰まっています。

ソリューション1 Gerbenのおかげ

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3A = 20; // 20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  delay(1000);
  Serial.println(cont);
  cont = 0;
}

ISR(TIMER3_COMPB_vect)
{
  cont++;
}

ソリューション2 BrettMのおかげで

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B =  20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  //TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  Serial.println(cont); 
  cont = 0;
  delay(1000);

}

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

そして、digitalWrite行のコメントを外すと、LEDが毎秒約1回(0.66秒ごとに)点滅します。
Ricardo

はい、コメントを外してLEDの点滅をdigitalWrite設定OCR3B = 5;すると、その頻度で点滅します。
UserK、2014

それからそれは謎です。cont = 0;ループの内側をコメントアウトしてみましたか?次に何が起こりますか?
Ricardo

1
頻度を増やしてみてください。どういうわけか、あなたのifステートメントは、割り込みが呼び出されるよりも頻繁にカウンターをクリアしているのではないかと思います。しかし、出力にはさらに多くのものが表示されるはずです。また、実行時間を長くした場合(たとえば1分)、結果を貼り付けます。また、質問を更新するときは、古い出力をそのままにして、質問が(編集履歴なしで)意味をなすようにします。
リカルド

1
割り込みルーチンが一度だけ呼び出されてから無効にされているのではないかと思います。割り込みコードの実行中に割り込みが無効にされることをどこかで読んだことがありますが、場合によっては再度有効にする必要がありますが、それが正しいかどうかは本当にわかりません。うまくいけば、より知識のある誰かが私たちの救助に来るでしょう...
Ricardo

回答:


5

CTCモードでは、トップではOCR3AありませんOCR3B

それは、後にTIMSK3 |= (1 << OCIE3B);もに変更しなければならないTIMSK3 |= (1 << OCIE3A);、とISR(TIMER3_COMPB_vect)しますISR(TIMER3_COMPA_vect)

3Hzの場合、OCR3A20ではなく5208 にする必要があります。

技術的にTCCR3B |= (1 << WGM12);TCCR3B |= (1 << WGM32);


構成では、カウンターは更新されず、毎秒「セットアップが完了しました」という文(setup()関数に記述されています!)が表示されます。本当に奇妙な行動。
UserK、2014

を使用して解決されましたTIMSK3 |= (1 << OCIE3B);。ガーベンありがとう!回答を変更してください。解決策として受け入れます。
UserK、2014

1
ISRベクトルの変更も必要であるという言及を忘れていました。ISR(TIMER3_COMPB_vect)する必要がありますISR(TIMER3_COMPA_vect)。ISRが定義されていない場合、AVRはあなたが経験していたように、それ自体をリセットします。うまくいきました。
Gerben

3

CTCモードはOCR3A Gerbenでのみ機能することを指摘してくれてありがとう、この質問に対する私の答えは以前は不完全だったようです。投稿する前にテストを行わなかったことをお詫びします。

この質問のみの情報を考慮して、Gerbenの回答は完全ですが、他の質問は、サーボライブラリが原因でOCR3Aを使用できないことを示唆しているため、少し追加します。(私もその答えを編集しました)

割り込みルーチンでTCNT3を0に設定することにより、CTCモードの動作をエミュレートできます。コードでCTCモードをオンにする行を忘れずに削除してください。

このISRでコードをテストしました。

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

タイマーレジスタのこの構成

OCR3B = 5208; // 800Hz 5; // 3 Hz
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);

これは高周波数ではCTCよりも少し正確ではないかもしれませんが、わかりませんが、3Hzでは完全に機能しました。5208は20ではなく正しいOCR値であることに注意してください(これもGerbenのおかげです)。


私はあなたのコードを試しましたが、カウンターはインクリメントされていません。あなたが言ったようTCNT3=0;に、ISR()にを追加//TCCR3B |= (1 << WGM32);し、setup()で削除し ました。私もcont=0;行をコメントアウトしようとしましたが、何も変更されませんでした
UserK

1
コードが他のすべての方法で質問に投稿されたものと一致することを確認してください。ループをに変更してみてくださいprintln(cont); delay(1000);。また、あなたはまだcli()とTCCR3Aなどが正しいビットを含めていますか?
BrettAM 2014

わかりました。800 Hzでも正確です。
UserK、2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.