タイマーを使う

今まで使っていた,wait()関数は,あまり正確ではありません. 単位がどれくらいなのか,経験的にしか分かりませんし, コンパイルする環境によって,待ち時間がかわったりします.

今回使うMEGA88には3つの独立したタイマーがあり,一定時間ごとに決められた動作をすることが出来ます. タイマー0~2がありますが,0と1は,それぞれモータとサーボに使っているので, 残っているのはタイマー2です.

タイマーの使い方

詳しい使い方は抜きにして例だけ書きます.

割り込み

タイマーを使って決められた動作をするために,割り込みという機能を使います. 割り込みを使うと,イベントが起きた瞬間にその動作をさせて,終わったら もとの処理に戻るということが簡単にできます.

割り込みを使うには,「avr/interrupt.h」をインクルードする必要があります. (古いバージョンのavr-gccでは,avr/signal.hも必用かもしれません) 先頭に以下の行を加えてください.

#include <avr/interrupt.h>

タイマーを使うには,いくつかのレジスタを設定する必要があります. さらに,割り込みをつかうので,sei()で割り込みを有効にしてください.

	// タイマー2割り込み設定
	TCCR2A = 0;
	TCCR2B = 0x03; // 32分周 (1KHz)
	TCNT2 = 0; // カウンタ初期化
	TIMSK2 = 1<<TOIE2; //オーバーフロー割り込み許可
	sei();//割り込み有効

今回のAVRは8000KHzで動いているので,32分周すると250KHzになります. さらに,8ビットのカウンタなので,256回に一度オーバーフローします. オーバーフローで割り込みが起きるようにしているので, つまり,256/250 = 1.024msごとに,割り込みが起きます.

(比較一致の機能を使えば,正確に1msごとに割り込みを掛けることもできますが, 各自やってください)

次に,割り込み時に呼ばれる関数を書きます. 今回は,変数をインクリメント(++)しているだけです. 割り込みが起きるたびに,wait_timeの値が増加していきます.

// Timer-2 Overflow
volatile uint16_t wait_time=0;
SIGNAL(SIG_OVERFLOW2) {
	wait_time ++;
}

wait()関数

void wait(uint16_t w){
	wait_time = 0;
	while (wait_time<w);
}

wait_timeを0に設定して,wait_timeがw以上になるのを待つだけです. wait_timeは,タイマー割り込みで勝手に増加していきます.

プログラム例

一秒ごとにLEDを順番にONにしていって,またOFFします.

timer_test.c

////////////////////////////////////////////////////////////////////////////
//    タイマー割り込み サンプル
//
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t wait_time=0;

// Timer-2 Overflow
SIGNAL(SIG_OVERFLOW2) {
	wait_time ++;
}

void wait(uint16_t w){
	wait_time = 0;
	while (wait_time<w);
}

int main()
{
	int i;

	// ポート初期化
	DDRB = 0xFF; // モータ
	DDRC = 0x00; // ボタン,センサー
	DDRD = 0xFF; // モータ,LED
	PORTC |= 3; // プルアップON

	// タイマー2割り込み設定
	TCCR2A = 0;
	TCCR2B = 0x03; // 32分周 (1KHz)
	TCNT2 = 0; // カウンタ初期化
	TIMSK2 = 1<<TOIE2; //オーバーフロー割り込み許可
	sei();//割り込み有効


	//LED 点灯確認
	for(i = 0; i <= 3; i++){
		PORTD |= 1<<i;
		wait(1000);
	}
	for(i = 0; i <= 3; i++){
		PORTD &= ~(1<<i);
		wait(1000);
	}

	for(;;);

}

解説

特に無し.

void wait2(uint16_t w){
	while (wait_time<w);
	wait_time = 0;
}

というような関数を作ると,間に色々な処理を入れても,前回からの待ち時間を一定にできるので, ループの周期を一定に保つときは便利かもしれません.

この文書の履歴

Copyright © 瓶詰堂 all rights reserved.