今まで使っていた,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 ++;
}
void wait(uint16_t w){
wait_time = 0;
while (wait_time<w);
}
wait_timeを0に設定して,wait_timeがw以上になるのを待つだけです. wait_timeは,タイマー割り込みで勝手に増加していきます.
一秒ごとにLEDを順番にONにしていって,またOFFします.
////////////////////////////////////////////////////////////////////////////
// タイマー割り込み サンプル
//
#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;
}
というような関数を作ると,間に色々な処理を入れても,前回からの待ち時間を一定にできるので, ループの周期を一定に保つときは便利かもしれません.