概要
analogWrite()は、PWM出力を行う関数です。analogWrite()のリファレンスはこちらを参照してください。PWMの簡単な説明はこちらを参照してください。
ATmega328Pは、PWM出力に利用できるタイマ/カウンタを3個(タイマ/カウンタ0から2の3個)持っています。それぞれのタイマ/カウンタが2個の比較出力器を持っているため、6本のピンでPWM出力を行うことができます。このため、Arduinoでも6本のピンからPWM出力を行うことができます。
3個のタイマ/カウンタのうち2個(タイマ/カウンタ0とタイマ/カウンタ2)は8ビット、1個(タイマ/カウンタ1)は16ビットです。
PWMの出力周波数の設定はinit()で行っています。analogWrite()では、PWM出力の開始とデューティ比の設定を行います。これらの設定はタイマ関連のレジスタを操作することで実現しています。
タイマ/カウンタ0
タイマ/カウンタ0は8ビットのタイマ/カウンタで、TCCR0AとTCCR0B、TCNT0、OCR0A、OCR0B、TIMSK0、TIFR0という7個のレジスタで制御します。
タイマ/カウンタ0は、Arduino Unoのデジタルピンの6番(OC0A)とデジタルピンの5番(OC0B)のPWM出力を制御します。
TCCR0A、TCCR0B
TCCR0A(タイマ/カウンタ0制御レジスタA)とTCCR0B(タイマ/カウンタ0制御レジスタB)は、PWMの動作を制御します。
TCCR0A
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | COM0A1 | COM0A0 | COM0B1 | COM0B0 | - | - | WGM01 | WGM00 |
TCCR0B
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | FOC0A | FOC0B | - | - | WGM02 | CS02 | CS01 | CS00 |
上記の、WGM02とWGM01、WGM00は生成する波形を制御するビットです。3つのビットの組み合わせで意味が変わります。
Mode | WGM02 | WGM01 | WGM00 | 意味 |
---|---|---|---|---|
0 | 0 | 0 | 0 | 通常 |
1 | 0 | 0 | 1 | PWM、Phase Correct |
2 | 0 | 1 | 0 | CTC |
3 | 0 | 1 | 1 | Fast PWM |
4 | 1 | 0 | 0 | 予約 |
5 | 1 | 0 | 1 | PWM、Phase Correct |
6 | 1 | 1 | 0 | 予約 |
7 | 1 | 1 | 1 | Fast PWM |
Arduino Unoでは、init()の中で、WMG01とWGM00とを1に設定しています。このため、タイマ/カウンタ0は、モード3のFast PWMで動作します。モード3のFast PWMは、カウンタを0から255までインクリメントしていき、0に戻るまでが一周期です。モード7のFast PWMでは、カウンタを0からOCR0Aに設定した値までインクリメントし、0に戻るまでが1周期です。
COM0A1とCOM0A0は、デジタルピンの6番のPWMの制御を行います。Fast PWMモードの場合の動作は以下の通りです。
COM0A1 | COM0A0 | 意味 |
---|---|---|
0 | 0 | 標準操作(切断) |
0 | 1 | WGM02が0のときは、標準操作(切断)、WGM02が1のときは、比較一致で出力を反転。 |
1 | 0 | タイマとOCR0Aとの比較一致でLOW、タイマが0になるとHIGH。 |
1 | 1 | タイマとOCR0Aとの比較一致でHIGH、タイマが0になるとLOW。 |
Arduino Unoでは、COM0A0は0です。analogWrite()で、COM0A1を1にします。
COM0B1とCOM0B0は、デジタルピンの5番のPWMの制御を行います。Fast PWMモードの場合の動作は以下の通りです。
COM0B1 | COM0B0 | 意味 |
---|---|---|
0 | 0 | 標準操作(切断) |
0 | 1 | 予約 |
1 | 0 | タイマとOCR0Bとの比較一致でLOW、タイマが0になるとHIGH。 |
1 | 1 | タイマとOCR0Bとの比較一致でHIGH、タイマが0になるとLOW。 |
Arduino Unoでは、COM0B0は0です。analogWrite()で、COM0B1を1にします。
FOC0AとFOC0Bは、Arduino Unoでは利用していないようです。
CS02とCS01、CS00はクロックを選択します。
CS02 | CS01 | CS00 | 意味 |
---|---|---|---|
0 | 0 | 0 | クロックなし |
0 | 0 | 1 | 分周比1 |
0 | 1 | 0 | 分周比8 |
0 | 1 | 1 | 分周比64 |
1 | 0 | 0 | 分周比256 |
1 | 0 | 1 | 分周比1024 |
1 | 1 | 0 | 外部クロック。立下りでオン。 |
1 | 1 | 1 | 外部クロック。立ち上がりでオン。 |
Arduino Unoでは、init()でCS01とCS00を1に設定しています。このため、分周比は64です。
Fast PWMの周波数fは、以下の式で求めます。
$$f = クロック周波数 / (分周比 \times 256)$$
Arduino Unoでは、クロック周波数が16MHz、分周比は64なので、5番ピンと6番ピンに出力するPWMの周波数は、
$$ 16000000 / (64 \times 256) = 976.5625 Hz $$
です。
256で割っているのは、カウンタが0から255までいって、その後0にリセットするので、全体で256クロックかかるからだと思います。
TCNT0
TCNT0は、8ビットのレジスタで、タイマ/カウンタです。この値が、1クロックごとに1インクリメントされます。255になると0に戻ります。
OCR0A、OCR0B
OCR0AとOCR0Bは8ビットの比較レジスタです。Fast PWMでは、TCNT0とOCR0A、OCR0Bの値を比較し、一致すると出力がLOWになります。TCNT0が0になると出力がHIGHになります。
OCR0Aが6番ピン用、OCR0Bが5番ピン用です。analogWrite()で指定したデューティ比を保持します。以下に動作の概念図を示します。

TIMSK0
TIMSK0は、割り込みマスクを制御します。
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | - | - | - | - | - | OCIE0B | OCIE0A | TOIE0 |
OCIE0B、OCIE0Aはタイマ/カウンタ0の比較割り込みを制御します。analogWrite()では利用していません。
TOIE0は、タイマ/カウンタ0オーバーフロー割り込み許可です。init()でこのフラグを設定しています。analogWrite()ではなく、millis()やmicros()のために利用します。
TIFR0
TIFR0はタイマ/カウンタ0割り込みフラグレジスタです。Arduinoでは特に設定は行っていないようです。
タイマ/カウンタ1
タイマ/カウンタ1は、16ビットのタイマ/カウンタで、TCCR1AとTCCR1B、TCCR1C、TCNT1H・TCNT1L、OCR1AH・OCR1AL、OCR1BH・OCR1BL、ICR1H・ICR1L、TIMSK1、TIFR1というレジスタで制御します。
タイマ/カウンタ1は、Arduino Unoのデジタルピンの9番(OC1A)とデジタルピンの10番(OC1B)のPWM出力を制御します。
TCCR1A、TCCR1B、TCCR1C
TCCR1A(タイマ/カウンタ1制御レジスタA)とTCCR1B(タイマ/カウンタ1制御レジスタB)/TCCR1C(タイマ/カウンタ1制御レジスタC)は、PWMの動作を制御します。
TCCR1A
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | COM1A1 | COM1A0 | COM1B1 | COM1B0 | - | - | WGM11 | WGM10 |
TCCR1B
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | ICNC1 | ICES1 | - | WGM13 | WGM12 | CS12 | CS11 | CS10 |
TCCR1C
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | FOC1A | FOC1B | - | - | - | - | - | - |
WGM13とWGM12とWGM11、WGM10は生成する波形を制御するビットです。4つのビットの組み合わせで意味が変わります。
Mode | WGM13 | WGM12 | WGM11 | WGM10 | 意味 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 通常 |
1 | 0 | 0 | 0 | 1 | PWM、Phase Correct, 8bit |
2 | 0 | 0 | 1 | 0 | PWM、Phase Correct, 9bit |
3 | 0 | 0 | 1 | 1 | PWM、Phase Correct, 10bit |
4 | 0 | 1 | 0 | 0 | CTC |
5 | 0 | 1 | 0 | 1 | Fast PWM, 8bit |
6 | 0 | 1 | 1 | 0 | Fast PWM, 9bit |
7 | 0 | 1 | 1 | 1 | Fast PWM, 10bit |
8 | 1 | 0 | 0 | 0 | PWM, Phase and Frequency Correct |
9 | 1 | 0 | 0 | 1 | PWM, Phase and Frequency Correct |
10 | 1 | 0 | 1 | 0 | PWM, Phase Correct |
11 | 1 | 0 | 1 | 1 | PWM, Phase Correct |
12 | 1 | 1 | 0 | 0 | CTC |
13 | 1 | 1 | 0 | 1 | 予約 |
14 | 1 | 1 | 1 | 0 | Fast PWM |
15 | 1 | 1 | 1 | 1 | Fast PWM |
Arduino Unoでは、init()の中で、WM10を1に設定しています。このため、タイマ/カウンタ1は、モード1のPWM、Phase Correct, 8bitで動作します。このモードでは、カウンタを0から255までインクリメントしていき、その後、0までデクリメントしていきます。
COM1A1とCOM1A0は、デジタルピンの9番のPWMの制御を行います。COM1B1とCOM1B0は、デジタルピンの10番のPWMの制御を行います。モード1のPhase Correct PWMモードの場合の動作は以下の通りです。
COM1A1/COM1B1 | COM1A0/COM1B0 | 意味 |
---|---|---|
0 | 0 | 標準操作(切断) |
0 | 1 | 標準操作(切断) |
1 | 0 | タイマとOCR1A/OCR1Bとの比較一致で、加算しているときにLOW、減算しているときにHIGH。 |
1 | 1 | タイマとOCR1A/OCR1Bとの比較一致でHIGH、タイマが0になるとLOW。 |
Arduino Unoでは、COM1A0/COM1B0は0です。analogWrite()で、COM1A1/COM1B1を1にします。
ICNC1とICES1はArduino Unoでは操作していません。
CS12とCS11、CS10はクロックを選択します。
CS12 | CS11 | CS10 | 意味 |
---|---|---|---|
0 | 0 | 0 | クロックなし |
0 | 0 | 1 | 分周比1 |
0 | 1 | 0 | 分周比8 |
0 | 1 | 1 | 分周比64 |
1 | 0 | 0 | 分周比256 |
1 | 0 | 1 | 分周比1024 |
1 | 1 | 0 | 外部クロック。立下りでオン。 |
1 | 1 | 1 | 外部クロック。立ち上がりでオン。 |
Arduino Unoでは、init()でCS11とCS10を1に設定しています。このため、分周比は64です。
Phase Correct PWMの周波数fは、以下の式で求めます。
$$ f = クロック周波数 / (分周比 \times TOP \times 2) $$
Phase Correct PWM 8bitの場合のTOPは255です。また、Arduino Unoでは、クロック周波数が16MHz、分周比は64なので、9番ピンと10番ピンに出力するPWMの周波数は、
$$ 16000000 / (64 \times 255 \times 2) = 490.1961 Hz $$
です。
カウンタを0から255まで加算し、その後、0まで減算していくため、255 * 2で割っていると思います。
FOC1AとFOC1Bは未使用です。
TCNT1H・TCNT1L
TCNT1HとTCNT1Lは、2つ合わせて、16ビットのタイマカウンタです。ただし、Arduino Unoで利用する8ビットのPhase Correct PWMでは0から255までインクリメントしたら、0までデクリメントしていきます。
OCR1AH・OCR1AL、OCR1BH・OCR1BL
OCR1AとOCR1Bは、16ビットの比較レジスタです。Phase Correct PWMでは、TCNT1とOCR1A、OCR1Bの値を比較し、TCNT1が加算中に一致すると出力がLOWになり、減算中に一致すると出力がHIGHになります。
OCR1Aが9番ピン用、OCR1Bが10番ピン用です。analogWrite()で指定したデューティ比を保持します。以下に動作の概念図を示します。

ICR1H・ICR1L、TIMSK1、TIFR1
ICR1H・ICR1L、TIMSK1、TIFR1はanalogWrite()では利用していないようです。
タイマ/カウンタ2
タイマ/カウンタ2は、8ビットのタイマ/カウンタで、TCCR2AとTCCR2B、TCNT2、OCR2A、OCR2B、TIMSK2、TIFR2、ASSR、GTCCRというレジスタで制御します。
タイマ/カウンタ2は、Arduino Unoのデジタルピンの3番(OC2B)とデジタルピンの11番(OC2A)のPWM出力を制御します。
TCCR2A、TCCR2B
TCCR2A(タイマ/カウンタ2制御レジスタA)とTCCR2B(タイマ/カウンタ2制御レジスタB)は、PWMの動作を制御します。
TCCR2A
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | COM2A1 | COM2A0 | COM2B1 | COM2B0 | - | - | WGM21 | WGM20 |
TCCR2B
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
名称 | FOC2A | FOC2B | - | - | WGM22 | CS22 | CS21 | CS20 |
WGM22とWGM21、WGM20は生成する波形を制御するビットです。3つのビットの組み合わせで意味が変わります。
Mode | WGM22 | WGM21 | WGM20 | 意味 |
---|---|---|---|---|
0 | 0 | 0 | 0 | 通常 |
1 | 0 | 0 | 1 | PWM、Phase Correct |
2 | 0 | 1 | 0 | CTC |
3 | 0 | 1 | 1 | Fast PWM |
4 | 1 | 0 | 0 | 予約 |
5 | 1 | 0 | 1 | PWM、Phase Correct |
6 | 1 | 1 | 0 | 予約 |
7 | 1 | 1 | 1 | Fast PWM |
Arduino Unoでは、init()の中で、WGM20を1に設定しています。このため、タイマ/カウンタ2は、モード1のPhase Correct PWMで動作します。モード1のPhase Correct PWMは、カウンタを0から255までインクリメントしていき、その後、0までデクリメントしていきます。
COM2A1とCOM2A0はデジタルピンの11番のPWMの制御を行ないます。Phase Correct PWMモードの場合の動作は以下の通りです。
COM2A1 | COM2A0 | 意味 |
---|---|---|
0 | 0 | 標準操作(切断) |
0 | 1 | 標準操作(切断) |
1 | 0 | タイマとOCR2Aとの比較一致で、加算しているときにLOW、減算しているときにHIGH。 |
1 | 1 | タイマとOCR2Aとの比較一致でHIGH、タイマが0になるとLOW。 |
Arduino Unoでは、COM2A0は0です。analogWrite()で、COM2A1を1にします。
COM2B1とCOM2B0はデジタルピンの3番のPWMの制御を行います。
COM2B1 | COM2B0 | 意味 |
---|---|---|
0 | 0 | 標準操作(切断) |
0 | 1 | 予約 |
1 | 0 | タイマとOCR2Bとの比較一致で、加算しているときにLOW、減算しているときにHIGH。 |
1 | 1 | タイマとOCR2Bとの比較一致でHIGH、タイマが0になるとLOW。 |
Arduino Unoでは、COM2B0は0です。analogWrite()で、COM2B1を1にします。
FOC2AとFOC2Bは、analogWrite()では利用していないようです。
CS22とCS21、CS20はクロックを選択します。
CS22 | CS21 | CS20 | 意味 |
---|---|---|---|
0 | 0 | 0 | クロックなし |
0 | 0 | 1 | 分周比1 |
0 | 1 | 0 | 分周比8 |
0 | 1 | 1 | 分周比32 |
1 | 0 | 0 | 分周比64 |
1 | 0 | 1 | 分周比128 |
1 | 1 | 0 | 分周比256 |
1 | 1 | 1 | 分周比1024 |
Arduino Unoでは、init()でCS22を1に設定しています。このため、分周比は64です。
Phase PWMの周波数fは、以下の式で求めます。
$$f = クロック周波数 / (分周比 \times 255 \times 2)$$
Arduino Unoでは、クロック周波数が16MHz、分周比は64なので、11番ピンと3番ピンに出力するPWMの周波数は、
$$16000000 / (64 \times 255 \times 2) = 490.1961 Hz $$
です。
TCNT2
TCNT2は、8ビットのレジスタで、タイマ/カウンタです。この値が、1クロックごとにインクリメントされます。255になると0になるまで1クロックごとにデクリメントされます。
OCR2A、OCR2B
OCR0AとOCR0Bは8ビットの比較レジスタです。Phase Correct PWMでは、TCNT2とOCR2A、OCR2Bの値を比較し、TCNT2が加算中に一致すると出力がLOWになり、減算中に一致すると出力がHIGHになります。
OCR2Aが11番ピン用、OCR2Bが3番ピン用です。analogWrite()で指定したデューティ比を保持します。
TIMSK2
TIMSK2は、割り込みマスクを制御します。analogWrite()では特に設定していないようです。tone()で利用します。
TIFR2
TIFR2はタイマ/カウンタ0割り込みフラグレジスタです。analogWrite()では特に設定は行っていないようです。
ソースコード
analogWrite()は、hardware/arduino/avr/ cores/arduino/wiring_analog.c に定義されています。以下に全ソースコードを示します。Arduino Unoの場合に適用される部分だけを抜粋しています。実際には#if によりさまざまなチップに対応しています。
|
|
入力はpinとvalで、それぞれuint8_t型とint型の変数です。出力はありません。
まず、pinMode()を使って、pinを出力モードにします。
|
|
次に、valが0のときと255のときは、digitalWrite()でそれぞれ、LOWとHIGHをpinに出力してこの関数は終了します。
|
|
valが0でも255でもない場合は、switch文を使って処理を分岐します。
|
|
digitalPinToTimer()は、デジタルピンを入力すると対応するタイマ名を返す関数です。
TIMER0A(5番ピン)の場合は、sbi()を使って、TCCR0AのCOM0A1ビットを1にします。sbi()は、第1引数で指定したアドレスの内容の第2引数ビットを1に設定するマクロです。その後、OCR0Aにvalを代入し、デューティ比を設定します。以降、各ピンに応じたTCCRnxのビットの設定と、OCRnxへのデューティ比の設定を行います。
|
|
PWM出力ができないピンを指定した場合は、valが128未満の場合はLOWを、128以上の場合はHIGHを出力します。
|
|
バージョン
Arduino AVR Boards 1.8.6
最終更新日
March 21, 2023