それでは、今度はH8/3664に搭載されているタイマVを使って、ダイナミック点灯させてみましょう。
タイマVには、タイマカウンタが設定した値になったときにイベントを発生させる「コンペアマッチ機能」があります。今回はこの機能を使って、1m秒置きに割り込みを発生させ、それにより2つの7セグメントLEDをダイナミック点灯させます。
1m秒周期のイベント発生に必要なハードウェア構成を図2に示します。
まず16MHzのシステムクロックΦを、「プリスケーラ(分周器)」によって周波数を下げます。タイマVでは、Φ/4、Φ/8、Φ/16、Φ/32、Φ/64、Φ/128から選択することが可能です。
8ビットのタイマカウンタV(TCNTV)は、分周されたクロックによってカウントアップされます。
タイマVのコンペアマッチ機能が選択されていると、比較回路によってTCNTVとタイムコンスタントレジスタA(TCORA)の値が比較されます。ここで、TCNTVとTCORAの値が一致した次のクロック入力で、TCNTVを0クリアし、コンペアマッチフラグA(CMFA)を「1」にします。これを割り込み要因とすることによって、周期的に割り込みを発生させることができるのです。
それでは、16MHzから1m秒周期の割り込みを発生するには、どのようにタイマVを使うのでしょうか。次の2通りの設定が考えられます。
[その1]
[その2]
以上の解説を基に、C言語プログラムを考えます。
タイマVの制御レジスタには、「タイマコントロールレジスタV0(TCRV0)(図3)」「タイマコントロールレジスタV1(TCRV1)(図4)」「タイマコントロール/ステータスレジスタV(TCSRV)(図5)」があります。
[その1]の設定で1秒間隔の周期イベントを発生させるために、最初にタイマコンスタントレジスタA(TCORA)に「124」を代入します。
TCORA = 124;
タイマVのパルス出力機能は使わず、コンペアマッチAによるタイマカウンタのクリア、コンペアマッチAによる割り込み許可、タイマクロックをΦ/128にするのに、
TCRV1 = 0xe3;
TCRV0 = 0x4b;
とします。
タイマVは、TCRV0の下位3ビットが「0」以外になると、TCNTVにクロック投入されるようになっています。そのため、TCRV0を最後に設定しタイマを起動させます。
タイマV割り込み処理ルーチンは、int_timv関数です。
ここでは、コンペアマッチAイベントでダイナミック点灯を行います。
タイマVの割り込みは、「コンペアマッチA」「コンペアマッチB」「オーバーフロー」の3つの要因で引き起こされます。そのため、割り込み処理ルーチンでは、
if (TCSRV & CMFA) {
/* コンペアマッチA割り込み処理 */
}
else if (TCSRV & CMFB) {
/* コンペアマッチB割り込み処理 */
}
else if (TCSRV & OVF) {
/* オーバーフロー割り込み処理 */
}
のように、割り込み要因に対応した選択処理を行います。
プログラムは次のようになります(ソースコード2)。
/* 1秒間隔でカウント表示する。
*
*/
#define PCR5 (*((volatile unsigned char *)0xffe8))
#define PDR5 (*((volatile unsigned char *)0xffd8))
#define PCR8 (*((volatile unsigned char *)0xffeb))
#define PDR8 (*((volatile unsigned char *)0xffdb))
#define TMA (*(volatile unsigned char *)0xffa6)
#define IRR1 (*(volatile unsigned char *)0xfff6)
#define IENR1 (*(volatile unsigned char *)0xfff4)
#define TCRV0 (*(volatile unsigned char *)0xffa0)
#define TCSRV (*(volatile unsigned char *)0xffa1)
#define TCORA (*(volatile unsigned char *)0xffa2)
#define TCORB (*(volatile unsigned char *)0xffa3)
#define TCRV1 (*(volatile unsigned char *)0xffa5)
#define IRRTA 0x40
#define IENTA 0x40
#define CMFA 0x40
#define LED1 0x01
#define LED2 0x02
void int_tima(void) __attribute__((interrupt_handler));
void int_timv(void) __attribute__((interrupt_handler));
int count1, count10;
int main(void)
{
asm("orc.b #0xc0,ccr"); /* 割り込み禁止 */
/* タイマAの初期化 */
TMA = 0x18;
IRR1 &= ~IRRTA;
IENR1 |= IENTA;
/* タイマVの初期化 */
TCSRV = 0;
TCORA = 124;
TCRV1 = 0xe3;
TCRV0 = 0x4b;
/* ポートの初期化 */
PCR5 = 0x03;
PCR8 = 0xff;
asm("andc.b #0x3f,ccr"); /* 割り込み許可 */
count1 = 0;
count10 = 0;
for (;;) ;
return 0;
}
void int_tima(void)
{
IRR1 &= ~IRRTA;
if (count1 < 9)
count1++;
else {
count1 = 0;
if (count10 < 9)
count10++;
else
count10 = 0;
}
}
void int_timv(void)
{
static unsigned char LED[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
static int tagle = 0;
if (TCSRV & CMFA) {
TCSRV &= ~CMFA;
if (tagle) {
PDR5 = ~LED2;
PDR8 = LED[count1];
tagle = 0;
}
else {
PDR5 = ~LED1;
PDR8 = LED[count10];
tagle = 1;
}
}
else
TCSRV = 0;
}
タイマVを使ったら、ダイナミック点灯がループじゃなくなった。
タイマで周期的に処理するのは、制御プログラミングの基本の形よ。
あと、割り込み処理ルーチンでは下手にループさせないこと! これ重要よ。
えっ、何で?
だって、割り込みで長い処理を行うとCPUを占有しちゃうでしょ。
割り込み処理は、さっさと済ませること。
ふむふむ。『ちょっとだけよー』ってことか!
よし! これを『割り込みチラリズムの法則』と命名しよう。
……。
じゃ、次のワタシのプログラムを見て!
無視か……。
Copyright © ITmedia, Inc. All Rights Reserved.
組み込み開発の記事ランキング
コーナーリンク