コンテンツにスキップ

05. タイマー割り込み

AVR のタイマ割り込みを使う

タイマー割り込み #Arduino - Qiita

事前知識

タイマー割り込みとは

タイマー割り込みとは、マイコン内蔵のタイマーが発火したときメインループを中断して任意の処理を行うことができる機能である。

タイマーについて

ATmega328P は 8 ビットの Timer0、16 ビットの Timer1、8 ビットの Timer2 を持つ。

タイマーはそれぞれクロックが入るたびに 1 だけカウントしていき、オーバーフローしたら割り込みが入る。(後述する CTC を使う場合は CTC の設定値を超えたときに割り込みが入る。)

クロック周波数 16Mhz で 8 ビットのタイマーを使ったとき、カウンターの最大値は \(2^8\) なので 16us 間隔の発火になる。

\[ \frac{1}{16 \times 1000 \times 1000} \times 2^8 = 16 \times 10^{-6} \mathrm{s} \]

タイマー割り込みの間隔をもっと短くしたい場合は CTC を使えば良い。

タイマー割り込みの間隔をもっと長くしたい場合は 16 ビットのタイマーを使うなり、後述するプリスケーラを使えば良い。

CTC

通常タイマーはカウンターがオーバーフローしたら発火するが、CTC(Counter Timer Circuit)という方式を使うとカウンターが一定の値になったときに割り込みを発火させることができる。これを使って割り込み間隔を細かくできる。

プリスケーラ

プリスケーラを使うとタイマーのカウンターを遅らせることができる。ATmega328P では 8 分割、64 分割、256 分割、1024 分割に対応している。8 分割だと8 数えるたびにタイマーをカウントするみたいな感じになる。

実装例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#define F_CPU 16000000UL

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

ISR(TIMER0_COMPA_vect)  //タイマ割り込み
{
  PORTB ^= 0b00100000;    // PB5をビット反転させる
}

int main(void) {
  DDRB  = 0b11111111;   // PBxのピンのうち、全てを出力に設定する
  PORTB = 0b00000000;   // PBxのピン全ての出力を0にする

  // TCCR0Aレジスタ
  // 以下WGM02が0の場合
  // 0b******00: タイマーが0xFFになったら割り込み発火
  // 0b******10: CTC(タイマーが任意の値になったら発火)
  TCCR0A = 0b00000010;   // CTC有効

  // OCR0Aレジスタ
  OCR0A = 0xff;    // CTCの上限値。255にすると255クロックで割り込み発火。

  // TCCR0Bレジスタ
  // 0b*****xxx: 分周率の設定(001: プリスケールなし, 010: 8分割, 011: 64分割)
  TCCR0B = 0b00000001;  // これを有効にしないとワンショットになる

  // TIMSK0レジスタ
  // 0b*****x**: OCIE0B。Timer0の比較一致B割り込みの許可。
  // 0b******x*: OCIE0A。Timer0の比較一致A割り込みの許可。このビットを1に設定すると、OCR0Aに設定した値に達したときに割り込みが発生する。
  // 0b*******x: TOIE0。Timer0のオーバーフロー割り込み許可。
  TIMSK0 |= (1 << OCIE0A);

  // 割り込みを有効にする
  sei();

  while(1) {
    ;
  }

  return 0;
}

なおcli()を呼ぶと割り込みを無効にできる。

出力波形

16us で割り込みが入っていることが分かる。

割り込み間隔を短くしてみる

OCR0Aを小さくすることで割り込み間隔を短くできる。

OCR0A=0x7F(127)

8us。OK。

OCR0A=0x3F(63)

4us。OK。

OCR0A=0x1F(31)

2us になるはずだが、やや遅れてしまっている。

OCR0A=0x0F(15)

1us になるはずだが、もはや追従していない。

まとめ

タイマー割り込みを使うとより制御の幅が広がる。

ただしタイマー割り込みの処理にも限界がある。単純なパルス生成は 4us が限界である。

割り込みにパルス生成以外もやらせようとしたらさらに限界が下がることを理解しておく必要がある。