タイマー1の使い方



【概要】

 タイマ1は、ミッドレンジシリーズの中でも高機能なPICに内蔵されている機能で、
タイマ0と同様の機能を持っていますが、大きな特徴はカウンタが16ビットカウンタと
なっているところです。
 また、タイマ1は基本的な使い方以外に、キャプチャ機能やコンパレータ機能と
組合わせることで、時間測定や、プログラムに影響されない一定のインターバルの
繰り返しなど、さらに高機能な使い方が出来ます。
本ページではタイマ1の基本的な使い方を説明していますが、さらに高機能な使い
方は、CCPのページで説明していますので参照して下さい。


【タイマ1の機能】

実際のタイマ1の内部構成は下図のようになっていて、動作の流れは次のように
なります。
 まず、入力として、外部入力、内部クロック、専用発振回路の3種類が使え、いず
れかを指定して使います。 内部クロックの入力の時はシステムクロックの1/4の
周波数となっています。専用発振回路はシステムクロックのLPモードと同じ構成と
なっており、200KHz以下のクリスタル発振回路用となっています。これは、時計用
としてタイマ1を使うときに便利なように、32KHzの発振回路が想定されているよう
です。外部入力の時は、T1CKIピンの入力パルスのカウントをすることになります。
 そして次に専用の3ビットのプリスケーラを通したあと、内部クロックとの同期回路
を通して、16ビットのTMR1レジスタでカウントします。
 TMR1レジスタは8ビットずつのTMR1HとTMR1Lの2つのレジスタとなっていて、
プログラムで読み書きが自由に出来ます。TMR1もカウントがオーバーフローした時
TMR1IFフラグがOnとなって割込みを発生します。
これらのタイマ1の動作の仕方を指定するのは、タイマ1専用の制御用レジスタで
ある「T1CONレジスタ」で行います。





【レジスタの使い方】

 タイマ1の内部の設定切替はT1CONレジスタに設定することで可能となります
が、このT1CONレジスタの詳細は下図のようになっています。




タイマ1の入力源としては、タイマ0と同じ内部クロックか、専用発振回路による
タイマモードと、外部入力によるカウンタモードの3種類があります。
その指定方法はT1CONレジスタの中で下表のようにして行います。

入力種別

T1OSCEN

^T1SYNC

TMR1CS

内部クロック

専用発振回路

外部入力(非同期)

外部入力(同期)


(1) 外部入力カウンタモード
  カウンタモードの時には、内部クロックに同期をとることが出来るようになって
  おり、この同期をとっておくと、TMR1の読み出し最中にカウンタがカウント
  アップ動作をすることを避けられるため正確な値を読み出すことが可能となり
  ます。
  普通は同期させるようにしますが、逆に、クロックより高い周波数の時には
  同期が正確には取れなくなりますから、そのような場合には同期をしないよう
  にすれば、外部入力信号がそのままカウンタの入力となります。

  タイマ1は16ビットカウンタであるため、カウントさせながらカウンタ値を読み
  込むのには、TMR1HとTMR1Lを分けて別々に読み込む動作が必要となります。
  こうすると問題が起きることがあります。つまり読み込み中にカウントアップ動作
  をしてしまうことが有りうるからです。
  これを避けるため次のような手順を踏んで読み込む必要があります。

   まず上位のTMR1Hを読み込みレジスタに保存します。
   次に下位のTMR1Lを読み込んで保存します。
   そしてもう一度上位を読み込んで前のと同じかどうかを確認します。
   同じなら正常で完了ですが、異なっていた時には、再度読み込みをしなお
   します。

(2) 内部クロックモード
  タイマ1はプリスケーラも合わせると全部で19ビットのカウンタとなりますから、
  内部クロックが20MHzの時でも、最長約105msecという長いインターバルタイマ
  を作ることが出来ます。

(3) 専用発振回路モード
  タイマ1についている専用発振回路は、システムクロック発振回路のLPモードと
  同じ回路になっていて、最高200kHzまでのクリスタル発振回路用となっています。
  これは、時計用の32kHzのクリスタル発振回路を想定したもので、実際の例として、
  32.768kHzのクリスタルを使った時の、タイマ1にセットする値とオーバーフロー
  割込み発生までの時間を一覧表にすると下表のようになり、扱いやすい値の
  インターバルが出来るようになっています。
  但し、この時のプリスケーラの値は1で、TMR1Lは0のままです。

TMR1の値

オーバーフローまでの時間

8000H

1sec

C000H

0.5sec

E000H

0.25sec

F000H

0.125sec


【C言語による使い方】

CCS Cコンパイラでタイマ1を使うためには、専用の組込み関数を使います。
この関数を使うことで、割込みも容易に扱うことが出来ます。
タイマ1用の組込み関数としては下表が用意されています

組込み関数書式

内   容

SETUP_TIMER_1(mode) タイマー1の初期設定を行う。
複数の設定はORで行う。

modeの値は下記を使用する。
 T1_DISABLED タイマ1を使用しない
 T1_INTERNAL 内部クロックモード指定
 T1_EXTERNAL 外部入力、非同期モード指定
 T1_EXTERNAL_SYNC 外部入力同期モード指定
 T1_CLK_OUT 内蔵発振回路を使う指定
 T1_DIV_BY_1 プリスケール値1
 T1_DIV_BY_2  〃     2
 T1_DIV?BY_4  〃     4
 T1_DIV_BY_8  〃     8

例 setup_timer_1(T1_DISABLED);
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_8)
GET_TIMER1( ) 現在のTMR1の内容を返す。
16ビットなのでlong変数で扱う必要がある。

例 while (get_timer1( ) != 0) 
SET_TIMER1(value) TMR1レジスタにvalueの値をセットする

例 if(get_timer1( )=1000)
set_timer1(0);


【プログラム例】

実際にタイマ1を使ったプログラム例を紹介します。
下記はタイマ1をPIC16F877を専用発振回路で動作させ、1秒毎に発光ダイオードを
点滅させるプログラムです。
mainの中で同時にプログラムタイマのdelay_ms関数を使って、やはり1秒周期で
別の発光ダイオードの点滅もしています。

この時の回路図は下図のようになっています。専用発振回路には、32.768kHzの時計
用の水晶振動子を使って発振回路を構成しています。
タイマで点滅させるのはLED1の発光ダイオードで、メインルーチンの中で、プログラム
タイマを使って点滅させているのが、LED2の発光ダイオードです。





≪プログラムリスト≫ 下記には漢字スペースを含んでいます。
 
//////////////////////////////////////////////
// Timer1 of 16F877 test program.
// Use 32.768kHz crystal and set 1sec period.
// Each interval interrupt,LED is controled.
//////////////////////////////////////////////
#include <16f877.h>
#use delay(CLOCK=10000000)     //10MHz

#int_timer1            //タイマ1割込み処理
intval() {
 int flag1;
 set_timer1(0x8000);       //1secに再セット
 if(flag1 == 0) {
   output_high(PIN_B7);     //LED off
   flag1 = 1;
 }
 else {
   output_low(PIN_B7);     //LED on
   flag1 = 0;
 }
}
main() {
 int flag;
 set_tris_b(0);         //all output
 output_high(PIN_B7);      //LED off

 setup_timer_1(T1_EXTERNAL_SYNC | T1_CLK_OUT | T1_DIV_BY_1);
 set_timer1(0x8000);      //initial set
 enable_interrupts(INT_TIMER1);
 enable_interrupts(GLOBAL);

 while(1) {
   if(flag == 0) {       //key input
    output_high(PIN_B6);   //LED2 on
    flag = 1;
   }
   else {
    output_low(PIN_B6);    //LED2 off
    flag = 0;
   }
   delay_ms(1000);
 }
}



  目次ページに戻る