Arduino UNO割り込みタイマー

タイマはすべてのマイコンに組み込まれている機能で、時間の経過に関する特定の機能を持っています。マイコンのタイマ機能を具体的に説明すると、プログラムが実行されるタイミングと停止されるタイミングを決める機能です。マイコンのTimerはいくつかのレジスタで構成され、その値は自動的に減ったり増えたりします。Arduino UNOには、8ビット分解能のタイマーと16ビット分解能のタイマーの2種類があります。しかし、この命令ではArduino UNOでタイマーを実行し、設定する方法に焦点を当てるので、FSテックではこのタイマーについて詳しく説明しません。

割り込みタイマーを使う理由

マイコンにタイマーを設定することで、ある時間間隔で非常に特定の時間を使ったプログラムをマルチタスクで実行することができる。ご存知のように、Arduinoはvoid loop(void) {}関数を使ってループするプログラムを書かれた順番に実行しますが、この関数に含まれるイベントの時間を特定するのは非常に困難です。これは、あるコマンドは非常に速く実行され、他のコマンドは非常にゆっくりと実行されるためで、これは実行されるプログラムの数や、if、while、do while、for loopなどの条件文によって決まります。Arduinoのloop()関数で実行されるタイマーは、Arduinoライブラリに含まれる多くの関数のため、予測するのが非常に困難です。

インターラプト・タイマーを実行すると、loop()関数の実行時間が停止し、loop()関数の外側のタイマーで実行される一連の個別のプログラムが実行され、別のタイマーがプログラムの実行を終了した後にタイマーを戻して再びloop()関数が実行されます。

割り込みタイマーを実行することで得られる利点には、以下のようなものがある:

  • 受信信号を等間隔で測定
  • 2つのプログラム間の時間を計算する
  • 特定の周波数で信号を送受信する
  • 受信シリアルデータを定期的にチェックする
  • 2つのプログラムを同時に実行(マルチタスク)
  • その他多数

プリスケーラとタイマ値の計算

Arduino UNOには、Timer-0、Timer-1、Timer-3の3つのタイマーがあります。Arduino Unoの各タイマは、レジスタに格納されている一定の値に達するまで、時間ごとに設定値が増えていき、その値に達するたびにリセットされます。そしてこのサイクルはArduinoの電源が入っている間続きます。タイマーの値はタイマーのアドレスビットの大きさによって異なり、例えば8ビットのタイマーの値の範囲は0~255、16ビットの分解能のタイマーの値の範囲は0~65535です。

タイマーを計算できるようにするには、プリスケーラーと呼ばれる計算を使うことができる。

タイマー速度(Hz) ArduinoClockSpeed(16MHz) / プリスケーラ

プリスケーラ・アドレスのプリスケーラ値

上の表は、各プリスケーラ・アドレスのプリスケーラ値を示しているので、タイマ演算値の式は以下の式で書ける。

割り込み周波数(Hz) ArduinoClockSpeed(16MHz) / ((プリスケーラ * (compareMatchRegister + 1))

0にインデックス付けされた一致するレジスタ値の比較による+1。

つまり、プリスケーラ値が欲しい場合、方程式は以下の式に従って書くことができる。

CompareMatchRegister = 比較一致登録 16MHz / (プリスケーラ * 割り込み希望周波数) - 1

また、タイマー-0とタイマー-2を使用する場合は256より小さい値でなければならず、タイマー-1を使用する場合は65536より小さい値でなければならないことに注意してください。 

タイマ割り込みを使ってマルチタスク・プログラムを実行する方法

タイマー-0 2KHz

				
					voidセットアップ(void) {
	cli();
	TCCR0A = 0;
	TCCR0B = 0;
	TCNT0 = 0;
	OCR0A = 124;
	TCCR0A |= (1<<WGM01);
	TCCR0B |= (1<<cs01) | (1<<cs00);
	timsk0 |= (1<<ocie0a);
	sei();
}
				
			

TCCR0A = 0; TCCR0B, TCNT0 = 0; は時間値を 0 に戻す。

OCR0A コンペアマッチレジスタを2KHz単位で設定 (16*10^6)/(2000*64)-1

WGM01 CTCをオンにする

CS01 & CS00 64プリスケーラ用にCS01 & CS00ビットをセット

TIMSK0イネーブル・タイマー・コンペア割り込み

タイマー1 1Hz

				
					voidセットアップ(void) {
	cli();
	TCCR1A = 0;
	TCCR1B = 0;
	TCNT1 = 0;
	OCR1A = 15624;
	TCCR1B |= (1<<WGM12);
	TCCR1B |= (1<>cs10);
	timsk1 |= (1<<ocie1a);
	sei();
}
				
			

TCCR1A = 0; TCCR1B, TCNT1 = 0; は時間値を 0 に戻す。

OCR1A コンペアマッチレジスタを1Hz単位で設定 (16*10^6)/(1*1024)-1

WGM12 CTCをオンにする

CS10 & CS12 1024プリスケーラ用にCS10 & CS12ビットを設定

TIMSK1 イネーブル・タイマー・コンペア割り込み

タイマー2 8KHz

				
					voidセットアップ(void) {
	cli();
	TCCR2A = 0;
	TCCR2B = 0;
	TCNT2 = 0;
	OCR2A = 249;
	TCCR2A |= (1<<WGM21);
	TCCR2B |= (1<<cs21);
	timsk2 |= (1<<ocie2a);
	sei();
}
				
			

TCCR2A = 0; TCCR2B, TCNT2 = 0; は時間値を 0 に戻す。

OCR2A コンペアマッチレジスタを8KHz刻みで設定 (16*10^6)/(8000*8)-1

WGM21 CTCをオンにする

CS21 8プリスケーラ用CS21ビット設定

TIMSK1 イネーブル・タイマー・コンペア割り込み

タイマーを何個でも使用するには、CTCモードが必要です。

TCCR0A |= (1 << WGM01); // タイマー0用

TCCR1B |= (1 << WGM12); // タイマー1用

TCCR2A |= (1 << WGM21); // タイマー2用

また、プリスケーラの数は表のとおりです。

TCCR1B |= (1 << CS11); // タイマー1用8プリスケーラ 

TCCR2B |= (1 << CS22); // タイマー2用64プリスケーラ

TCCR0B |= (1 << CS02) | (1 << CS00); // タイマー0用の1024プリスケーラ

このタイマー割り込み中に実行したいコマンドは、void setup(void)関数とvoid loop(void)関数の外にあるArduinoスケッチに以下のようにまとめてあり、各タイマーの例も説明しています。

ISR(TIMER0_COMPA_vect){」を実行する。

// タイマー0用

}

ISR(TIMER1_COMPA_vect){の場合

// タイマー1用

}

ISR(TIMER2_COMPA_vect){の場合

// タイマー2用

}

タイマーを起動するArduinoプログラム例

タイマー0の例 2KHz

				
					voidセットアップ(void) { { {ピンモード(11, OUTPUT)
	pinMode(11, OUTPUT);
	
	cli();
	TCCR0A = 0;
	TCCR0B = 0;
	TCNT0 = 0;
	OCR0A = 124;
	TCCR0A |= (1<<WGM01);
	TCCR0B |= (1<<cs01) | (1<<cs00);
	timsk0 |= (1<<ocie0a);
	sei();
}
void loop(void) {
	// delay()なしで何かをする
}
ISR(TIMER0_COMPA_vect){の場合
	static boolean toggle = true;
	toggle = !toggle;
	digitalWrite(11, toggle ? HIGH : LOW);
}</xmp
				
			

タイマー1の例 1Hz

				
					voidセットアップ(void) { { {ピンモード(11, OUTPUT)
	pinMode(11, OUTPUT);
	
	cli();
	TCCR1A = 0;
	TCCR1B = 0;
	TCNT1 = 0;
	OCR1A = 15624;
	TCCR1B |= (1<<WGM12);
	TCCR1B |= (1<>cs10);
	timsk1 |= (1<<ocie1a);
	sei();
}
void loop(void) {
	// delay()なしで何かをする
}
ISR(TIMER1_COMPA_vect){の場合
	static boolean toggle = true;
	toggle = !toggle;
	digitalWrite(11, toggle ? HIGH : LOW);
}</xmp
				
			

タイマー2の例 8KHz

				
					voidセットアップ(void) { { {ピンモード(11, OUTPUT)
	pinMode(11, OUTPUT);
	
	cli();
	TCCR2A = 0;
	TCCR2B = 0;
	TCNT2 = 0;
	OCR2A = 249;
	TCCR2A |= (1<<WGM21);
	TCCR2B |= (1<<cs21);
	timsk2 |= (1<<ocie2a);
	sei();
}
void loop(void) {
	// delay()なしで何かをする
}
ISR(TIMER1_COMPA_vect){の場合
	static boolean toggle = true;
	toggle = !toggle;
	digitalWrite(11, toggle ? HIGH : LOW);
}</xmp
				
			

エンディング

3つのタイマプログラムの例から、タイマ割り込みがアクティブになった場合、delay()関数を使用することは推奨されないことがわかります。特に、delay()関数の値がタイマ割り込みのプリスケーラ値を超えている場合、マイクロコントローラのすべてのタイマ動作を妨害する可能性があるからです、しかし、もしdelay()関数の値がプリスケーラの値を超えないのであれば、少しは許容できるかもしれません。

そして、説明するのを忘れていたかもしれないが、cli()関数とsei()関数が少し追加された。

cli()関数はタイマー割り込みを無効にするために使用される。

sei()関数はタイマー割り込みを起動するために使用される。

ありがとう。

ありがとう。

関連ブログ

Arduino UNO割り込みタイマー

Arduino UNO Interrupt Timer タイマーはすべてのマイクロコントローラーに組み込まれている機能で、時間の経過に関する特定の機能を持っています。タイマー機能

続きを読む "

ぜひ、ご意見をお聞かせください