前回、タイマ関連のレジスタの説明を行いました。今回は、タイマ・アレイ・ユニット機能の1つであるインターバル・タイマの設定を行い、定期的(1秒毎)にタイマ割り込みを発生させ、LEDを点滅させるプログラムを作成していこうと思います。
インターバル・タイマの設定
「IOポートの設定」と「スイッチのON/OFFによりLEDを点灯・消灯させる」で作成した「RL78G14_init.c」ファイルとプロジェクトファイルを使用します。
そして、 「RL78G14_init.c」ファイルに、タイマの初期化処理の関数を用意します。関数名は、戻り値も引数もない「static void RL78G14_init_Timer(void)」です。
この関数に、「タイマ・アレイ・ユニット機能で使用するレジスタの説明」で解説したタイマのレジスタを設定します。
「RL78G14_init.c」ファイルに、「static void RL78G14_init_IO_Port( void );」のプロトタイプ宣言している下に「static void RL78G14_init_Timer(void);」のプロトタイプ宣言を追加します。
#include "iodefine.h"
static void RL78G14_init_IO_Port( void );
static void RL78G14_init_Timer( void ); /* ←ここに追加 */
次に、同じ「RL78G14_init.c」ファイルに、 タイマの各レジスタの設定値の定数定義を追加します。
void hdwinit( void )関数の上あたりに記述します。
/***************/
/* タイマ初期値 */
/***************/
#define RL78G14_INIT_TAU0EN (1U)
#define RL78G14_INIT_TMR00 (0x0000U)
#define RL78G14_INIT_TPS0 (0x000AU) /* CK00=31.25kHz */
#define RL78G14_INIT_TDR00 (0x7A12U) /* 31250cnt(1秒) */
#define RL78G14_INIT_TIS0 (0x00U)
#define RL78G14_INIT_TOE0 (0x0000U)
#define RL78G14_INIT_TO0 (0x0000U)
#define RL78G14_INIT_TOL0 (0x0000U)
#define RL78G14_INIT_TOM0 (0x0000U)
#define RL78G14_INIT_ISC (0x00U)
#define RL78G14_INIT_NFEN1 (0x00U)
void hdwinit( void ) /* ←既存コード */
{
PIOR0 = RL78G14_INIT_PIOR0;
PIOR1 = RL78G14_INIT_PIOR1;
RL78G14_init_IO_Port();
RL78G14_init_Timer(); /* ←今回追加コード */
}
static void RL78G14_init_IO_Port( void ) /* ←既存コード */
{
省略
}
static void RL78G14_init_Timer( void ) /* ←今回追加コード */
{
TAU0EN = RL78G14_INIT_TAU0EN ;
TMR00 = RL78G14_INIT_TMR00;
TPS0 = RL78G14_INIT_TPS0;
TDR00 = RL78G14_INIT_TDR00;
TIS0 = RL78G14_INIT_TIS0;
TOE0 = RL78G14_INIT_TOE0;
TO0 = RL78G14_INIT_TO0;
TOL0 = RL78G14_INIT_TOL0;
TOM0 = RL78G14_INIT_TOM0;
ISC = RL78G14_INIT_ISC;
NFEN1 = RL78G14_INIT_NFEN;
}
TAU0ENは、PER0レジスタのビット0に該当するレジスタです。タイマ・アレイ・ユニット0の入力クロックを供給する設定にします。これで、タイマ・アレイ・ユニット0で使用するレジスタへのリード/ライトが可能になります。PER0 = 0x01Uとしても同じです。ただし、PER0レジスタは、タイマ・アレイ・ユニット以外にも、A/Dコンバータや、シリアル通信などの入力クロックを供給する設定もあるため、タイマ・アレイ・ユニット0機能のみに限定するため、TAU0ENレジスタに設定するようにしました。
最初に設定していますが、それ以外では特に順番などは気にする必要はないかと思います。
この後、各タイマ関連のレジスタの設定値について説明します。
タイマ・モード・レジスタ00(TMR00)
今回使用するタイマは、タイマ・アレイ・ユニット0のチャネル0を使用します。
このため、ユニット0のチャネル0に該当するタイマ・モード・レジスタ00を設定します。
チャネル0の動作クロックの選択は、CK00を使用することにします。このため、TMR00のビット14とビット15のCKS000とCKS001は、それぞれ 0 を設定します。
チャネル0のカウント・クロックの選択は、CK00の動作クロックを使用するため、TMR00のビット12のCCS00は、 0 を設定します。
マスタ/スレーブの選択、16ビット/8ビットタイマを選択は、チャネル0は該当しないため、0 固定です。
スタートトリガとキャプチャトリガの設定は、インターバルタイマのため、ソフトウェア・トリガ・スタートのみ有効(他のトリガ要因を非選択)にするため、TMR00のビット8~10のSTS000~STS002は、 0 を設定します。
TIxx端子の有効エッジを選択は、インターバルタイマで、TIxx端子を使用しないため、TMR00のビット6、7のCIS000、CIS001は、 0 を設定します。
動作モードの設定は、インターバル・タイマ・モードを選択するため、TMR00のビット1~3のMD001~MD003は、 0 を設定します。
カウント・スタートと割り込みの設定は、スタート・トリガに割り込みを発生させないため、TMR00のビット0のMD000は、 0 を設定します。
このため、TMR00の設定値は、すべて 0 である、0x0000を設定します。
タイマ・クロック選択レジスタ0(TPS0)
使用するタイマは1つで、選択するクロックは、TMR00にて、CK00を選択しました。
このため、TPS0のCK00に該当するビット0~3のPRS000~PRS003のみ設定します。
今回は、1秒毎のインターバル・タイマとするため、1秒までカウントできるクロックを選択する必要があります。
動作クロックは、32MHzのため、1秒に32000000クロックで、1カウント=31.25ナノ秒です。
タイマは、16ビットタイマのため、カウントの最大値は、65535カウントまでしかできません。このため、最大でも約2ミリ秒しかカウントできません。
そこでクロックを分周して1秒までカウントできるクロックに設定します。
62.5kHz以下であれば、1秒までカウントできるのですが、余裕をもって31.25kHzまで分周する設定にしました。
このため、TPS0の設定値は、0x000A を設定になります。
タイマ・データ・レジスタ00(TDR00)
タイマのカウント値を設定します。
タイマに使用するクロックが31.25kHz(1秒に31250クロック)なので、1秒のカウント値は、31250に設定します。16進数では、0x7A12です。
タイマ入力選択レジスタ0(TIS0)
ユニット0のチャネル0, 1のタイマ入力を選択するレジスタではありますが、タイマ入力端子の入力信号でも、ELCからのイベント入力信号でもないため、特に設定は不要です。
このため、初期値の 0x00 を設定します。
タイマ出力許可レジスタ0(TOE0)
各チャネルのタイマ出力のレジスタです。
今回は、タイマの出力は行わないため、タイマの出力は禁止( 0 )のままで大丈夫です。
このため、初期値の 0x0000 を設定します。
タイマ出力レジスタ0 (TO0)
タイマの出力値を書き換えれるレジスタですが、出力はさせないため、 0 を出力しておけば大丈夫です。
このため、 0x0000 を設定します。
タイマ出力レベル・レジスタ0(TOL0)
タイマ出力する値の反転設定を行うレジスタですが、タイマの出力は行わないため、 初期値の 0 のままで大丈夫です。
タイマ出力モード・レジスタ0(TOM0)
各チャネルのタイマ出力モードを設定するレジスタが、タイマは1つの単独のため、初期値の 0 のままで大丈夫です。
入力切り替え制御レジスタ(ISC)
今回使用するチャネルは0のため、特に初期値の 0 のままで大丈夫です。
ノイズ・フィルタ許可レジスタ1(NFEN1)
今回は、ノイズ・フィルタを使用することはないため、ノイズ・フィルタOFFに設定しておきます。
このため、0x00 を設定します。
タイマの初期化については以上です。
1秒毎にLEDを点灯/消灯させるプログラムを作成
次は、実際にタイマを使用して、定期的(1秒毎)にタイマ割り込みを発生させ、LEDを点滅させるプログラムを作成していこうと思います。
まだ、タイマを開始していないため、タイマを開始させるところからプログラムを記述していきます。それから、割り込み機能を使用しないと、タイマを開始させるだけでは、指定した時間が経過しても何も起こらないので、少し割り込み機能について触れていきます。
割り込みは、割り込み要因というものがあり、割り込み要因に対して、アドレスが決められています。このアドレスをベクタ・テーブル・アドレスといいます。
この割り込み要因の一つに、ユニット0のチャネル0のカウント完了時があります。これは、アドレス0x002C(INTTM00)に割り当てられており、割り込みが発生すると、このアドレスにジャンプするようになっています。
そして、この アドレス0x002C(INTTM00) に関数名を登録することにより、割り込みが発生したときに、登録している関数を呼び出すような仕組みになっています。
前に、「スイッチのON/OFFによりLEDを点灯・消灯させる」のところで作成したmain関数は削除します。
今回用にまた、新たにmain関数を作成していきたいと思います。
最初に、タイマの指定した時間経過したときに、処理させるために、割り込み時に呼ばれる関数名を決めます。決めた関数名にベクタ・テーブル・アドレスを割り当てます。
次に、main関数では、 アドレス0x002C(INTTM00)の割り込みを許可にし、タイマを開始します。それ以降は、処理はないため、無限ループしておきます。
次は、TimerCtrl関数では、タイマの指定した時間経過したときの処理として、LED0が0 の場合は、 1 に、 1の場合は、 0になるようにします。これにより、1秒毎にLED0を点灯と点滅を繰り返すことになります。
main.cファイルのプログラムを次に示します。
#include "iodefine.h"
#pragma interrupt TimerCtrl(vect=INTTM00)
void main(void);
void main(void)
{
TMMK00 = 0; /* INTTM00の割り込みを許可にする */
TS0 = 0x0001; /* ユニット0のチャネル0のタイマを開始する */
__EI(); /* RL78マイコンは割り込み禁止状態で開始されるので、ここで割り込みを許可にします */
while( 1 )
{
/* 処理が終わってしまうため、無限ループにて割り込みを待っている状態にする */
}
}
static void TimerCtrl(void)
{
if( P1_bit.no7 == 1 ) /* LED0が消灯している場合 */
{
P1_bit.no7 = 0; /* LED0を点灯する */
}
else /* LED0が点灯している場合 */
{
P1_bit.no7 = 1; /* LED0を消灯する */
}
}
1行目では、レジスタの定数定義を使うため、iodefine.hをインクルードしています。
3行目では、#pragma interruptと記述することにより、対象の関数定義をハードウェア割り込みハンドラとして定義できます。
#pragma interruptの後に任意の関数名を指定します。今回は、TimerCtrl関数としました。その後に、(vect=ベクタ・テーブル・アドレス)を記述することにより、関数と割り込み要因のアドレスが紐づきます。これにより、割り込みが発生したときに、TimerCtrl関数が呼び出されることになります。
main関数では、ユニット0のチャネル0のカウント完了時の割り込み要因が発生したときに、割り込みされるように、この割り込みを許可にする必要があります。 9行目では、この処理を行っています。
10行目で、ユニット0のチャネル0のタイマを開始します。
11行目では、マイコンはまだ割り込み禁止状態になっているため、割り込み要因の割り込みを許可にしただけでは、割り込みができませんので、__EI()を実行することにより割り込みを許可します。
main関数が終わってしまうとプログラムが終了してしまうため、無限ループを行っています。処理は、割り込み時のTimerCtrl関数で行うのみのため、main関数では特に処理は行いません。
TimerCtrl関数では、LED0が消灯している場合は、点灯し、点灯している場合は、消灯する処理を記述しています。
インターバル・タイマを使ってLEDを点滅させるプログラムについては、以上となります。
実際に動作を確認すると、1秒毎にLED0が点灯と消灯を繰り返していることがわかるかと思います。