TIMER0_OVF_vect

概要

TIMER0_OVF_vectは、タイマ/カウンタ0(TCNT0)がオーバーフローしたときに起動される割り込みハンドラです。Arduinoを起動してからの時間を管理するために利用しています。

TCNT0は8ビットのタイマ/カウンタなので、256回インクリメントするとオーバーフローします。また、タイマ/カウンタのクロックは分周比64に設定されているので、64クロックに1回インクリメントします。このため、この割り込みハンドラは256*64=16384クロックに1回起動されます。

ソースコード

TIMER0_OVF_vectは、hardware/arduino/avr/cores/arduino/wiring.c に定義されています。以下に全ソースコードを示します。

 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
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
 
// the whole number of milliseconds per timer0 overflow
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
 
// the fractional number of milliseconds per timer0 overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)
 
volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;
 
ISR(TIMER0_OVF_vect)
{
    // copy these to local variables so they can be stored in registers
    // (volatile variables must be read from memory on every access)
    unsigned long m = timer0_millis;
    unsigned char f = timer0_fract;
 
    m += MILLIS_INC;
    f += FRACT_INC;
    if (f >= FRACT_MAX) {
        f -= FRACT_MAX;
        m += 1;
    }
 
    timer0_fract = f;
    timer0_millis = m;
    timer0_overflow_count++;
}

MICROSECONDS_PER_TIMER0_OVERFLOWは、タイマ/カウンタ0がオーバーフローするまでに要する時間をマイクロ秒で表したもので、64*256クロック経過するのに必要な時間です。clockCyclesToMicroseconds()は、指定したクロック数をマイクロ秒に変換するマクロです。

MILLIS_INCは、タイマ/カウンタ0がオーバーフローするまでに要する時間をミリ秒で表したものです。

FRACT_INCは、タイマ/カウンタ0がオーバーフローするまでに要する時間のうち、ミリ秒未満の値を示します。Arduino Unoでは、本来であれば24(=1024-1000)です。FRACT_MAXは、FRCAT_INCがとりうる値(999)+1です。FRACT_INCとFRACT_MAXは、最大で1000なので、10ビット必要となりますが、1バイトに収めるために、3ビット右にシフトしています。FRACT_INCは、Arduino Unoでは24で、2進数で表すと0b11000、FRACT_MAX(1000)は2進数で表すと0b1111101000となり、どちらも、下3桁は0なので、3ビット右にシフトしても精度に影響は出ません。このため、FACT_INCは3(=24»3)に設定し、FRACT_MAXは125に設定しています。

timer0_overflow_countは、Arduinoを起動してからこの割り込みハンドラが呼び出された回数を保持する変数です。

timer0_millisは、Arduinoを起動してから経過した時間のミリ秒部分を保持します。timer0_fractは、Arduinoを起動してから経過した時間のミリ秒未満部分をマイクロ秒単位を3ビット右シフトした値を保持します。

ISR()は、割り込みハンドラを定義する際に利用するマクロです。関数の属性を指定して、割り込みハンドラでの利用を示します。

timer0_millisとtimer0_fractを、それぞれ、自動変数のmとfにコピーします。

18
19
20
21
22
23
ISR(TIMER0_OVF_vect)
{
    // copy these to local variables so they can be stored in registers
    // (volatile variables must be read from memory on every access)
    unsigned long m = timer0_millis;
    unsigned char f = timer0_fract;

コメントによると、timer0_millisとtimer0_fractは、volitileと指定しているため、メモリから読み込む必要があると書かれています。

この割り込みハンドラは、タイマ/カウンタ0がオーバフローするたびに呼び出され、前回オーバーフローしてから今回オーバーフローするまでの時刻のミリ秒部分であるMILLIS_INCをmに足します。同様に、FRACT_INCをfに足します。

fがFRAC_MAX以上であれば、マイクロ秒部分が1000を超えてミリ秒になったということなので、fからFRAC_MAXを引き、mに1を足します。

25
26
27
28
29
30
    m += MILLIS_INC;
    f += FRACT_INC;
    if (f >= FRACT_MAX) {
        f -= FRACT_MAX;
        m += 1;
    }

その後、fとmをもとの変数に書き戻します。

最後に、timer0_overflow_cout(この割り込みハンドラが呼び出された回数)をインクリメントします。

32
33
34
35
    timer0_fract = f;
    timer0_millis = m;
    timer0_overflow_count++;
}

バージョン

Arduino AVR Boards 1.8.6

最終更新日

March 21, 2023

inserted by FC2 system