AVRでのタイマとPWMの使い方
今回の内容
AVRでのタイマとPWMの使い方を説明します。タイマには、8bitタイマと16bitタイマがあり、16bitの方がより多くのパターンを表せます。また、AVRであるATmega48,88,168,328にはPWMを使えるピンが6つあります。AVRでLEDをPWMで明るさを制御するプログラムも作成しました。
次回の内容
次回は、AVRでの割り込みの使い方について説明します。
[追記] AVRに関する記事を以下の記事にまとめましたので、ぜひご覧ください。
AVRに関する記事
タイマとPWM
PWMを使うには、まずタイマについて理解しなければなりません。タイマには、8bitタイマと16bitタイマがあります。16bitの方がより多くのパターンを表せます。
- 8bitタイマは、「0〜255」(2の8乗通り)のパターンを表せます
- 16bitタイマは、「0〜65535」(2の16乗通り)のパターンを表せます
例: AVRの動作周波数が1[MHz]のとき、1/1M = 0.000001[s]が表せる最小の時間なので8bitタイマでは、最大0.000001 * 256 = 0.256[ms] までの時間を表せます。
16bitタイマでは、最大0.000001 * 65536 = 65.536[ms] までの時間を表せます。
タイマとPWMの関係を図1に示します。タイマは実線(青)とし、PWM出力は実線(赤)とします。
青線は、タイマ(カウンタ)で0からTOP値までカウントしていきます。TOP値を超えると「オーバーフロー割り込み」が発生し、TOP値を超えたことを知らせてくれます。その後、タイマ(カウンタ)の値は0に戻り、カウントが再開されます。
また、指定した値に到達したことを知らせてくれる割り込み「比較一致割り込み」などの割り込みがあります。比較一致(コンペアマッチ)のときに、波形をHIGH、LOW、反転させることでPWM制御ができます(赤線)。
キーワード
- タイマモードの種類
- 標準モード (普通のタイマ、カウンタを使う)
- CTCモード (カウンタの上限を自由に設定)
- 高速PWM (タイマが、ノコギリ波)
- 位相基準PWM (タイマが、三角波)
- PWM,タイマが出力できるピン
- 1. OCR0A(PD6)とOCR0B(PD5)
- 2. OCR1A(PB1)とOCR1B(PB2)
- 3. OCR2A(PB3)とOCR2B(PD3)
- タイマとPWMを使うための設定
- 1のための設定: TCCR0AとTCCR0B
- 2のための設定: TCCR1AとTCCR1B
- 3のための設定: TCCR2AとTCCR2B
- これらは、タイマ設定レジスタである
タイマモード
タイマのモードには、「標準」「CTC」「位相基準PWM」「高速PWM」があります。PWMを使いたいときは、タイマモードを「位相基準PWM」「高速PWM」に設定することで使えます。
タイマとPWMの関係をもう一度、図2に示します。タイマは実線(青)とし、PWM出力は実線(赤)とします。
PWMとタイマを使用するための説明を行います。この図は、タイマ0(8bitタイマ)の図ですが、他のタイマでも似たような感じです。
-
標準モードは、カウンタとして動作させたい時に使用します。
(普通のタイマ) - コンペアマッチ(指定値とタイマの値が一致)するための指定値はOCRNA,B(Nは数字,後で詳し説明)で設定されます。 その値を超えたらTOPになるまでPWM信号は0を出力し、その後、タイマは0に戻ります。 しかし、MAXの値をTOP=OCRNA,B(Nは数字)とすることで、MAXの値まで行かなくてもタイマを0に戻すことができます。 これをCTCモードといいます。
- 高速PWMモードは、PWMを使うときに使用します。 動作原理は、図2の通りです(タイマはノコギリ波で表される)。
- 位相基準PWMモードもPWMを扱いますが、高速PWMとは違い、タイマは三角波で表されます。
PWM出力ができるピン
ATmega48,88,168,328にはPWMを使えるピンが6つあります。
OCR0A(PD6)とOCR0B(PD5), OCR1A(PB1)とOCR1B(PB2), OCR2A(PB3)とOCR2B(PD3)。カッコ内がピン名です。
上記6つのピンに対するタイマやPWMの設定は、それぞれTCCR0AとTCCR0B, TCCR1AとTCCR1B, TCCR2AとTCCR2Bで設定します。
TCCR○Aは、タイマレジスタの7,6bitで使い方を指定し、
TCCR○Bは、タイマレジスタの5,4bitで使い方を指定します。
タイマ | 8bitタイマ (タイマ0) | 16bitタイマ (タイマ1) | 8bitタイマ (タイマ2) |
---|---|---|---|
ピン設定 | TCCR0AとTCCR0B | TCCR1AとTCCR1B | TCCR2AとTCCR2B |
ピン出力 | OCR0A, OCR0B | OCR1A, OCR1B | OCR2A, OCR2B |
ピン名 | PD6およびPD5 | PB1およびPB2 | PB3およびPD3 |
タイマ設定レジスタ
8bitタイマであるタイマ0 [OCR0A(PD6)とOCR0B(PD5)] を使う場合は、TCCR0AとTCCR0BでタイマとPWMの設定を行います。
TCCR0Aで、PWMのコンペアマッチとタイマのモード設定を行い、
TCCR0BでタイマのTOP値と、クロック分周の設定を行うことができます。
詳細は、以下の "タイマ0のレジスタ設定" に示します。
16bitタイマであるタイマ1 [OCR1A(PB1)とOCR1B(PB2)] を使う場合は、
TCCR1AとTCCR1BでタイマとPWMの設定を行います。
詳細は、以下の "タイマ1のレジスタ設定" に示します。
8bitタイマのタイマ3 [OCR2A(PB3)とOCR2B(PD3)] については、 タイマ0とほぼ一緒なので割愛します。
タイマ0のレジスタ設定
PWM出力方法 (コンペアマッチA) 出力ピン : OC0A |
PWM出力方法 (コンペアマッチB) 出力ピン : OC0B |
関係なし | 関係なし | タイマのモード設定(一部) | |||||
---|---|---|---|---|---|---|---|---|---|
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
名前 | COM0A1 | COM0A0 | COM0B1 | COM0B0 | - | - | WGM01 | WGM00 | |
波形出力なし | 0 | 0 | 0 | 0 | - | - | 0 | 0 | 標準 |
コンペアマッチで トグル | 0 | 1 | 0 | 1 | - | - | 1 | 0 | CTC |
コンペアマッチで LOW |--__| |
1 | 0 | 1 | 0 | - | - | 0 | 1 | 位相基準PWM |
コンペアマッチで HIGH |__--| |
1 | 1 | 1 | 1 | - | - | 1 | 1 | 高速PWM |
上記の表(TCCR0Aタイマ0設定レジスタ表)を見られない方は、画像を用意しましたのでTCCR0Aタイマ0設定レジスタ表の画像をご覧ください。
OC0A,B強制変更 | - | - | タイマモード設定 (一部) | クロック分周の設定 | ||||
---|---|---|---|---|---|---|---|---|
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
名前 | FOC0A | FOC0B | - | - | WGM02 | CS02 | CS01 | CS00 |
役割 | 強制コンペアマッチ (非PWMモードのみ) |
- | - | 下で説明 | クロック分周の選択 |
上記の表(TCCR0Bレジスタ表)を見られない方は、画像を用意しましたのでTCCR0Bレジスタ表の画像をご覧ください。
WGM02 | WGM01 | QGM00 | 動作モード | TOP |
---|---|---|---|---|
0 | 0 | 0 | 標準 | 0xff |
1 | 0 | 0 | 予約 | - |
0 | 0 | 1 | 位相基準PWM | 0xff |
1 | 0 | 1 | 位相基準PWM | OCRA |
0 | 1 | 0 | CTC | OCRA |
1 | 1 | 0 | 予約 | - |
0 | 1 | 1 | 高速PWM | 0xff |
1 | 1 | 1 | 高速PWM | OCRA |
名前 | CS02 | CS01 | CS00 |
---|---|---|---|
TCCR0Bでのビット | 2 | 1 | 0 |
タイマ停止 | 0 | 0 | 0 |
分周なし | 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 |
タイマ1のレジスタ設定
PWM出力方法 (コンペアマッチA) 出力ピン : OC1A |
PWM出力方法 (コンペアマッチB) 出力ピン : OC2B |
関係なし | 関係なし | タイマモード設定 (一部) |
||||
---|---|---|---|---|---|---|---|---|
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
名前 | COM1A1 | COM1A0 | COM1B1 | COM1B0 | - | - | WGM11 | WGM10 |
波形出力なし | 0 | 0 | 0 | 0 | - | - | タイマモード設定 (下で説明) |
|
コンペアマッチで トグル | 0 | 1 | 0 | 1 | - | - | ||
コンペアマッチで LOW |--__| |
1 | 0 | 1 | 0 | - | - | ||
コンペアマッチで HIGH |__--| |
1 | 1 | 1 | 1 | - | - |
上記の表(TCCR1Aタイマ1設定レジスタ表)を見られない方は、画像を用意しましたのでTCCR1Aタイマ設定1レジスタ表の画像をご覧ください。
インプットキャプチャ | - | タイマモード設定 (一部) |
クロック分周の設定 | |||||
---|---|---|---|---|---|---|---|---|
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
名前 | 1CNC1 | 1CES1 | - | WGM13 | WGM12 | CS12 | CS11 | CS10 |
役割 | ノイズ除去器を有効にする。 (4回同じ入力で1入力される) |
エッジ設定 0:立ち下がり 1:立ち上がり | - | タイマモード設定 (下で説明) |
クロック分周の選択 |
上記の表(TCCR1Bレジスタ表)を見られない方は、画像を用意しましたのでTCCR1Bレジスタ表の画像をご覧ください。
WGM13 | WGM12 | WGM11 | QGM10 | 動作モード | TOP |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 標準 | 0xffff |
0 | 0 | 0 | 1 | 8bit位相基準PWM | 0x00ff |
0 | 0 | 1 | 0 | 9bit位相基準PWM | 0x01ff |
0 | 0 | 1 | 1 | 10bit位相基準PWM | 0x03ff |
1 | 0 | 0 | 0 | 位相・周波数基準PWM | ICR1 |
1 | 0 | 0 | 1 | 位相・周波数基準PWM | OCR1A |
1 | 0 | 1 | 0 | 位相基準PWM | ICR1 |
1 | 0 | 1 | 1 | 位相基準PWM | OCR1A |
0 | 1 | 0 | 0 | CTC | OCR1A |
1 | 1 | 0 | 0 | CTC | ICR1 |
1 | 1 | 0 | 1 | 予約 | - |
0 | 1 | 0 | 1 | 8bit高速PWM | 0x00ff |
0 | 1 | 1 | 0 | 9bit高速PWM | 0x01ff |
0 | 1 | 1 | 1 | 10bit高速PWM | 0x03ff |
1 | 1 | 1 | 0 | 高速PWM | ICR1 |
1 | 1 | 1 | 1 | 高速PWM | OCR1A |
名前 | CS12 | CS11 | CS10 |
---|---|---|---|
TCCR1Bでのビット | 2 | 1 | 0 |
タイマ停止 | 0 | 0 | 0 |
分周なし | 0 | 0 | 1 |
分周1/8 | 0 | 1 | 0 |
分周1/64 | 0 | 1 | 1 |
分周1/256 | 1 | 0 | 0 |
分周1/1024 | 1 | 0 | 1 |
外部クロック。T1を立ち下がりエッジで. | 1 | 1 | 0 |
外部クロック。T1を立ち上がりエッジで. | 1 | 1 | 1 |
結局、PWMを使うときの設定
- タイマ0 (8bit)のとき
- レジスタ : TCCR0AとTCCR0B
- HIGH時間を指定する : OCR0A(PD6),OCR0B(PD5)
- タイマ1 (16bit)のとき
- レジスタ : TCCR1AとTCCR1B
- HIGH時間を指定する : OCR1A(PB1),OCR1B(PB2)
- TOP値を指定する : ICR1
- タイマ2 (8bit)のとき
- レジスタ : TCCR2AとTCCR2B
- HIGH時間を指定する : OCR2A(PB3)とOCR2B(PD3)
上記を設定してあげれば使えます。 ごちゃごちゃあったように感じるけど、案外、あっさりしてる。
PWMのプログラム例
タイマ1を使ってPWMでLEDを点滅させます。PB0にスイッチを付け、スイッチを押したとき点滅するプログラムを以下に示します。なお、PORTB="0x00000001" とすることでPB0のプルアップ抵抗を有効にしているので、スイッチに抵抗を付ける必要はありません。
/* タイマ0 : 8bit : 0~255 タイマ1 : 16bit : 0~65535 1MHzで動作すると仮定して, 1クロック 0.000001sec なので、 タイマ1 : 0.000001*65536 = 65.5ms までOK */ /* 高速PWMモード ICR1 : 最大値 OCR1A (データシートのpin配置ではOC1A) : 真ん中 | ICR1 |----------------------- | /\ | / \ / OCR1A|------\------/----------- | / \ / |/ \/ 出力波形(PB1) | |--________________--___ | CTCモード : 最大値はICR1 通常モード : 最大値はOCR1A */ /* タイマ1をつかう */ #include <avr/io.h> int main(void){ //制御レジスタA TCCR1A = 0b10000010; //10:コンペアマッチAでLOW,10:高速PWM動作 //制御レジスタB TCCR1B = 0b00011001; //11:高速PWM動作, 001:分周なし //最大値 ICR1 = 64999; //0から数える. 全体時間 65ms //0.000001 * 65000 : 65ms //HIGHの時間(クロック数) OCR1A = 32499; //0から数える. High時間 32.5ms //0.000001 * 32500 : 32.5ms //OCR1AはPB1ピン DDRB = 0b11111110; //portB : 0bit目のみ入力 PORTB = 0b00000001; //PB0のプルアップ抵抗を有効に. while(1){ if(bit_is_clear(PINB,PB0)){ //PB0が0(on)なら OCR1A = 32499; //PB1 HIGH時間 32.5ms //OCR1Aの値を変えることで、LEDが光る時間を調節できる } else{ OCR1A = 0; //PB1 HIGH時間 0ms } } return 0; }
#includeの前は、コメントなので気にしないでください。
PWMの設定
- TCCR1AとTCCR1Bで、タイマ1を使うための設定をします。
-
ICR1で、タイマ(カウンタ)のTOP値を決めます。(ICR1=64999)
0から数えるので、65000回、カウントアップされる。
1MHz(=0.000001s)なので、0.000001*65000=65[ms]が1周期。 -
OCR1Aで、PWM波形のHIGHの時間を決めます。(OCR1A=32499)
同様に、0.000001*32500 = 32.5[ms]が、1周期のHIGH時間
その他の設定
- DDRBで入出力設定、PORTBでPB0のプルアップ抵抗を有効に。
- bit_is_clear(PINB,PB0) でPB0が0 (スイッチon)のとき trueとなる。
- スイッチonで、PWM波形のHIGH時間を 32.5[ms]とする。
- スイッチoffで、HIGH時間を 0[ms]にする。
PWM用に作成した回路
今回は、スイッチを押すとPWM制御により、LEDが点滅する回路を作成しました。
図3,4の回路は、スイッチにプルアップ抵抗を付けていません。 先ほどのプログラム中でAVRが用意しているプルアップ抵抗を有効にしたので、いらないのです。 ちなみに、AVRのプルアップ抵抗を有効にしない場合は、以下のように、抵抗を付ける必要があります。
では、プログラムをAVRに書き込んで、スイッチを押してみてください。 点滅したでしょ。画像なので点灯してるように見えますが、ちゃんと点滅してましたよ。
このことを生かして、TVのリモコンを作っていきたいと思います。 その前に、割り込み制御について話しておきます。
<< リモコンの動作原理へ | AVRの割り込みの使い方へ >> |