ATmega328でのタイマとPWMの使用方法
概要
タイマには、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出力は実線(赤)とする)
タイマ(カウンタ)は、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タイマ)の図だが、他のタイマも似たものとなる。
下記にタイマと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が点滅する回路を以下に記載する。
サンプルコード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)
{
;
}
}