トップページ > dsPIC入門 > タイマーについて
最初に作成したテストプログラムは、for文で時間稼ぎをしていて 残念な感じでした(汗)次はちゃんと時間を測って動作するような、実用的なものをタイマーを使ってで実現します。 まずは、いろいろ細かい設定は置いといて(またか)てっとり早くタイマーの使い方を覚えます。
dsPICの内部モジュール“タイマー”は、独立してカウンターの値をインクリメント(+1する)していきます。 その値が設定値に達すると、コンパイラ側で決められた名前を持つ関数(内容は自分で記述する)が呼び出されます。 その際、それまで行っていた処理は中断されます。これが「タイマー割り込み」。割り込み関数からreturnすると また元の処理に戻ります。
例の「LEDナイトライダー」のプログラムをタイマー割り込みを使ったものに書き換えてみます。
前のプログラムでは「メイン関数内でLEDをシフト→時間稼ぎ」という感じでした。
今回は、最初にメイン関数内で初期設定を済ませて、後は何もしません。
設定した時間が経過するとタイマー割り込みが発生するので、その関数内でLEDのシフトを行うようにします。
…すると、一定時間ごとにLEDがシフトしているように見えます。割り込み処理の中に、再度割り込みが発生
できるように記述することで、繰り返し割り込みが発生できるようにします。
実際のところ、あのプログラムではタイマーのありがたみを感じることは無いとおもいます。
ただ、今後赤外線通信や音声のサンプリングなんかを実装する際には非常に重宝するので、簡単な例で
使い方を確認しよう…ということです。
//********************************************************************
//LEDナイトライダー(タイマーで) @dsPIC30F4012
//********************************************************************
//********************************************************************
//ヘッダファイル
#include "p30f4012.h"
#include "timer.h"
//********************************************************************
//コンフィグ(変更なし)
_FOSC(XT_PLL8 & CSW_FSCM_OFF);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_ON & BORV_20 & PWRT_64 & MCLR_EN);
_FGS(CODE_PROT_OFF);
//********************************************************************
//グローバル変数
int flag = 0;
int cnt=0;
char a = 0x01;
//********************************************************************
//タイマー割り込み関数
void _ISR _T1Interrupt(void)
{
//タイマー割り込みフラグをOFFにしておく。(同時にカウンタもリセットされる)
IFS0bits.T1IF = 0;
//===================================================================
//PORTBで6回シフト
if(flag==0)
{
//PORTEは消しとく
PORTE=0;
//表示して、シフト
PORTB = a;
a = a << 1;
//シフト回数をカウント
cnt++;
//もしPORTBの左ハジまでいったら…
if(cnt==6)
{
cnt=0;
a=0x01;
//flagの値を変えて、次に呼ばれた時は別な処理を実行する
flag=1;
return;
}
return;
}
//===================================================================
//PORTEの0ビット点灯
if(flag==1)
{
PORTB=0;
PORTE = 0x01;
//flagの値を変えて、次の処理へ
flag=2;
return;
}
//===================================================================
//PORTEの1ビット点灯
if(flag==2)
{
PORTE=0x02;
//flagの処理を変えて、次の処理へ
flag=0;
return;
}
}
//********************************************************************
//メイン関数
int main(void)
{
//===================================================================
//入出力ポートの設定
TRISB = 0x00;
TRISE = 0x00;
PORTB = 0x00;
PORTE = 0x00;
//===================================================================
//タイマーの設定&タイマー割り込みを許可
OpenTimer1(T1_ON & T1_GATE_OFF & T1_PS_1_64 & T1_SYNC_EXT_OFF & T1_SOURCE_INT,10000);
ConfigIntTimer1(T1_INT_PRIOR_5 & T1_INT_ON);
//===================================================================
//今回は、本処理で何もしない
while(1)
{
}
}
//********************************************************************
…それでは、新しく追加された事項を見ていくことにします。ソースコードの上の行から順番にいきます。
…という感じで記述します。導入で使った30F4012には計5個のタイマーモジュールが載っています。 今回は“タイマー1”だけを使用していますが、基本的なタイマーとしての使い方であれば、他のタイマーも同様です。 注意点は、以下のとおりです。
割り込みが発生すると、dsPIC内で割り込みに関して使用されるレジスタの値が書き変わります。「割り込み制御レジスタ」と呼ばれる ものですが、このレジスタをプログラム中で自由に書き換えることで、割り込み動作を制御することができます。 今回のプログラムでは…
という構文で割り込みフラグをクリアする際にアクセスしています。
割り込みが発生すると、”IFS(Interrupt Flag Status)”レジスタが書きかえられます。
割り込みフラグが立つ…とか言うやつです。IFSレジスタは実際にはIFS0〜IFS2まで3つあり、各ビットが割り込みを発生する内蔵モジュールへ
割り当てられています。今回使用しているタイマー1のフラグは「IFS0」の中の1ビットです。T1IFビット(Timer 1 Interrupt Flag-bit)というそのまんま
の名前です。
この割り込み制御レジスタの値は、割り込み関数が終了した後でも値が保存され続けてしまいます。よって、割り込み処理内でクリアしてあげないと
割り込み関数を抜けた直後にまた割り込み関数が呼ばれて永久ループになってしまいます。
割り込み処理の頭にフラグクリア…というのは常套句のようです。
その場でテキトーに書いたので、洗練されていないのは目をつぶってください。まず、グローバル変数使うな…というのは自分でも気になっています。 割り込み関数内でstaticとかつけて宣言すればいいのでしょうけど。あと、PORTBが6bitしかないというのがなんともアレです。 PORTEの2ビットを巻き込んでいるので、どうしてもゴチャゴチャしますね。もはや、1Byteが1単位だ!っていうのは古いのでしょうか?組み込み系だし…。 dsPICでデータバス相手の処理ってのも、ヘンな感じするし…。ブツブツ…。
割り込み関数の書式はスッキリでしたが、初期設定は結構ゴチャゴチャします。機能が多くなった分だけしょうがないのかもしれませんが…。 とりあえず初期設定としては、タイマーそのものの動作モードの設定・タイマーの割り込みレベルの設定・タイマー割り込みの許可を考えます。
名前のとおり、タイマーを動作開始させる関数です。タイマ用ライブラリ内に含まれてます。
便利ですねー。もしタイマー2を使うなら、「OpenTimer2()」とかになります。
引数は2つあります。1つ目はconfig…コンフィグレーションについてのところでやったような、
マクロを&でつないで記述するアレが引数としてズラーっと並びます。今回関係あるパラメータのみ書き出すと、
タイマのON・OFF
2つ目の引数は、カウンタの上限値の設定です。つまり、カウンタがインクリメントされていってこの値に達すると 割り込みが発生する…というタイマー時間の設定のようなものです。今回は10000です。テキトーです。すいません。
もう一度、今回のプログラムの設定を見てみます。これはタイマーの割り込みに関する設定をする関数です。また引数がconfigになっています。またマクロを羅列します。煩雑ですいません。
MPLABでprojectへライブラリーファイルを追加しないと、コンパイルエラーとなります。使用するデバイスと同じ名前のライブラリファイル (拡張子は“.a”)を入れます。ディレクトリはC:/Program Files/Microchip/MPLAB C30/libとかです。今回は30F4012を使用しているので、 “libp30F4012-coff.a”を選択します。