2014年5月10日土曜日

Arduino PWM周波数の高周波化

ArduinoのPWM周波数を変更したいので調べてみました.
ATMELのマニュアルは大変参考になります
日本語ではgarretlabさんのanalogWrite()の項目が体系的にまとめられています.
基本的にはそちらを見ていただいた方がいいと思います.

以下は自分のための覚え書きです.
とにかく一度動かしたい方はこちら

前置き

ArduinoはPWM出力を持っていますが, この周波数は
5番, 6番Pinは977Hz, 9番,10番PINは490Hz, 3番,11番PINも490Hzです.
Arduinoの内部で3つの独立したタイマからPWM生成の設定をしており,それぞれ
5番と6番, 9番と10番, 3番と11番ピンに対応しています.

例えば
 analogWrite(NPIN,100);
でNPIN=5とした時の波形を図1, NPIN=9とした時の波形を図2に示します.
オシロが周波数を表示してくれてますが, 確かに976Hzと490Hzになっていることがわかります.
図1 5番PINから出力したPWM波形
図2 13番PINから出力したPWM波形
同じPWM端子ですが,この3系統は内部処理や設定が異なっていることがポイントと思います.
(PWM波形生成の設定が異なっていたり, 9, 10番ピンは16ビットカウンタだったりします)
このため少し話がごちゃごちゃします.
以下それぞれの設定項目についてマニュアル[1]参照ページを記入したので, 必要に応じて参照してください. (読みが違っていたらごめんなさい, お気づきの点はご指摘ください.)


5番,6番ピンはFAST PWMモードで動いているため
周波数f(Hz)はクロック周波数fc(Hz), 分周比rを使って
f=fc/(256*r)
とかけます[1: p. 102]. 
rはTCCR0Bの下位3ビットを使って指定して
1,8,64,256,1024の中から選びます.
イニシャルは64が設定されています.
クロック周波数は16MHzですので, PWM周波数は977Hzになります.
(注) なお, Arduinoは5, 6番ピンが使用しているカウンタをもとに時間を管理しています.
従って5, 6番ピンのPWM周波数をあげるとdelay()などの挙動が変わってきます.
たんにPWM周波数を向上させたい場合は5, 6番ピンの設定を変えないほうが無難です.

9,10番ピンは Phase Correct PWMモードで動いていて
周波数f(Hz)はクロック周波数fc(Hz), 分周比r, カウントビットTOPを使って
f=fc/(2*TOP*r)
とかけます[1: p. 130]. 
TOPはイニシャルで255です.
rはTCCR1Bの下位3ビットを使って指定して
1,8,64,256,1024の中から選びます
イニシャルは64が設定されています.
クロック周波数は16MHzですので, PWM周波数は409.2Hzになります.

3, 13番ピンは
周波数f(Hz)はクロック周波数fc(Hz), カウンタのビット数nと分周比rを使って
f=fc/(510*r)
とかけます[1: p. 153].

rはTCCR2Bの下位3ビットを使って指定して
1,8,32, 64,128,256,1024の中から選びます. イニシャルは64が設定されています.
クロック周波数は16MHzですので, PWM周波数は409.2Hzになります.


具体的な方法

やっと本題ですが, PWM周波数を高周波化したい時は, 分周比rを変更します
この変更はTCCR*B(*は5番, 6番ピンは0, 9番, 10番ピンは1, 3番, 13番ピンは2です)
の下位3ビットで行います.
それぞれにはCS*2, CS*1, CS*0と名前がついています(*は0~2で前述と同じ).

TCCR0B(5,6番ピン) については[1]の110ページ 表14-9を参照
r=1 は001
r=8 は010
r=64 は 011
r=256は 100
r=1024は 101
です.

例えば
 Serial.println(TCCR0B,BIN);
と現状の設定をシリアルモニタで確認すると
11と帰ってくると思います.

変更する場合のプログラム記述はsetup関数内で
setup(){
 TCCR0B &= B11111000;
 TCCR0B |= B00000010;// r=8の場合
}
と記述すればOKです.

TCCR1B(9,10番ピン)については[1]の137ページ 表15-5を参照
r=1 は001
r=8 は010
r=64 は 011
r=256は 100
r=1024は 101
です.

TCCR2B(3,11番ピン)については[1]の162ページ 表17-9を参照
r=1 は001
r=8 は010
r=32は011
r=64 は 100
r=128は101
r=256は 110
r=1024は 111
です.
前出の2つと割当が違うので注意が必要です.

最後に例として9ピンの周波数をかえてみます.
rを1として, 前述の式
f=fc/(2*TOP*r)
より31.37kHとなるはずです.

void setup(){
TCCR1B &= B11111000;
TCCR1B |= B00000001;//rを1に設定 fc/(2*255*1)Hzになる
pinMode(9, OUTPUT);
}
void loop(){
analogWrite(9,100);
}
と簡単なプログラムの結果を図3にのせます
図3 9番ピンで分周比を1とした場合
波形は1V程度のオーバーシュートが見えますが,
周波数は31.36kHzとほぼ想定通りの値になっています.

参考文献

[1] ATmega48PA/88PA/168PA/328Pマニュアル 

キーワード

Arduino PWM 周波数 高周波化

1 件のコメント:

大王怒(ダイオード) さんのコメント...

T1の設定を変えるとT2のPWM Freq.も変わるので注意が必要。

// T0 is used for mills timer in Arduino all time, Can not touch Timer0.
// T1 is used for Propo_Pulse_Width_Counting.
TIMSK1 = 0; // T1, no overflow interrupt
TCCR1A = 0; // T1, normal operation simple count-up timer mode
TCCR1B = 2; // T1 runs 1/8 clock(2MHz)

これでT2はメロメロ。