――大規模で複雑なプログラムを作るとき、すべての処理を1つのファイルに記述するこはありません。プログラムを機能によって分類し、複数のモジュールからプログラムが構成されるように作成します。それではプログラムをモジュール化してみましょう。
晴子さんは、プログラムを「main.c」「h8tiny.h」「interrupu.c」の3つに分けました(晴子さんのプログラム「7seg2.lzh」)。それでは個々のプログラムを解説しましょう。
main.cには、main関数のみが記述されています。ここではH8マイコンの周辺機能を初期化し、さらにカウント変数をクリアして無限ループに入ります。仕事はすべて割り込みで行われるからです。
いままで紹介したプログラムでは、プログラムの先頭部分でレジスタの宣言などを行っていましたが、main.cでは、
#include “h8tiny.h”
と1行で済ませています。
#includeはソースを差し込む指定で、ここでh8tiny.hファイルの内容が差し込まれるのです。
#include “h8tiny.h”
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;
}
それでは、h8tiny.hを見てみましょう。
h8tiny.hは、次のようにレジスタの宣言などが含まれています。このようにレジスタ宣言をヘッダファイルで定義しておけば、後はインクルードするだけで共通に利用できます。
#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
interrupu.cには、割り込みベクタが書かれています。ここでもH8マイコンの周辺機能を使いますが、レジスタの定義はh8tiny.hをインクルードするだけです。
カウント変数count1とcount10の宣言で、
extern int count1, count10;
と、extern宣言していますが、これは外部の変数を使うという意味です。main.cにある変数count1とcount10を使うので、interrupu.cではextern宣言しているわけです。
#include "h8tiny.h"
void int_tima(void) __attribute__((interrupt_handler));
void int_timv(void) __attribute__((interrupt_handler));
extern int count1, count10;
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;
}
最後に、プログラムの実行方法を説明します。
まず、スタートアップ・ルーチンをアセンブルします。
$ h8300-elf-gcc -c crt0.s
そして、main.cをコンパイルします。
$ h8300-elf-gcc -c -mh -mn main.c
さらに、interrupt.cをコンパイルします。
$ h8300-elf-gcc -c -mh -mn interrupt.c
最後にリンクして、実行ファイルを作りましょう。
$ h8300-elf-gcc -o swcount.bin -T 3664.x -nostdlib -mh -mn crt0.o main.o interrupt.o
いかがでしょうか。ソースファイルの数だけコンパイルし、最後にリンクすればよいのです。意外と簡単ですよね。
なるほど、割り込みも奥が深いなぁ。
そうね。
制御のプログラムってイベント処理が多いから。
ところで晴子さん。
宿題がちゃんとできたご褒美(デート)、いつにしましょうか?
えっ、ワタシいつそんな約束したかしら。
あっ、いけない。今日買い物頼まれているんだったわ。
健一君にはいつもどおり宿題を用意しといたから、ワタシ帰るね。
バイバーイ。
えっー!!
H8Tiny-USBから通信で「Hello world」を送ってね。パソコンに通信ソフトをインストールしないとダメよ!!
前回に引き続き、タイマ割り込みをテーマに、7セグメントLEDのダイナミック点灯を行いました。これでH8Tiny-USBのハードウェアをすべて使いこなしたことに……。といいたいところですが、まだ「シリアル通信」が残っていますね。
H8Tiny-USBとパソコンをつなぐUSBケーブルは、電源の供給、プログラムのダウンロードのほか、H8Tiny-USBとの通信に使うことができます。というわけで、次回(ついに完結!!)は、シリアル通信によるprintf関数を作ってみましょう。お楽しみに!(次回に続く)
Copyright © ITmedia, Inc. All Rights Reserved.
組み込み開発の記事ランキング
コーナーリンク