314.タイマー1で16ビットタイマー


2002/10/23 【ソフトウエア編TOPに戻る】

PIC16F873などのミッドレンジのPICには、タイマー1(TMR1)と呼ばれる16ビットタイマーが装備されており、タイマー0の8ビットタイマーよりもちょっと長めのインターバルタイマーなどが組めます今回は、このタイマー1を使った16ビットタイマーのプログラム例を簡単にご紹介します。ちなみに、PIC16F84Aには、残念ながらこの機能はありません。


314−1.タイマー1の概要

タイマー1は16ビットのタイマーカウンタで、最大1:8のプリスケーラを併用すると524280までのクロックをカウントすることができます。クロックは外部入力と内部発生を選択することができ、タイマーカウンタTMR1のカウント値がFFFFHから0000Hに変化するタイミングで発生させることができます。TMR1TMR1HTMR1Lの2個の8ビットカウンタレジスタからなり、それぞれ上位と下位の8ビットずつとして働きます。

基本的にはアップカウンタなので、カウント開始からFFFFHを過ぎて割り込みが発生するまでのインターバル時間を調整するために、タイマーカウンタレジスタTMR1HTMR1Lに初期値を書き込む操作を行ないます。つまり、TMR1の初期値とプリスケーラ値の設定によって割り込み発生までに必要なカウント値が決まります。

タイマーカウンタレジスタTMR1SFR(スペシャルファンクションレジスタ)として読み書きが可能で、プリスケーラ値やクロックの外部/内部の選択、および外部クロック時の立上り/立下りタイミングの設定などの、TMR1の動作設定はT1CONレジスタ(TIMER1 CONTROLレジスタ)によって行ないます。302.PICの命令とレジスタ一覧のページも参照して下さい。

内部クロックを基準とする場合のインターバル時間は、以下のようにして求めることが出来ます。

内部クロック周期 = 1/システムクロック周波数 x 4

システムクロック(PICに与えている発振器のクロック周波数)が20MHzの場合は、1/20MHz x 4 = 0.2μSということになります。

TMR1のカウントアップ周期 = 内部クロック周期 x プリスケーラ設定値

実際のタイマーカウンタTMR1は、プリスケーラを経由した後のクロック周期でカウントアップされます。プリスケーラは1:1〜1:8の4段階から選択できますので、上記の通りシステムクロックが20MHzの場合、プリスケーラが1:1の時は0.2μS、1:8の時は1.6μSのカウントアップ周期となります。

つまり、システムクロックが20MHzの場合、TMR1を使ったタイマー動作では、1.6μS x65535カウント = 104.856mS が計測できる最長時間ということになります。タイマー0での最長時間が13.056mSでしたから、ちょっと長めの計測ができるということになります。

【先頭に戻る】


314−2.タイマー1を使ったプログラムその1 tmr1tes1.asm

それでは、実際にタイマー1を使ったインターバルタイマー動作のプログラム例をご紹介します。内容的には313.タイマー0を使うでご紹介したプログラムを、タイマー1に置き換えただけのものです。

このプログラムでは、タイマー1のプリスケーラを8、タイマーカウンタTMR1の初期値を00Hに設定してカウント動作をさせ、TMR1がFFFFHに達して0000Hに変化したタイミングで発生する割り込み処理内で、RBの8BITから2進バイナリカウントを出力させます。つまり、システムクロックが20MHzならば、RBポートに8BITのLEDを接続すると104.856mSの周期で2進カウント表示を行ないます。

プログラムはPIC16F873 用のみでtmr1tes1.asm(ダウンロード)です。

 

;**********************************************************************
;TMR1 TIMER TEST1                                                         RIKIYA   2001.11.10
;DEVICE : PIC16F873
;CLOCK : 20MHz
;TMR1の割り込みを使った、インターバルタイマー動作
;PORTBからカウントアップ出力を行なう
;内蔵のTMR1カウンタだけで最長105mSのインターバルを発生する。
;**********************************************************************
          list p=16F873
          #include <p16F873.inc>

          __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF

          CNT1        EQU 20H                     ;アドレス20Hを変数CNT1とする。
;**********************************************************************
          ORG         0                                ;リセット時の開始アドレスセット
          GOTO       MAIN                          ;メインルーチンMAINにジャンプ
          ORG         4                                ;割り込みアドレスセット
          GOTO       INTR                           ;割り込みルーチンINTRにジャンプ

MAIN   BSF         STATUS,RP0                ;メモリーバンクを1にセット
          MOVLW    080H                           ;Wレジスタに80Hをセット
          MOVWF    OPTION_REG                ;OPTION_REGに80Hをセット PULL UPなし
          BSF         PIE1,TMR1IE                 ;TMR1オーバーフロー割り込み許可
          CLRF       TRISB                          ;TRISBをクリア PORT-Bを出力にセット
          BCF         STATUS,RP0                ;メモリーバンクを0にセット

          MOVLW    30H                             ;Wレジスタに30Hをセット
          MOVWF    T1CON                        ;T1CONレジスタ プリスケーラ1:8 停止

          MOVLW    00H                             ;Wレジスタに00Hをセット
          MOVWF    TMR1L                         ;TMR1Lに下位8ビットデータをセット
          MOVLW    00H                             ;Wレジスタに00Hをセット
          MOVWF    TMR1H                        ;TMR1Hに上位8ビットデータをセット
          CLRF       CNT1                           ;CNT1変数を00Hにクリア

          BSF         INTCON,PEIE                ;周辺割り込みの許可
          BSF         INTCON,GIE                  ;全体割り込みの許可
          BSF         T1CON,TMR1ON            ;TMR1のTMR1ONビットをセット カウント開始

;***********************************************************************
;割り込みを待つループ
;***********************************************************************
LOOP
          NOP ;何もしない
          GOTO       LOOP                          ;ラベルLOOPにジャンプ

;***********************************************************************
;割り込み処理
;***********************************************************************
INTR

        MOVLW   00H                        ;Wレジスタに00Hをセット
        MOVWF   TMR1L                    ;TMR1Lに下位8ビットデータをセット
        MOVLW   00H                        ;Wレジスタに00Hをセット
        MOVWF   TMR1H                    ;TMR1Hに上位8ビットデータをセット

          BCF         PIR1,TMR1IF                ;オーバーフローフラグのクリア
          BSF         STATUS,RP0                ;メモリーバンクを1にセット
          BSF         PIE1,TMR1IE                 ;オーバーフロー割り込み許可
          BCF         STATUS,RP0                ;メモリーバンクを0にセット

          INCF        CNT1,F                        ;変数CNT1に+1する。
          MOVF      CNT1,W                        ;WレジスタにCNT1の値をセット
          MOVWF    PORTB                        ;PORTBへCNT1の値を出力

          RETFIE                                      ;割り込みを許可してリターン

          END

以下のプログラム説明に出てくる各種レジスタについては、302.PICの命令とレジスタ一覧のページを参照して下さい。

 

■ヘッダー部

下記はPICのデバイスを指定する部分と、デバイス固有のヘッダファイルを読み出す指定をしている部分です。

          list p=16F873
          #include <p16F873.inc>

下記はコンフィグレーションビットの設定を行なう部分です。

          __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF

下記の部分はデータメモリの20HというアドレスにCNT1という名前を付けています。実際には「CNT1という文字列は20Hという値を示す」という宣言をしているだけですが、意味合い的にはCNT1という変数を宣言して、20Hというアドレス空間を確保した、という感じになります。

          CNT1        EQU 20H                     ;アドレス20Hを変数CNT1とする。

■リセット、割り込みベクター部

ORGとは、指定したプログラムメモリアドレスにカレントアドレスを移動させる、といった意味の擬似命令です。つまり、「ORG  0」 とした後に 「GOTO  MAIN」 とすると、プログラムメモリの0番地にGOTO MAINという命令が書き込まれます。同様にして、アドレスの4番地に「GOTO INTR」という命令が書き込まれます。

          ORG         0                                ;リセット時の開始アドレスセット
          GOTO       MAIN                          ;メインルーチンMAINにジャンプ
          ORG         4                                ;割り込みアドレスセット
          GOTO       INTR                           ;割り込みルーチンINTRにジャンプ

リセット後に一番初めに実行されるのが0番地の命令になるため、リセット後はMAINというラベルにジャンプするようになります。同様に、割り込みが発生した場合には自動的に4番地にジャンプするため、INTRというラベルにジャンプするようになります。

 

■イニシャル部(ラベルMAIN)

MAINというラベルから実際のレジスタの初期化、つまりイニシャル処理を行ないます。実際に行なっていることはソースコードのコメント欄の通りですので、ここでは簡単な補足説明だけにしておきます。

MAIN   BSF         STATUS,RP0                ;メモリーバンクを1にセット
          MOVLW    080H                           ;Wレジスタに80Hをセット
          MOVWF    OPTION_REG                ;OPTION_REGに80Hをセット PULL UPなし

          BSF         PIE1,TMR1IE                 ;TMR1オーバーフロー割り込み許可
          CLRF       TRISB                          ;TRISBをクリア PORT-Bを出力にセット
          BCF         STATUS,RP0                ;メモリーバンクを0にセット

ここまでは、PORT-Bの初期設定とタイマー1の割り込み許可の設定までを行っています。PORT-Bの設定については311.PIOで入出力する(PIC16F873)のページを参照して下さい。タイマー1の割り込み設定については、PIE1レジスタで行っています。PIE1レジスタは以下のような内容になっています。

★PIE1(ペリフェラルインタラプトイネーブル)レジスタの機能

周辺機能の割り込みの許可/禁止設定を行います。

7 6 5 4 3 2 1 0
PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE

今回はこの中からTMR1IEビットを1にすることによって、タイマー1の割り込みを使用可能としています。

          MOVLW    30H                             ;Wレジスタに30Hをセット
          MOVWF    T1CON                        ;T1CONレジスタ プリスケーラ1:8 停止

ここでは、T1CONレジスタで、タイマー1のプリスケーラを1:8に設定しています。T1CONレジスタは以下のような内容になっています。

★T1CONレジスタの機能

では、タイマー1の動作設定を行います。

7 6 5 4 3 2 1 0
T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON

このうちプリスケーラを設定するのはT1CKPS10のビットで、以下のように使います。

T1CKPS1,0:プリスケーラ選択ビット

T1CKPS1,0

プリスケール値

1 1 1:8
1 0 1:4
0 1 1:2
0 0 1:1

それ以外の各ビットについては以下のような意味があります。

T1OSCEN:タイマ1オシレータイネーブルビット

    1 = オシレータを動作させる。

    0 = オシレータを停止させる。

T1SYNC:タイマ1外部クロック入力同期コントロールビット(TMR1CSが1の時に有効)

     1 = 外部クロック入力を同期させない。

     0 = 外部クロック入力を同期させる。

TMR1CS:タイマ1クロックソース選択ビット

     1 = RC0/T1OSO/T1CK1ピンからの外部クロックを有効にする。

     0 = 内部クロックを有効にする。

TMR1ON:タイマ1オン(スタート)ビット

     1 = タイマ1を動作させる。

     0 = タイマ1を停止させる。

今回はプリスケーラ1:8、内部クロックを選択、とりあえずタイマー1を停止状態にしておく、ということで以下の設定にします。

7 6 5 4 3 2 1 0
T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON
0 0 1 1 0 0 0 0

なので、T1CONには03Hという値をセットしています。


          MOVLW    00H                             ;Wレジスタに00Hをセット
          MOVWF    TMR1L                         ;TMR1Lに下位8ビットデータをセット
          MOVLW    00H                             ;Wレジスタに00Hをセット
          MOVWF    TMR1H                        ;TMR1Hに上位8ビットデータをセット
          CLRF       CNT1                           ;CNT1変数を00Hにクリア

ここではTMR1タイマーレジスタ0000Hという値を設定するために、下位8ビットTMR1Lと上位8ビットTMR1Hに対して、個別に00Hをセットしています。ついでに、PORT-Bにカウント出力をさせるための変数CNT1を00Hにクリアしています。


          BSF         INTCON,PEIE                ;周辺割り込みの許可
          BSF         INTCON,GIE                  ;全体割り込みの許可
          BSF         T1CON,TMR1ON            ;TMR1のTMR1ONビットをセット カウント開始

ここでは、使用可能にした割り込みを許可するための処理をした後、T1CONレジスタTMR1ONビットを1にして、実際にTMR1のタイマーカウント動作をスタートさせています。

■メインルーチン部

LOOP
          NOP ;何もしない
          GOTO       LOOP                 ;ラベルLOOPにジャンプ

イニシャル部の動作が終了すると、メインルーチン部に処理が移ります。で、上の処理がメインルーチンになります。そう。何もしないNOPという命令を永久に繰り返すだけのものです。RBポートにデータを出力させたりといった、このプログラムの目的である動作を行なうための命令は、ここにはありません。では、どうやって目的の動作を行なわせるのかというと、TMR1のオーバーフローによる割り込み処理が登場します。

 

■割り込み処理部

以下の部分が割り込み発生時に処理される部分です。割り込みが発生するとプログラムカウンタは04hになって04h番地の命令、つまり GOTO INTR を実行します。で、以下の部分が実行されることになります。

INTR

        MOVLW   00H                        ;Wレジスタに00Hをセット
        MOVWF   TMR1L                    ;TMR1Lに下位8ビットデータをセット
        MOVLW   00H                        ;Wレジスタに00Hをセット
        MOVWF   TMR1H                    ;TMR1Hに上位8ビットデータをセット

ここでは、TMR1タイマーレジスタの初期化を行っています。イニシャル部でも同じ初期化を行っていますし、そもそも割り込み処理が実行されるのはTMR1FFFFHから0000Hに変化したタイミングなので、この時点では必ずTMR1は0000Hのはずです。では、なぜここでこんな処理が必要になるのかというと、初期値を0000H以外に設定したい場合を想定しているからです。インターバル時間を104mS以下にしたい場合TMR1の初期値を0000Hよりも大きくしなければならないため、ここで割り込み発生ごとに毎回設定することになります。

          BCF         PIR1,TMR1IF                ;オーバーフローフラグのクリア
          BSF         STATUS,RP0                ;メモリーバンクを1にセット
          BSF         PIE1,TMR1IE                 ;オーバーフロー割り込み許可
          BCF         STATUS,RP0                ;メモリーバンクを0にセット

PIR1レジスタTMR1IFビットは、TMR1のオーバーフロー割り込みが発生すると1になりますが、ここではこのビットをクリアしています。また、TMR1のオーバーフロー割り込みが発生するとクリアされるPIE1レジスタTMR1IEビットを再び1にして、次の割り込みを受け付けられる状態にしています。


          INCF        CNT1,F                        ;変数CNT1に+1する。
          MOVF      CNT1,W                        ;WレジスタにCNT1の値をセット
          MOVWF    PORTB                        ;PORTBへCNT1の値を出力

          RETFIE                                      ;割り込みを許可してリターン

そして、ここでCNT1番地に書き込まれているデータに+1してRBポートに出力しています。この部分がプログラムの実行結果として目に見える部分になります。

RETFIE命令は、全ての割込みを許可(INTCONレジスタのGIEビットをセット)してから元の処理に戻る命令です。

【先頭に戻る】


314−3.実験風景

左の写真が実験風景です。右側の基板がPIC学習用ボードで、PIC16F873が実装されています。左側の基板が簡易型実験用I/Oボードで、PICのポートBに接続した8ビット分のLEDが点灯しています。

 

【先頭に戻る】


今回は、タイマー1のもっとも基本的な動作である16ビットカウンタとしての動作と、そのオーバーフロー割り込み処理を行ってみました。結局は前回ご紹介したタイマー0の延長線の動作でしたが、タイマー1にはキャプチャ/コンペアマッチといった、タイマー0にはない機能が付いていますので、より高度な処理が可能となっています。

次回は、タイマー1のコンペアマッチ動作などについてご紹介することにしましょう。

 

  【ソフトウエア編TOPに戻る】


【表紙に戻る】