うしこlog
公開: 2013/07/14

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出力は実線(赤)とします。

タイマとPWM
タイマと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
タイマと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のレジスタ設定

TCCR0A タイマ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設定レジスタ表の画像をご覧ください。

TCCR0B レジスタ
OC0A,B強制変更 - - タイマモード設定
(一部)
クロック分周の設定
ビット 7 6 5 4 3 2 1 0
名前 FOC0A FOC0B - - WGM02 CS02 CS01 CS00
役割 強制コンペアマッチ
(非PWMモードのみ)
- - 下で説明 クロック分周の選択

上記の表(TCCR0Bレジスタ表)を見られない方は、画像を用意しましたのでTCCR0Bレジスタ表の画像をご覧ください。

タイマモード設定 WGMの役割
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のレジスタ設定

TCCR1A タイマ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レジスタ表の画像をご覧ください。

TCCR1B レジスタ
インプットキャプチャ - タイマモード設定
(一部)
クロック分周の設定
ビット 7 6 5 4 3 2 1 0
名前 1CNC1 1CES1 - WGM13 WGM12 CS12 CS11 CS10
役割 ノイズ除去器を有効にする。
(4回同じ入力で1入力される)
エッジ設定
0:立ち下がり
1:立ち上がり
- タイマモード設定
(下で説明)
クロック分周の選択

上記の表(TCCR1Bレジスタ表)を見られない方は、画像を用意しましたのでTCCR1Bレジスタ表の画像をご覧ください。

タイマモード設定 WGMの役割
WGM13 WGM12 WGM11 QGM10 動作モード TOP
00 0 0 標準 0xffff
00 0 1 8bit位相基準PWM 0x00ff
00 1 0 9bit位相基準PWM 0x01ff
00 1 1 10bit位相基準PWM 0x03ff
10 0 0 位相・周波数基準PWM ICR1
10 0 1 位相・周波数基準PWM OCR1A
10 1 0 位相基準PWM ICR1
10 1 1 位相基準PWM OCR1A
01 0 0 CTC OCR1A
11 0 0 CTC ICR1
11 0 1 予約 -
01 0 1 8bit高速PWM 0x00ff
01 1 0 9bit高速PWM 0x01ff
01 1 1 10bit高速PWM 0x03ff
11 1 0 高速PWM ICR1
11 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が点滅する回路を作成しました。

PWMでLEDを制御する回路図
PWMでLEDを制御する回路図
PWMでLEDを制御する回路
PWMでLEDを制御する回路

 図3,4の回路は、スイッチにプルアップ抵抗を付けていません。 先ほどのプログラム中でAVRが用意しているプルアップ抵抗を有効にしたので、いらないのです。 ちなみに、AVRのプルアップ抵抗を有効にしない場合は、以下のように、抵抗を付ける必要があります。

プルアップ抵抗
プルアップ抵抗

 では、プログラムをAVRに書き込んで、スイッチを押してみてください。 点滅したでしょ。画像なので点灯してるように見えますが、ちゃんと点滅してましたよ。

PWMでLEDを点滅
PWMでLEDを点滅

 このことを生かして、TVのリモコンを作っていきたいと思います。 その前に、割り込み制御について話しておきます。

<< リモコンの動作原理 AVRの割り込みの使い方へ >>