C言語

インターバル・タイマを使ってLEDを点滅させる

前回、タイマ関連のレジスタの説明を行いました。今回は、タイマ・アレイ・ユニット機能の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が点灯と消灯を繰り返していることがわかるかと思います。

-C言語