LECTURE 8 タイマ/カウンタ1を使う

○ はじめに

前回 は、タイマ/カウンタ0 を使って LED を点滅させてみました。今回はタイマ/カウンタ1 を使って同じことをしてみようと思います。

○ 関連レジスタ

タイマ/カウンタ1関連のレジスタを以下に紹介します。マクロについては、avr-libc で使用できる定義名を掲載しています。また、日本語のレジスタ名とビット名は、英語の定義名称を適当に訳してます。

  • タイマ/カウンタ1制御レジスタA(TCCR1A)

    ビット番号 7 6 5 4 3 2 1 0
    マクロ COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10
    初期値 0 0 0 0 0 0 0 0

    各ビットの説明を以下に書きます。

    ビット名 内容
    COM1A1/COM1A0
    COM1B1/COM1B0(比較1出力モード)
    OC1A/OC1B ピン(PDIP パッケージでは 19/18 ピン)の出力方式を設定します。

    • WGM11 = WGM10 = 0 の場合(標準動作、CTC動作)(?=A/B)
      COM1?1 COM1?0 内容
      0 0 OC1? には出力されない
      0 1 比較一致において反転
      1 0 比較一致において 0(Low)
      1 1 比較一致において 1(High)

    • WGM13-10=0101/0110/0111/1110/1111 の場合(高速PWM)(?=A/B)
      COM1?1 COM1?0 内容
      0 0 OC1? には出力されない
      0 1 WGM13-10=1111 の場合は比較一致で OC1A 反転、OC1B は出力されない。 WGM13-10=それ以外の場合は OC1? には出力されない
      1 0 比較一致で 0(Low)、TCNT1 = 0 で 1(High)
      1 1 比較一致で 1(High)、TCNT1 = 0 で 0(Low)

    • WGM13-10=0001/0010/0011/1000/1001/1010/1011 の場合(位相基準PWM)(?=A/B)
      COM1?1 COM1?0 内容
      0 0 OC1? には出力されない
      0 1 WGM13-0=10x1 の場合は比較一致で OC1A 反転、OC1B は出力されない。 それ以外は OC1? には出力されない
      1 0 TCNT1 上昇時の比較一致で 0(Low)、下降時の比較一致で 1(High)
      1 1 TCNT1 上昇時の比較一致で 1(High)、下降時の比較一致で 0(Low)

    FOC1A/FOC1B(OC1A/OC1B出力強制) 動作種別が標準動作および比較一致タイマ/カウンタクリアの場合に、1 を設定することで強制的に比較一致を発生させます。割り込みやタイマ/カウンタのクリアは行われず、OC1A/OC1B ピンの出力のみ変更になる様です。自分は使い所がよく分りませんが…
    WGM11/WGM10(波形生成モード) TCCR1B レジスタの WGM13-12ビットと併せて動作種別(LECTURE 6 タイマ/カウンタについてを参照)を設定します。

    WGM13 WGM12 WGM11 WGM10 動作種別
    0 0 0 0 標準動作
    0 0 0 1 8ビット位相基準PWM動作
    0 0 1 0 9ビット位相基準PWM動作
    0 0 1 1 10ビット位相基準PWM動作
    0 1 0 0 比較一致タイマ/カウンタクリア(CTC)動作(OCR1Aピンがカウンタ最大値)
    0 1 0 1 8ビット高速PWM動作
    0 1 1 0 9ビット高速PWM動作
    0 1 1 1 10ビット高速PWM動作
    1 0 0 0 位相/周波数基準PWM動作(ICR1ピンがカウンタ最大値)
    1 0 0 1 位相/周波数基準PWM動作(OCR1Aピンがカウンタ最大値)
    1 0 1 0 位相基準PWM動作(ICR1ピンがカウンタ最大値)
    1 0 1 1 位相基準PWM動作(OCR1Aピンがカウンタ最大値)
    1 1 0 0 比較一致タイマ/カウンタクリア(CTC)動作(ICR1ピンがカウンタ最大値)
    1 1 0 1 予約
    1 1 1 0 高速PWM動作(ICR1ピンがカウンタ最大値)
    1 1 1 1 高速PWM動作(OCR1Aピンがカウンタ最大値)


  • タイマ/カウンタ1制御レジスタB(TCCR1B)

    ビット番号 7 6 5 4 3 2 1 0
    マクロ ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
    初期値 0 0 0 0 0 0 0 0

    各ビットの説明を以下に書きます。

    ビット名 内容
    ICNC1(捕獲入力1ノイズ消去器) 1 に設定することで、捕獲入力ノイズ消去器が有効になります。
    ICES1(捕獲入力1エッジ選択) 1を設定すると ICP1 ピンの立ち上がりエッジで捕獲を認識し、0 を設定すると立下りエッジで捕獲を認識します。
    WGM13/WGM12(波形生成モード) TCCR1A レジスタの WGM11-10ビット説明を参照
    CS12/CS11/CS10(クロック選択) タイマ/カウンタ1で使用するクロックのシステムクロックに対する分周比、あるいは外部クロックの使用を以下の組み合わせで設定します。

    CS12 CS11 CS10 内容
    0 0 0 タイマ/カウンタ0停止
    0 0 1 分周比無し
    0 1 0 CK/8
    0 1 1 CK/64
    1 0 0 CK/256
    1 0 1 CK/1024
    1 1 0 外部クロック。T1 ピン(PDIP パッケージでは 2 ピン)の立ち下がりエッジ
    1 1 1 外部クロック。T1 ピン(PDIP パッケージでは 2 ピン)の立ち上がりエッジ


  • タイマ/カウンタ1カウンタ(TCNT1H,TCNT1L)(TCNT1 として 2 バイトアクセス可能)

    16 ビットのカウンタ値を格納するレジスタです。
    TCNT1 として 2 バイトアクセスする場合は、 アクセス時に割り込みが起きない様にしてください。

    --- TCNT1H ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0

    --- TCNT1L ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0


  • タイマ/カウンタ1比較Aレジスタ(OCR1AH,OCR1AL)(OCR1A として 2 バイトアクセス可能)

    TCNT1 との比較に使われる 16 ビットレジスタです。
    OCR1A として 2 バイトアクセスする場合は、 アクセス時に割り込みが起きない様にしてください。

    --- OCR1AH ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0

    --- OCR1AL ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0


  • タイマ/カウンタ1比較Bレジスタ(OCR1BH,OCR1BL)(OCR1B として 2 バイトアクセス可能)

    TCNT1 との比較に使われる 16 ビットレジスタです。
    OCR1B として 2 バイトアクセスする場合は、 アクセス時に割り込みが起きない様にしてください。

    --- OCR1BH ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0

    --- OCR1BL ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0


  • タイマ/カウンタ1捕獲レジスタ(ICR1H,ICR1L)(ICR1 として 2 バイトアクセス可能)

    ICP1 ピンで捕獲を認識した時点の TCNT1 の値を格納する 16 ビットレジスタです。
    ICR1 として 2 バイトアクセスする場合は、 アクセス時に割り込みが起きない様にしてください。

    --- ICR1H ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0

    --- ICR1L ---

    ビット番号 7 6 5 4 3 2 1 0
    マクロ - - - - - - - -
    初期値 0 0 0 0 0 0 0 0


  • タイマ/カウンタ割り込みマスクレジスタ(TIMSK)(タイマ/カウンタ間共通)
    ※タイマ/カウンタ1に関係有るのは TICIE1/OCIE1A/OCIE1B/TOIE1 です。

    ビット番号 7 6 5 4 3 2 1 0
    マクロ OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0
    初期値 0 0 0 0 0 0 0 0

    各ビットの説明を以下に書きます。

    ビット名 内容
    TICIE1(捕獲割り込み許可) 1 を設定すると、捕獲割り込みが有効になります。
    OCIE1A(比較A一致割り込み許可) 1 を設定すると、比較A一致割り込みが有効になります。
    OCIE1B(比較B一致割り込み許可) 1 を設定すると、比較B一致割り込みが有効になります。
    TOIE1(オーバーフロー割り込み許可) 1 を設定するとオーバーフロー割り込みが有効になります。


  • タイマ/カウンタ割り込み要求フラグレジスタ(TIFR)(タイマ/カウンタ間共通)
    ※タイマ/カウンタ1に関係有るのは ICF1/OCF1A/OCF1B/TOV1 です。

    ビット番号 7 6 5 4 3 2 1 0
    マクロ OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 OCF0 TOV0
    初期値 0 0 0 0 0 0 0 0

    各ビットの説明を以下に書きます。

    ビット名 内容
    ICF1(捕獲フラグ) ICP1 ピンで捕獲を認識した場合に 1 が設定されます。割り込み処理時に自動的に 0 となる他、1 を書き込むことで 0 となります。
    OCF1A(比較A一致フラグ) TCNT1 と OCR1A の値が一致した場合に 1 が設定されます。割り込み処理時に自動的に 0 となる他、1 を書き込むことで 0 となります。
    OCF1B(比較B一致フラグ) TCNT1 と OCR1B の値が一致した場合に 1 が設定されます。割り込み処理時に自動的に 0 となる他、1 を書き込むことで 0 となります。
    TOV1(オーバーフローフラグ) TCNT1 でのオーバーフロー発生時に 1 が設定されます。割り込み処理時に自動的に 0 となる他、1 を書き込むことで 0 となります。

○ 回路図

LECTURE 1 ATmega8535 および使用環境について に掲載してある全体回路図に対して、点滅させる LED 部分を赤枠で囲んだ図をこちらに置いておきます。…とは言っても、LECTURE 2 LED を点滅させる と全く同じなのでそちらの図へのリンクです。

○ サンプルプログラムと説明

タイマ/カウンタ1を使って LED を点滅させるサンプルプログラムを 08timer1.tar.gz からダウンロードできます。はじめに のページから、全てのサンプルプログラムを 固めた tar ファイルをダウンロードすることもできます。

中には

  • Makefile
  • util.h
  • util.c
  • timer1.h
  • timer1.c
  • main-ov.c
  • main-comp.c

が格納されています。util.h/util.c については LECTURE 4 A/D 変換でボリューム(可変抵抗)値を読む の内容と同じで Makefile もほとんど変わらないので、それ以外について以下に載せます。なお、以下に掲載しているソースコードには修正 BSD ライセンス条項を含めていませんが、ソースコード配布は修正 BSD ライセンスに従います(はじめに のページの免責事項を参照してください)。

これまでにヒューズビットの設定を行ったことが一度も無い場合は、まず最初に make fuse を実行してください。fuse ターゲットについては、LECTURE 2 LED を点滅させる のサンプルプログラムの項を参照してください。

make 実行後、オーバーフロー割り込みを使用したプログラムをアップロードする場合は make uisp-ov を実行してください。また、比較一致割り込みを使用したプログラムをアップロードする場合は make uisp-comp を実行してください。実装方法が異なるだけで動作内容は同じです。

LED が約 500ms 毎に(1 秒間に 2 回程)ON/OFF を繰り返します。前回 と動作内容が同じなので、動画は載せません。

  • timer1.h
        1    #ifndef ___TIMER1_H_INCLUDED_
        2    #define ___TIMER1_H_INCLUDED_
        3    
        4    #include <avr/io.h>
        5    #include <inttypes.h>
        6    
        7    
        8    /* タイマークロック選択用マクロ */
        9    #define TIMER1_STOP      0x00
       10    #define TIMER1_CK        (_BV(CS10))
       11    #define TIMER1_CK_8      (_BV(CS11))
       12    #define TIMER1_CK_64     (_BV(CS11) | _BV(CS10))
       13    #define TIMER1_CK_256    (_BV(CS12))
       14    #define TIMER1_CK_1024   (_BV(CS12) | _BV(CS10))
       15    
       16    /* 比較出力モード選択用マクロ */
       17    #define COM_A_NONE       0x00
       18    #define COM_A_TOGGLE     (_BV(COM1A0))
       19    #define COM_A_HIGH_FIRST (_BV(COM1A1))
       20    #define COM_A_LOW_FIRST  (_BV(COM1A1) | _BV(COM1A0))
       21    
       22    #define COM_B_NONE       0x00
       23    #define COM_B_TOGGLE     (_BV(COM1B0))
       24    #define COM_B_HIGH_FIRST (_BV(COM1B1))
       25    #define COM_B_LOW_FIRST  (_BV(COM1B1) | _BV(COM1B0))
       26    
       27    /* 波形生成種別選択用マクロ */
       28    #define WGM1_NORMAL         0x00
       29    #define WGM1_CTC_ICR1       (_BV(WGM13) | _BV(WGM12))
       30    #define WGM1_CTC_OCR1A      (_BV(WGM12))
       31    #define WGM1_FAST_PWM_ICR1  (_BV(WGM13) | _BV(WGM12) | _BV(WGM11))
       32    #define WGM1_FAST_PWM_OCR1A (_BV(WGM13) | _BV(WGM12) | _BV(WGM11) | _BV(WGM10))
       33    
       34    #define timer1_ov_enable()         { TIMSK |= _BV(TOIE1); }
       35    #define timer1_ov_disable()        { TIMSK &= ~_BV(TOIE1); }
       36    #define timer1_compa_enable()      { TIMSK |= _BV(OCIE1A); }
       37    #define timer1_compa_disable()     { TIMSK &= ~_BV(OCIE1A); }
       38    #define timer1_compb_enable()      { TIMSK |= _BV(OCIE1B); }
       39    #define timer1_compb_disable()     { TIMSK &= ~_BV(OCIE1B); }
       40    #define timer1_ic_enable()         { TIMSK |= _BV(TICIE1); }
       41    #define timer1_ic_disable()        { TIMSK &= ~_BV(TICIE1); }
       42    #define timer1_clear_coma_mode()   { TCCR1A &= ~(_BV(COM1A1) | _BV(COM1A0)); }
       43    #define timer1_clear_comb_mode()   { TCCR1A &= ~(_BV(COM1B1) | _BV(COM1B0)); }
       44
       45    #define timer1_stop()\
       46           { TCCR1B &= ~(_BV(CS12) | _BV(CS11) | _BV(CS10)); }
       47    
       48    #define timer1_set_coma_mode(mode) {\
       49            timer1_clear_coma_mode();\
       50            TCCR1A |= (mode) & (_BV(COM1A1) | _BV(COM1A0));\
       51    }
       52    
       53    #define timer1_set_comb_mode(mode) {\
       54            timer1_clear_comb_mode();\
       55            TCCR1A |= (mode) & (_BV(COM1B1) | _BV(COM1B0));\
       56    }
       57    
       58    #define timer1_clear_wave_mode()   {\
       59            TCCR1A &= ~(_BV(WGM11) | _BV(WGM10));\
       60            TCCR1B &= ~(_BV(WGM13) | _BV(WGM12));\
       61    }
       62    
       63    #define timer1_set_wave_mode(mode) {\
       64            timer1_clear_wave_mode();\
       65            TCCR1A |= (mode) & (_BV(WGM11) | _BV(WGM10));\
       66            TCCR1B |= (mode) & (_BV(WGM13) | _BV(WGM12));\
       67    }
       68    
       69    #define timer1_start(clock) {\
       70            timer1_stop();\
       71            TCCR1B |= (clock) & (_BV(CS12) | _BV(CS11) | _BV(CS10));\
       72    }
       73    
       74    /*
       75     * TCNT1 に設定するカウンタ値を指定する。
       76     *
       77     * 16ビットレジスタにアクセスするため、16ビットレジスタ用の
       78     * 一時レジスタへの他アクセスが起きない状態で実行すること。
       79     */
       80    static inline void 
       81    timer1_set_count(uint16_t count)
       82    {
       83            TCNT1 = count;
       84    }
       85    
       86    
       87    /*
       88     * OCR1A に設定するカウンタ値を指定する。
       89     *
       90     * 16ビットレジスタにアクセスするため、16ビットレジスタ用の
       91     * 一時レジスタへの他アクセスが起きない状態で実行すること。
       92     */
       93    static inline void
       94    timer1_set_ocr1a(uint16_t ocr1a)
       95    {
       96            OCR1A = ocr1a;
       97    }
       98    
       99    
      100    /*
      101     * OCR1A に設定するカウンタ値を指定する。
      102     *
      103     * 16ビットレジスタにアクセスするため、16ビットレジスタ用の
      104     * 一時レジスタへの他アクセスが起きない状態で実行すること。
      105     */
      106    static inline void
      107    timer1_set_ocr1b(uint16_t ocr1b)
      108    {
      109            OCR1B = ocr1b;
      110    }
      111    
      112    
      113    /*
      114     * ICR1 に設定するカウンタ値を指定する。
      115     *
      116     * 16ビットレジスタにアクセスするため、16ビットレジスタ用の
      117     * 一時レジスタへの他アクセスが起きない状態で実行すること。
      118     */
      119    static inline void
      120    timer1_set_icr1(uint16_t icr1)
      121    {
      122            ICR1 = icr1;
      123    }
      124    
      125    
      126    void timer1_ov_set_interrupt(void (*func)(void));
      127    void timer1_compa_set_interrupt(void (*func)(void));
      128    void timer1_compb_set_interrupt(void (*func)(void));
      129    void timer1_ic_set_interrupt(void (*func)(void));
      130    
      131    
      132    #endif
      133    
      134    /* End of timer1.h */
    
    
    • 8 〜 14 行目

      タイマ/カウンタ1 用のクロック指定を楽にできる様にマクロを定義しています。TCCR1B レジスタの CS12-10 ビットに対応するビットを _BV() マクロで設定しています。本マクロは 後述の timer1_start() マクロ実行時に指定します。

    • 16 〜 25 行目

      比較出力モードを楽に指定できる様にマクロを定義しています。TCCR1A レジスタの COMaA1/COM1A0 - COM1B1/COM1B0 ビットに対応するビットを _BV() マクロで設定しています。本マクロは後述の timer1_set_coma_mode()/timer1_set_comb_mode() マクロ実行時に指定します。

    • 27 〜 32 行目

      波形生成種別を楽に指定できる様にマクロを定義しています。TCCR1A レジスタの WGM11-10 ビットおよび TCCR1B レジスタの WGM13-12 ビットに対応するビットを _BV() マクロで設定しています。 本マクロは後述の timer1_set_wave_mode() マクロ実行時に指定します。

    • 34 〜 72 行目

      記述が楽になる様に、あるいは分りやすくなる様にいくつかのマクロを定義しています。

      • timer1_ov_enable()/timer1_ov_disable() マクロは、TIMSK レジスタの TOIE1 ビットを操作することでオーバーフロー割り込みの有効化/無効化を行います。

      • timer1_compa_enable()/timer1_compa_disable() マクロは、TIMSK レジスタの OCIE1A ビットを操作することで比較A一致割り込みの有効化/無効化を行います。

      • timer1_compb_enable()/timer1_compb_disable() マクロは、TIMSK レジスタの OCIE1B ビットを操作することで比較B一致割り込みの有効化/無効化を行います。

      • timer1_ic_enable()/timer1_ic_disable() マクロは、TIMSK レジスタの TICIE1 ビットを操作することで捕獲割り込みの有効化/無効化を行います。

      • timer1_clear_coma_mode() マクロは、TCCR1A レジスタの COM1A1/COM1A0 ビットをクリアします。

      • timer1_clear_comb_mode() マクロは、TCCR1A レジスタの COM1B1/COM1B0 ビットをクリアします。

      • timer1_stop() マクロは、TCCR1B レジスタの CS12-10 ビットをクリア(クロック無し) することでタイマ/カウンタ1 を停止します。

      • timer1_set_coma_mode() マクロは、timer1_clear_coma_mode() で TCCR1A レジスタの COM1A1/COM1A0 ビットをクリアした後に、指定されたクロック設定を COM1A1/COM1A0 ビットに設定します。

      • timer1_set_comb_mode() マクロは、timer1_clear_comb_mode() で TCCR1A レジスタの COM1B1/COM1B0 ビットをクリアした後に、指定されたクロック設定を COM1B1/COM1B0 ビットに設定します。

      • timer1_clear_wave_mode() マクロは、TCCR1A レジスタの WGM11-10 ビットおよび TCCR1B レジスタの WGM13-12 ビットをクリアします。

      • timer1_set_wave_mode() マクロは、timer1_clear_wave_mode() で TCCR1A レジスタの WGM11-10 ビットおよび TCCR1B レジスタの WGM13-12 ビットをクリアした後に、指定された波形生成種別を WGM13-10 ビットに設定します。

      • timer1_start() マクロは、timer1_stop() でタイマ/カウンタ1 を停止した後に、 指定されたクロック設定を TCCR1B レジスタの CS12-10 ビットに設定することでタイマ/カウンタ1 を開始します。

    • 74 〜 123 行目

      こちらは型チェックを有効にしたかったので、マクロではなく inline 関数としました。

      timer1_set_count() 関数は、指定された 16 ビット値を TCNT1 に書き込みます。 TCNT1 の初期値を設定したり、割り込み等のタイミングでカウンタ値を変えたい場合に使います。

      timer1_set_ocr1a()/timer1_set_ocr1b()/timer1_set_icr1() は、指定された 16 ビット値をそれぞれ OCR1A/OCR1B/ICR1 に書き込みます。これらの値はそれぞれ比較A一致/比較B一致/捕獲に使用されます。

  • timer1.c
        1    #include <avr/interrupt.h>
        2    #include <avr/io.h>
        3    #include <inttypes.h>
        4    
        5    #include "timer1.h"
        6    
        7    
        8    static void (*timer1_ov_interrupt_handler)(void);
        9    static void (*timer1_compa_interrupt_handler)(void);
       10    static void (*timer1_compb_interrupt_handler)(void);
       11    static void (*timer1_ic_interrupt_handler)(void);
       12    
       13    
       14    /*
       15     * オーバーフロー割り込みハンドラ
       16     */
       17    ISR(TIMER1_OVF_vect)
       18    {
       19            timer1_ov_interrupt_handler();
       20    }
       21    
       22    
       23    /*
       24     * オーバーフロー時に割り込みハンドラ内で実行する
       25     * ユーザ関数を設定する。
       26     */
       27    void 
       28    timer1_ov_set_interrupt(void (*func)(void))
       29    {
       30            timer1_ov_interrupt_handler = func;
       31    }
       32    
       33    
       34    /*
       35     * 比較A一致割り込みハンドラ
       36     */
       37    ISR(TIMER1_COMPA_vect)
       38    {
       39            timer1_compa_interrupt_handler();
       40    }
       41    
       42    
       43    /*
       44     * 比較A一致時に割り込みハンドラ内で実行するユーザ関数を設定する。
       45     */
       46    void
       47    timer1_compa_set_interrupt(void (*func)(void))
       48    {
       49            timer1_compa_interrupt_handler = func;
       50    }
       51    
       52    
       53    /*
       54     * 比較B一致割り込みハンドラ
       55     */
       56    ISR(TIMER1_COMPB_vect)
       57    {
       58            timer1_compb_interrupt_handler();
       59    }
       60    
       61    
       62    /*
       63     * 比較B一致時に割り込みハンドラ内で実行するユーザ関数を設定する。
       64     */
       65    void
       66    timer1_compb_set_interrupt(void (*func)(void))
       67    {
       68            timer1_compb_interrupt_handler = func;
       69    }
       70    
       71    
       72    ISR(TIMER1_CAPT_vect)
       73    {
       74            timer1_ic_interrupt_handler();
       75    }
       76    
       77    
       78    /*
       79     * 捕獲割り込みハンドラ内で実行するユーザ関数を設定する。
       80     */
       81    void
       82    timer1_ic_set_interrupt(void (*func)(void))
       83    {
       84            timer1_ic_interrupt_handler = func;
       85    }
       86    
       87    /* End of timer1.c */
    
    
    • 14 〜 20 行目

      オーバーフロー割り込みを有効にした場合に使用する、割り込みハンドラを記述しています。 ATmega8535 のタイマ/カウンタ1 オーバーフロー割り込みを表すマクロは TIMER1_OVF_vect です。 実際には、後述する timer0_ov_set_interrupt() で登録されたユーザ関数を実行する様に実装しています。

    • 23 〜 31 行目 (timer1_ov_set_interrupt())

      前述のオーバーフロー割り込みハンドラ内で実際に実行する、ユーザ関数を登録します。

    • 34 〜 40 行目

      比較A一致割り込みを有効にした場合に使用する、割り込みハンドラを記述しています。 ATmega8535 のタイマ/カウンタ1 比較A一致割り込みを表すマクロは TIMER1_COMPA_vect です。 実際には、後述する timer1_compa_set_interrupt() で登録されたユーザ関数を実行する様に実装しています。

    • 43 〜 50 行目 (timer1_compa_set_interrupt())

      前述の比較A一致割り込みハンドラ内で実際に実行する、ユーザ関数を登録します。

    • 53 〜 59 行目

      比較B一致割り込みを有効にした場合に使用する、割り込みハンドラを記述しています。 ATmega8535 のタイマ/カウンタ1 比較一致割り込みを表すマクロは TIMER1_COMPB_vect です。 実際には、後述する timer1_compb_set_interrupt() で登録されたユーザ関数を実行する様に実装しています。

    • 62 〜 69 行目 (timer1_compb_set_interrupt())

      前述の比較B一致割り込みハンドラ内で実際に実行する、ユーザ関数を登録します。

    • 72 〜 75 行目

      捕獲割り込みを有効にした場合に使用する、割り込みハンドラを記述しています。 ATmega8535 のタイマ/カウンタ1 捕獲割り込みを表すマクロは TIMER1_CAPT_vect です。 実際には、後述する timer1_ic_set_interrupt() で登録されたユーザ関数を実行する様に実装しています。

    • 78 〜 85 行目 (timer1_ic_set_interrupt())

      前述の捕獲割り込みハンドラ内で実際に実行する、ユーザ関数を登録します。

  • main-ov.c(オーバーフロー割り込み使用時の main)
        1    #include <avr/interrupt.h>
        2    #include <avr/io.h>
        3    #include <avr/sleep.h>
        4    
        5    #include "timer1.h"
        6    #include "util.h"
        7    
        8    
        9    static void timer1_ov_interrupt(void);
       10    
       11    
       12    int
       13    main(void)
       14    {
       15            /* PB0 ピンのみ出力設定 */
       16            DDRB |= _BV(DDB0);
       17            pullup();
       18    
       19            timer1_ov_enable();
       20            timer1_ov_set_interrupt(timer1_ov_interrupt);
       21            timer1_set_count(0);
       22    
       23            sei();
       24    
       25            /* (8MHz/1)/65536 = 約122Hz */
       26            timer1_start(TIMER1_CK);
       27        
       28            while (1){
       29                    sleep_mode();
       30            }
       31    
       32            return 0; /* 警告を避けるため */
       33    }
       34    
       35    
       36    static void 
       37    timer1_ov_interrupt(void)
       38    {
       39            static int count = 0;
       40    
       41            /*
       42             * LED の状態変更周波数を約 2Hz (500ms) とする。
       43             * 割り込み周期が約 122Hz なので 61回毎に状態を変える。
       44             *
       45             * ON-----OFF-----ON-----...
       46             *   500ms   500ms  
       47             */
       48            if (++ count != 61) {
       49                    return;
       50            }
       51    
       52            count = 0;
       53            PORTB ^= _BV(PB0);
       54    }
       55    
       56    /* End of main-ov.c */
    
    

    本ファイルは、オーバーフロー割り込みを使う場合の main() を記述しています。

    • 12 〜 33 行目 (main())

      • pullup() 前に PORTB0 のみ出力方向に設定
      • pullup() (pullup.h、PORTB0 以外の全入力ポートの内部プルアップを有効化)
      • timer1_ov_enable() (timer1.h、オーバーフロー割り込み有効化)
      • timer1_ov_set_interrupt() (timer1.h、オーバーフロー割り込み時に実行するユーザ関数の登録)
      • timer1_set_count() (timer1.h、TCNT1 の初期値を設定)

      を行った後、sei() (avr/interrupt.h) を実行してシステムの割り込みを有効化しています。

      その後に timer1_start() を実行してタイマ/カウンタ1 の動作を開始します。 timer1_start() に TIMER1_CK を指定しているため、オーバーフロー割り込みの周期は約 122Hz ((8MHz/1)/65536)となります。

      オーバーフロー割り込みタイミング

      以後 sleep_mode() にてアイドル動作へ移行し、LED の点滅処理はオーバーフロー割り込みハンドラに任せます。

    • 36 〜 54 行目 (timer1_ov_interrupt())

      オーバーフロー割り込み時に実行されるユーザ関数です。

      static 変数である count で割り込み回数を数え、61 回に一度 PORTB0 の値を反転します。 割り込み周期が約 122Hz であるため、反転周期は約 122/61 = 2 Hz となります。

  • main-comp.c(比較一致割り込み使用時の main)
        1    #include <avr/interrupt.h>
        2    #include <avr/io.h>
        3    #include <avr/sleep.h>
        4    
        5    #include "timer1.h"
        6    #include "util.h"
        7    
        8    
        9    static void timer1_comp_interrupt(void);
       10    
       11    
       12    int
       13    main(void)
       14    {
       15            /* PB0 ピンのみ出力設定 */
       16            DDRB |= _BV(DDB0);
       17            pullup();
       18    
       19            timer1_compa_enable();
       20            timer1_compa_set_interrupt(timer1_comp_interrupt);
       21            timer1_set_wave_mode(WGM1_CTC_OCR1A);
       22            timer1_set_count(0);
       23            timer1_set_ocr1a(127);
       24    
       25            sei();
       26    
       27            /* (8MHz/256)/128 = 約244Hz */
       28            timer1_start(TIMER1_CK_256);
       29        
       30            while (1){
       31                    sleep_mode();
       32            }
       33    
       34            return 0; /* 警告を避けるため */
       35    }
       36    
       37    
       38    static void 
       39    timer1_comp_interrupt(void)
       40    {
       41            static int count = 0;
       42    
       43            /*
       44             * LED の状態変更周波数を約 2Hz (500ms) とする。
       45             * 割り込み周期が約 244Hz なので 122回毎に状態を変える。
       46             *
       47             * ON-----OFF-----ON-----...
       48             *   500ms   500ms  
       49             */
       50            if (++ count != 122) {
       51                    return;
       52            }
       53    
       54            count = 0;
       55            PORTB ^= _BV(PB0);
       56    }
       57    
       58    /* End of main-comp.c */
    
    

    本ファイルは、比較一致割り込みを使う場合の main() を記述しています。

    • 12 〜 35 行目 (main())

      • pullup() 前に PORTB0 のみ出力方向に設定
      • pullup() (pullup.h、PORTB0 以外の全入力ポートの内部プルアップを有効化)
      • timer1_compa_enable() (timer1.h、比較A一致割り込み有効化)
      • timer1_compa_set_interrupt() (timer1.h、比較A一致割り込み時に実行するユーザ関数の登録)
      • timer1_set_wave_mode() (timer1.h、波形生成種別を設定)
      • timer1_set_count() (timer1.h、TCNT1 の初期値を設定)
      • timer1_set_ocr1a() (timer1.h、OCR1A の値を設定)

      を行った後、sei() (avr/interrupt.h) を実行してシステムの割り込みを有効化しています。

      この初期化フェーズで、timer1_set_wave_mode(WGM1_CTC_OCR1A) によって波形生成種別を "比較一致タイマ/カウンタクリア(CTC)(カウンタ最大値は OCR1A)"に設定しています。 これにより TCNT1 と OCR1A が一致した時点で TCNT1 をクリアし、0 からカウントを再開する動作を選択しています。

      その後に timer1_start() を実行してタイマ/カウンタ1 の動作を開始します。 timer1_start() に TIMER1_CK_256 を指定しており、かつ OCR1A の値によりカウンタ最大値は 127 となるため、比較一致割り込みの周期は約 244Hz ((8MHz/256)/128)となります。

      比較A一致割り込みタイミング

      以後 sleep_mode() にてアイドル動作へ移行し、LED の点滅処理は比較A一致割り込みハンドラに任せます。

    • 38 〜 56 行目 (timer1_comp_interrupt())

      比較A一致割り込み時に実行されるユーザ関数です。

      static 変数である count で割り込み回数を数え、122 回に一度 PORTB0 の値を反転します。 割り込み周期が約 244Hz であるため、反転周期は約 244/122 = 2 Hz となります。

以上で解説は終わりです。次回からは、タイマ/カウンタの機能を使ってサーボモータを動かしてみます。