ATmega328でのタイマとPWMの使用方法

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動

概要

タイマには、8bitタイマと16bitタイマがあり、16bitの方がより多くのパターンを表すことができる。
また、ATmega48、88、168、328にはPWMを使えるピンが6つある。


タイマとPWM

PWMを使用するには、まずタイマについて理解しなければならない。
タイマには、8bitタイマと16bitタイマがある。

8bitタイマは、0 - 255のパターンを表すことができる。
16bitタイマは、0 - 65535のパターンを表すことができる。

例 :
ATmega328の動作周波数が1[MHz]のとき、1/1,000,000 = 0.000001[s]が表せる最小の時間なので、
8bitタイマでは、最大0.000001 * 256 = 0.256[ms]までの時間を表すことができる。
16bitタイマでは、最大0.000001 * 65536 = 65.536[ms]までの時間を表すことができる。

タイマとPWMの関係を下図に示す。(タイマは実線(青)とし、PWM出力は実線(赤)とする)

ATmega328 Timer PWM 1.jpg


タイマ(カウンタ)は、0からTOP値までカウントしていく。(青線)
TOP値を超えるとオーバーフロー割り込みが発生し、TOP値を超えたことを知らせる。
その後、タイマ(カウンタ)の値は0に戻り、カウントが再開される。
また、指定した値に到達したことを知らせる割り込み"比較一致割り込み(コンペアマッチ)"等の割り込みもある。
比較一致のときに、波形をHIGH、LOW、反転させることでPWM制御ができる。(赤線)


キーワード

  • タイマモードの種類
    • 標準モード (普通のタイマ、カウンタを使う)
    • CTCモード (カウンタの上限を自由に設定)
    • 高速PWM (タイマが、ノコギリ波)
    • 位相基準PWM (タイマが、三角波)


  • タイマ、PWMが出力できるピン
    • OCR0A(PD6)とOCR0B(PD5)
    • OCR1A(PB1)とOCR1B(PB2)
    • OCR2A(PB3)とOCR2B(PD3)


  • タイマとPWMを使うための設定(これらは、タイマ設定レジスタである)
    • 1のための設定: TCCR0AとTCCR0B
    • 2のための設定: TCCR1AとTCCR1B
    • 3のための設定: TCCR2AとTCCR2B



タイマモード

タイマのモードには、標準、CTC、位相基準PWM、高速PWMがある。
PWMを使用する時は、タイマモードを位相基準PWM、高速PWMに設定することで使用できる。

タイマとPWMの関係を再度、下図に示す。(タイマは実線(青)とし、PWM出力は実線(赤)とする)
下図は、タイマ0(8bitタイマ)の図だが、他のタイマも似たものとなる。

ATmega328 Timer PWM 1.jpg


下記にタイマとPWMを使用するための説明を行う。

  • 標準モードは、カウンタとして動作させたい時に使用する。(普通のタイマ)
  • コンペアマッチ(指定値とタイマの値が一致)するための指定値はOCRnAまたはOCRnB(nは数字、後述)で設定する。
その値を超えたらTOPの値になるまでPWM信号は0を出力し、その後、タイマは0に戻る。
しかし、TOPの値をTOP = OCRnAまたはTOP = OCRnBとすることで、TOPの値まで行かなくてもタイマを0に戻すことができる。
これを、CTCモードという。
  • 高速PWMモードは、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で設定する。

TCCRnAは、タイマレジスタの7 - 6bitで使い方を指定し、
TCCRnBは、タイマレジスタの5 - 4bitで使い方を指定する。

ピンの役割
8bitタイマ(タイマ0) 16bitタイマ(タイマ1) 8bitタイマ(タイマ2)
ピン設定 TCCR0A
TCCR0B
TCCR1A
TCCR1B
TCCR2A
TCCR2B
ピン出力 OCR0A
OCR0B
OCR1A
OCR1B
OCR2A
OCR2B
ピン名 PD6(OCR0A)
PD5(OCR0B)
PB1(OCR1A)
PB2(OCR1B)
PB3(OCR2A)
PD3(OCR2B)



タイマ設定レジスタ

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タイマであるタイマ2(OCR2A(PB3)とOCR2B(PD3))を使用する場合は、タイマ0とほぼ同じなので割愛する。



タイマ0のレジスタ設定

タイマ0の設定レジスタであるTCCR0Aの設定を下表に示す。

TCCR0A タイマ0設定レジスタ
PWM出力方法(コンペアマッチA)
出力ピン : OCR0A(PD6)
PWM出力方法(コンペアマッチB)
出力ピン : OCR0B(PD5)
設定なし 設定なし タイマのモード設定(一部)
ビット名 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


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


WGMの役割 タイマモード設定
WGM02 WGM01 WGM00 動作モード TOP
0 0 0 標準 0xFF
1 0 0 予約 -
0 0 1 位相基準PWM 0xFF
1 0 1 位相基準PWM OCR0A
0 1 0 CTC OCR0A
1 1 0 予約 -
0 1 1 高速PWM 0xFF
1 1 1 高速PWM OCR0A


クロック分周の設定
設定 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のレジスタ設定

タイマ1の設定レジスタであるTCCR1Aの設定を下表に示す。

TCCR1A タイマ1設定レジスタ
PWM出力方法
(コンペアマッチA)
出力ピン : OCR1A(PB1)
PWM出力方法
(コンペアマッチB)
出力ピン : OCR1B(PB2)
設定なし 設定なし タイマのモード設定(一部)
ビット名 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 - -


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


WGMの役割 タイマモード設定
WGM13 WGM12 WGM11 WGM10 動作モード TOP
0 0 0 0 標準 0xFFFF
0 0 0 1 8bit位相標準PWM 0x00FF
0 0 1 0 9bit位相標準PWM 0x1FFF
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
外部クロック
T0を立ち下がりエッジで
1 1 0
外部クロック
T0を立ち上がりエッジで
1 1 1



タイマ2のレジスタ設定

タイマ2の設定レジスタであるTCCR2Aの設定を下表に示す。

TCCR2A タイマ2設定レジスタ
PWM出力方法(コンペアマッチA)
出力ピン : OCR2A
PWM出力方法(コンペアマッチB)
出力ピン : OCR2B
設定なし 設定なし タイマのモード設定(一部)
ビット名 7 6 5 4 3 2 1 0
レジスタ名 COM2A1 COM2A0 COM2B1 COM2B0 - - WGM21 WGM20
波形出力なし 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


TCCR2B タイマ2設定レジスタ
OCR2AおよびOCR2Bの強制変更 設定なし 設定なし タイマモード設定(一部) クロック分周の設定
ビット名 7 6 5 4 3 2 1 0
レジスタ名 FOC2A FOC2B - - WGM22 CS22 CS21 CS20
役割 強制コンペアマッチ
(非PWMモードのみ)
- - 下で説明する クロック分周の選択


WGMの役割 タイマモード設定
WGM22 WGM21 WGM20 動作モード TOP
0 0 0 標準 0xFF
1 0 0 予約 -
0 0 1 8bit位相基準PWM 0xFF
1 0 1 位相基準PWM OCR2A
0 1 0 CTC OCR2A
1 1 0 予約 -
0 1 1 8bit高速PWM 0xFF
1 1 1 高速PWM OCR2A


クロック分周の設定
設定 CS22 CS21 CS20
ビット名(TCCR2B) 2 1 0
タイマ停止 0 0 0
分周なし 0 0 1
分周 1 / 8 0 1 0
分周 1 / 32 0 1 1
分周 1 / 64 1 0 0
分周 1 / 128 1 0 1
分周 1 / 256 1 1 0
分周 1 / 1024 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)



ソースコード

タイマ1を使用してPWM制御でLEDを点滅させる。
PB0にスイッチを付けて、スイッチを押下した時にLEDが点滅するプログラムを以下に記述する。
なお、PORTB = 0b00000001とすることで、PB0のプルアップが有効になるので、プルアップ抵抗を付ける必要はない。

 // タイマ0 : 8bit  : 0 -   255
 // タイマ1 : 16bit : 0 - 65535
 
 // 1[MHz]で動作すると仮定すると、1クロック0.000001[s]なので
 // タイマ1 : 0.000001 * 65536 = 65.5[ms]までOK
 
 /*  高速PWMモード
  ICR1 : 最大値
  OCR1A(データシートのピン配置ではOC1A) : 真ん中
 
    |
 ICR1 ----/\------------------------
    |    /   \
    |   /      \         /
 OCR1A /---------\------/-----------
    | /            \   /
    |/               \/
 
  PB1 出力波形
    |
    | ̄|                  | ̄|
    |  |__________________|  |___
    |

  CTCモード : 最大値はICR1
  通常モード : 最大値はOCR1A
 */
 
 // タイマ1を使用
 #include <avr/io.h>
 
 int main()
 {
    // 制御レジスタA
    TCCR1A = 0b10000010;  // 10 : コンペアマッチAでLOW, 10 : 高速PWM動作
    // 制御レジスタB
    TCCR1B = 0b00011001;  // 11 : 高速PWM動作, 001 : 分周なし
 
    // 最大値
    ICR1 = 64999;  // 0から数える(全体時間は65[ms])
    // 0.000001 * 65000 : 65[ms]
 
    // HIGHの時間(クロック数)
    OCR1A = 32499;  // 0から数える(High時間は32.5[ms])
    // 0.000001 * 32500 : 32.5[ms]
    // OCR1AはPB1ピン
 
    DDRB = 0b11111110;  // PB0のみ入力 
    PORTB = 0b00000001; // PB0をプルアップ
 
    while(1)
    {
       if(bit_is_clear(PINB, PB0))
       {  // PB0が0(オン)の場合
          OCR1A = 32499;  // PB1 HIGH時間 32.5[ms]
          // OCR1Aの値を変えることで、LEDが光る時間を調節できる
       }
       else
       {
          OCR1A = 0;  // PB1 HIGH時間 0[ms]
       }
    }
 
    return 0;
 }


PWMの設定

まず、TCCR1AとTCCR1Bで、タイマ1を使用するための設定を行う。

次に、ICR1で、タイマ(カウンタ)のTOP値(上記では、ICR1 = 64999)を決める。0からカウントするので、65000回カウントアップされる。
1[MHz](1[us])なので、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(スイッチがオンの状態)の時、trueとなる。

スイッチがオンの状態で、PWM出力波形のHIGH時間を32.5[ms]にする。
スイッチがオフの状態で、HIGH時間を0[ms]にする。

作成した回路

ここでは、スイッチを押下するとPWM制御により、LEDが点滅する回路を以下に記載する。

ATmega328 Timer PWM 2.jpg



サンプルコード2

タイマ割り込みでデューティ比を変化せるプログラムを以下に記述する。
PWMの周期を2048[us]、12.5[ms]ごとに割り込みを発生させて、デューティ比を0.78と0.04に切り替える。

 #include <avr/io.h>
 #include <util/delay.h>
 #include <avr/interrupt.h>
 
 unsigned char i;
 
 // タイマ2 コンペアマッチA割り込み
 ISR(TIMER2_COMPA_vect)
 {
    if(i == 255)
    {
       i = 0;
    }
    else
    {
       i++;
    }
 
    if(i % 2 == 0)
    {
       OCR0A = 10;
    }
    else
    {
       OCR0A = 200;
    }
 }
 
 int main()
 {
    // タイマ0
    TCCR0A = 0b10100011;  // 1010 = OCR0A出力とOCR1A出力, 011 = 高速PWM(TOP値 = 0xFF)
    TCCR0B = 0b00000010;  // 010 = 分周比 : 8(PWM周期 = 1 / (1,000,000[Hz] / 8分周) * 256 = 2048[us])
 
    // タイマ2(割り込み用 : コンペアマッチAで割り込み開始)
    TCCR2A = 0b00000010;  // 0000 = ピン出力なし, 010 = CTC(TOP値 = OCR2A)
    TCCR2B = 0b00000101;  // 101 = 分周比 : 128
    OCR2A  = 97;          // 12.5[ms]ごとに割り込み(1 / (1,000,000[Hz] / 128分周) * 98)
    TIMSK2 = 0b0000010;	  // コンペアマッチAの割り込みを有効

    // 方向レジスタの設定
    DDRB  = 0xFF;  // PORTB2を出力
    DDRD  = 0xFF;  // PORTD5を出力
 
    // 割り込み許可
    sei();
 
    while(1)
    {
       ;
    }
 }