index
タイマー

timer.c 内蔵のタイマーをカスケード接続して、正確に時間を計るプログラムの例です。screen 構造体のx-y座標に値を代入すると、エミュレータ上で正しく動作しないようなので、実機で動作テストしてください。もし、原因が解ったら教えてください。座標の保存のために配列を使用しなければ、エミュレータでも動作するようですが、マルチタスクOS上のエミュレータでは、正確な時間は計れません。
timer.c
/****************************************************************/
/*			Timer control				*/
/****************************************************************/

#include "gba.h"
#include "FontC64-08.c"
void init_screen(void);
void location(int, int);
void scroll(void);
void print(const char*);
void print_hex8(int);
void print_hex16(int);
FontC64-08.c は、キー入力と複数画面合成で使用したものと同じフォントデータ。
// Background palette base address pointer 0x05000000
hword* bcolor = (hword*) BG_PALETTE;

// Screen structures
screen plane[ 1 ] = {
	{ (hword*) VRAM_MAP(16), (hword*) VRAM_TILE(0), 0, 0},
};

int page = 0;				// page number
背景パレットのポインタ設定と、文字表示画面用のscreen型構造体を用意します。ここでは、背景を使用しないため、画面は1枚だけ必要なので、画面番号は page = 0 のみを使用します。
int main() {

	// Initialize screen
	init_screen();
init_screen 関数で、フォントデータの設定と画面の初期設定を行います。
	// Initialize timers
	gba_reg(TIMER_CNT0) = 0x0000;
	gba_reg(TIMER_CNT1) = 0x0000;
タイマー0とタイマー1のタイマー設定レジスタを16 bit の 0 に設定しています。これで、カウント初期値が、0になります。
	gba_reg(TIMER_CTL0) = TIMER_ENABLE + TIMER_PRE256;
	gba_reg(TIMER_CTL1) = TIMER_ENABLE + TIMER_CASCADE;
タイマー0とタイマー1のタイマー制御レジスタの値を、タイマー動作開始にすると同時に、タイマー1のプリスケーラ(分周器)を、256 = 28 周期に設定しています。これで、16 bit フルカウントすると、216 + 8 = 224となります。GBAのシステムクロックの周波数は、224Hz に設定されているため、16bit フルカウントすると、丁度1秒に相当します。ハードウエアの概要のページで確認してください。タイマー0だけでは、1秒までしかカウントできないので、タイマー1をカスケードモードにして1秒単位でカウントアップさせます。カスケードモードでは、前の番号のタイマーがオーバフローする毎に、1カウントするモードです。この設定方法も、ハードウエアの概要のページで確認してください。
	// Print loop
	while (1) {
		location(8, 7);
		print("Timer 0 : ");
		location(18, 7);
		print_hex16(gba_reg(TIMER_CNT0));
		location(8, 8);
		print("Timer 1 : ");
		location(18, 8);
		print_hex16(gba_reg(TIMER_CNT1));
	}
}
location 関数で、文字を出力する座標を指定し、タイマー0とタイマー1のカウント値を16進数4桁で表示します。
// Screen Initialization
void init_screen(void) {

	int i, row, col, bit, val;

	// Initialize palettes
	bcolor[ 0 ] = RGB(0, 0, 0);		// Black
	bcolor[ 1 ] = RGB(0, 31, 25); 		// Green

	// Setup tiles of font set
	for (i = 0; i < 96; i++) {
		for (row = 0; row < 8; row++) {
			for (col = 7; col >= 0; col--) {
				bit = (Font[ i ][ row ] & (1 << col)) ? 1 : 0;
				if (col % 2)
					val = bit;
				else
					plane[ 0 ].tile[((i + 32) * 32) + (row * 4) + \
                   ((7 - col)/2)] = val + (bit << 8);
			}
		}
	}
フォントデータをタイルに読み込みます。この処理は、テキスト表示のページと同じです。
	//Setup background mode and LCD control register
	gba_reg(BG0_CTL)  =	LCD_SIZE00   |
				LCD_COLOR256 |
				LCD_BGTILE(0)|
				LCD_BGMAP(16);
	gba_reg(LCD_CTL)  =	LCD_BG0 |
				LCD_MODE0;
}
文字表示用に背景コントロールレジスタとLCDコントロールレジスタを設定します。これまでに、何度も出てきたので、説明を省略します。
// Present position of tile character
void location(int xx, int yy) {

	if (xx < 0)
		plane[ page ].x = 0;
	else if (xx >= 30)
		plane[ page ].x = 30 - 1;
	else
		plane[ page ].x = xx;

	if (yy < 0)
		plane[ page ].y = 0;
	else if (yy >= 20)
		plane[ page ].y = 20 - 1;
	else
		plane[ page ].y = yy;
}
文字出力座標(タイル単位)を指定する関数です。キー入力と複数画面合成のページと同じものですから、内容説明は省略します。
// Scroll up
void scroll(void) {

	int i, j;

	// Scroll
	for (i = 1; i < 20; i++) {
		for (j = 0; j < 30; j++)
			plane[ page ].map[ (i - 1) * 32 + j ] = \
			plane[ page ].map[ i * 32 + j ];
		}
		// End line
	for (j = 0; j < 30; j++)
		plane[ page ].map[ 19 * 32 + j ] = 0x20; // SP in bottom line
}
文字出力画面をスクロールさせる関数です。キー入力と複数画面合成のページと同じものですから、内容説明は省略します。
// Print function
void print(const char* str) {

	const char* pt = str;

	while (*pt) {
		if (*pt == '\n') {
			plane[ page ].x = 0;
			if (plane[ page ].y < (20 - 1))
				plane[ page ].y++;
			else
				scroll();
			pt++;
			continue;
		}
		plane[ page ].map[ plane[ page ].y * 32 + plane[ page ].x ] = *pt++;
		if (plane[ page ].x < (30 - 1))
			plane[ page ].x++;
		else {
			plane[ page ].x = 0;
			if (plane[ page ].y < (20 - 1))
				plane[ page ].y++;
			else
				scroll();
		}
	}
}
文字列を表示する関数です。キー入力と複数画面合成のページと同じものですから、内容説明は省略します。
// Print 1Byte HEX
void print_hex8(int val) {
	char buf[ 3 ];

	buf[ 0 ] = "0123456789ABCDEF"[ (val & 0xF0) >> 4 ];
	buf[ 1 ] = "0123456789ABCDEF"[ val & 0x0F ];
	buf[ 2 ] = 0; // Null
	print(buf);
}
16進2桁の数値を表示する関数です。キー入力と複数画面合成のページと同じものですから、内容説明は省略します。
// Print 2Byte HEX
void print_hex16(int val) {
	print_hex8((val & 0xFF00) >> 8);
	print_hex8(val & 0x00FF);
}
16進4桁の数値を表示する関数です。キー入力と複数画面合成のページと同じものですから、内容説明は省略します。


お問い合わせはこちらまで: kitagawa@is.t.kanazawa-u.ac.jp

(c) Kanazawa Univ., 2004