これまで見てきたとおり、PWMの信号(パルス)を、IOポートをソフトウエアで制御することで作成することができた。
でも、これって面倒じゃないか?
PWMの出力をソフトでやろうとすると、他の処理に手が回らなくもなる。
こういった処理は専用のハードウエアにやらせたほうが効率的である...
ということでAVRマイコンにはタイマ機能の一部として、PWMの生成機能が実装されている。(タイマ機能の全体については、こちら)
AVR マイコンのPWMには、高速PWMモードと位相基準PWMモードがある。ここでは、タイマ0を用いた高速PWMモード(8bitタイマ)について説明す
る。(タイマ1、3は16bitタイマ。タイマ4は10bit。これらや、位相基準PWMモードなどのその他のモードについては、別に説明する。)
高速PWMモードは、更に2つのモードに分かれている。どちらのモードを使うかはTCCR0Bの第3ビットで選択する。
PWMの設定にはTCNT、OCR0A、OCR0B、TCCR0A、TCCR0B、TIMSK0(割り込みマスクレジスタ)、TIFR0(割り込みフラグレジスタ)のレジスタが関係する。また、TCNTは8bitの勝手に動作するカウンタで、システムクロック(16MHzもしくは1MHz)をプリスケーラで分周(周波数を何分の一かにすること)しカウントする。
OCR0A、OCR0Bレジスタも8bitのレジスタで、TCNTと値が一致したとき(比較・一致)に、PWM信号が切り替わる。(OCR0AとTCNTが一致した時はOC0A、OCR0BとTCNTが一致した時はOC0B)
各レジスタの役割を整理すると以下のとおり。
レジスタ名 | 機 能 |
TCNT0 | システムクロックをプリスケーラで分周した信号で自走するカウンタ |
TCCR0A | タイマ0の設定を行うレジスタ。 タイマモード、比較・一致発生時の出力 |
TCCR0B | タイマ0の設定を行うレジスタ。 タイマモード、プリスケーラの分周比 |
OCR0A | TCNT0との比較・一致を行う際に値を保管するレジスタ。 OC0A出力時のデューティ可変(モード3)、TCNT0の上限値(モード7) |
OCR0B | TCNT0との比較・一致を行う際に値を保管するレジスタ。 OC0B出力時のデューティ可変(モード3、7) |
TIMSK0 | 割り込みマスクレジスタ。比較・一致、TCNT0のオーバフローによる割り込み ハンドラの呼び出しを許可・禁止する。 |
TIFR0 | 割り込みフラグレジスタ。割り込みイベントの発生を記録する。 |
具体的な動作について、以下に説明する。
モード3では、
モード7では、
のように動作する。
TCCR0Aの各設定ビットの詳細は、以下のとおり。
まず、タイマの動作を、高速PWMモードに設定する。このためには、TCCR0AとTCCR0BのWGM0x(xは0~3)ビットを下表(タイマモードの設定)の様に設定する。
表:タイマモードの設定(TCCR0A、TCCR0B)
動作モード
レジスタ:bitの位置 (bitの名前) |
TCCR0B:3 |
TCCR0A:1 (WGM01) |
TCCR0A:0 (WGM00) |
TOP (TCNTが0に戻る時の上限値) |
TOV 割り込み |
モード0 (標準) | 0 | 0 | 0 | 0xFF | 0xFF |
モード1 (位相基準PWM) | 0 | 0 | 1 | 0xFF | 0 |
モード2 (CTC) | 0 | 1 | 0 | OCR0Aの値 | 0xFF |
モード3 (高速PWM) | 0 | 1 | 1 | 0xFF | 0xFF |
モード4 (予約) | 1 | 0 | 0 | - | |
モード5 (位相基準PWM) | 1 | 0 | 1 | OCR0Aの値 | 0 |
モード6 (予約) | 1 | 1 | 0 | - | |
モード7 (高速PWM) | 1 | 1 | 1 | OCR0Aの値 | 0xFF |
ここで、WGM02ビットを0に設定した場合は、TCNTの上限値は255、WGM02を1に設定した場合はTCNTの上限値はOCR0Aと同じ値になる。PWMの周期を様々に変えたい場合は、このモード(モード7)を使うと便利である。
また、WGM02を0とすると、OC0AとOC0Bの2本のPWM信号を出力可能だが、WGM02を1とすると、OC0Bのみとなる。
表:値の一致での動作(TCCR0A)
TCCR0Aのbitの位置 (ビットの名前) |
7 (COM0A1) |
6 (COM0A0) |
5 (COM0B1) |
4 (COM0B0) |
PWM出力 (OC0Aに出力) |
PWM出力 (OC0Bに出力) |
|||
波形出力なし | 0 | 0 | 0 | 0 |
TCNTとOCR0A・OCR0Bとの値の一致でPWM出力切替 | 0 | 1 | 0 | 1 |
TCNTとOCR0A・OCR0Bとの値の一致でPWM出力0 | 1 | 0 | 1 | 0 |
TCNTとOCR0A・OCR0Bとの値の一致でPWM出力1 | 1 | 1 | 1 | 1 |
※モード3の動作
表:プリスケーラの設定(TCCR0B)
TCCR0Bのbitの位置 (ビットの名前) |
2 (CS02) |
1 (CS01) |
0 (CS00) |
タイマ停止 | 0 | 0 | 0 |
1/1 | 0 | 0 | 1 |
1/8 | 0 | 1 | 0 |
1/64 | 0 | 1 | 1 |
1/256 | 1 | 0 | 0 |
1/1024 | 1 | 0 | 1 |
外部クロック(T0ピンの立下り) | 1 | 1 | 0 |
外部クロック(T0ピンの立上がり) | 1 | 1 | 1 |
プリスケーラは、TCNTのカウント入力の周波数を決める。システムクロック(16MHz、変更可能)を何分の一(分周)かにして、TCNTに供給する。
例えば、CS02:CS01:CS00を1:0:0と設定したとすると、システムクロックは1/256に分周される事になる。従って、TCNTは、
16000000 / 256 = 62500 Hz |
でカウントされることになる。(つまり一秒間に62500回、カウントアップされる)
この状態で、WGM02:WGM01:WGM00を0:1:1としたとすると、PWMの1周期は、
62500 / 255 = 245.098Hz |
となる。
また、WGM02:WGM01:WGM00を1:1:1として、OCR0Aを100とすると、
62500 / 100 = 625Hz |
となる。
サンプルプログラム1
(モード3:OC0AとOC0Bの2チャンネル出力)
/* ... 略 .... OCR0A = 200; // OC0A(29ピン~PB7)にduty = 200/256で出力 while(1) { |
サンプルプログラム2
(モード7:OC0A=周期、OC0B=デューティ、OC0Bの1チャンネル出力)
/* ... 略 ....
while(1) { |
PWMと割り込み
タイマ0の高速PWMでは、TCNTとOCR0A・OCR0Bとの比較・一致が発生した時に、割り込み(イベント)を発生させる事が出来る。
発生可能な割り込みイベントは、以下の3つである。
割り込み関連レジスタとビットの配置は、以下の通り。
表:割り込みフラグレジスタ(TIFR0)
bitの位置 (ビットの名前) |
7 (未使用) |
6 (未使用) |
5 (未使用) |
4 (未使用) |
3 (未使用) |
2 (OCF0B) |
1 (OCF0A) |
0 (TOV0) |
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
表:割り込みマスクレジスタ (TIMSK0)
bitの位置 (ビットの名前) |
7 (未使用) |
6 (未使用) |
5 (未使用) |
4 (未使用) |
3 (未使用) |
2 (OCIE0B) |
1 (OCIE0A) |
0 (TOIE0) |
初期値 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
サンプルプログラム(TCNTオーバフロー時の割り込みを使う例)
/* TCCR0A = 3; // タイマ・カウンタ・コントロールレジスタ
モード3(高速PWMモード) TCCR0A |= _BV(COM0A1); //
TCNT==OCR0Aで、OC0Aが0(GND)、TCNT=255でOC0Aが1(+5V) TCCR0A |= _BV(COM0B1); // TCNT==OCR0Bで、OC0Bをlow(=0)、TCNT=255でOC0Bをhi(=1) TCCR0B |= _BV(CS01); // 周波数設定(PWMの一周期) (TCNT:8bit) TIMSK0 |= _BV(TOIE0); //
TCNTが最大値を超えた時(0xFFもしくはOCR0Aの値)、割り込み発生
OCR0A = 200; // OC0A(29ピン~PB7)にduty = 200/256で出力 sei(); //
全ての割り込みを許可 |