なんだか当たり前のことを書いてしまったようなタイトルだけど、「analogWrite()はアナログ値が出てくるのではなくてPWMのデューティを指定するものなので、それを実測してみよう」という実験。

基礎実験(デューティ50%)
まず、analogWrite()のマニュアルはこちら。
analogWrite()の引数でデューティ比を指定する。0で0%、255で100%。
では、127を指定して50%デューティで出力してみる。Arduinoの3番ピンに出力し、そのまま観測(無負荷)。

周波数は490Hz(マニュアル通り)、デューティは49.8:50.2。ま、こんなものかな。
なお、ボードはArduino UNO互換のSeeeduino V4.2。
アナログ値に変換(CRフィルタ)
PWM出力をアナログ値に変換するにはCRフィルタ(LPF)を通すのが簡単。世の中には便利なものがあって、オンラインでPWMをCRフィルタに通したときのシミュレーションが行える。

これに条件を設定して計算してみる。Arduinoの出力を使うので、PWM信号は490Hz、5V(デューティは50%とする)。CR LPFの定数は100Ω、100μFでやってみる。

収束電圧は2.5V、リプルは約255mVpp。
では、実測してみる。CH1がPWM出力、CH2がCRフィルタの出力(無負荷)。なお、Arduinoの電源はDC入力から(USB供給ではない)。

CH2の平均値は2.48V、リプルはカーソルで上下を捉えると720mV。シミュレーション値より大きい。現実はシミュレーションよりは悪くなるってことだろう。
Cを10倍のの1000μFにすると、リプルはほとんど見えなくなる(Rは100Ωのまま)。

リプルを拡大(オシロのプローブをAC結合に)。カーソルで拾って44mV。

デューティ比とアナログ値
続いて、デューティ比を変えて、CRフィルタを通したときのアナログ値を見てみる。CRフィルタは、100Ω、1000μF。無負荷で。
analogWrite(3, 10)
3は出力ピン番号。10はデューティ比(255で100%)。
計算上は3.9%で0.195V。実測で160mV。

analogWrite(3, 30)
計算上は11.8%で0.59V。実測で559mV。

analogWrite(3, 63)
計算上は24.7%で1.235V。実測で1.228V。

analogWrite(3, 127)
計算上は49.8%で2.490V。実測で2.475V。

analogWrite(3, 191)
計算上は、74.9%で3.745V。実測で3.720V。

こうやって見比べていくと、デューティ比を上げるとPWM出力のLowレベルがじわじわ上ってくるみたい。
analogWrite(3, 255)
計算上は100%で5.0V。実測で4.96V。

なお、このときのCH1(Arduinoの出力端子側)は下のように、5.04V。無負荷とはいえ、CRフィルタを通すと現実的には多少のロスがあるってことかな?まぁ、オシロのプローブが負荷といえば負荷だけど。

負荷による出力電圧の変動
ここまでの測定は無負荷の場合。続いて、負荷を接続したときの様子を見ていく。出力電流の増加に伴って出力電圧は落ちていく。下はデータシートから引用したグラフ。20mA流すと0.5V程度落ちることがわかる。

ATmega328Pの端子出力電流の絶対定格は各ピン40.0mA。複数のピンの合計では150mA(引込みでは100mA)。詳細はデータシートを確認。
ここでの実験では、CRフィルタ(100Ω、1000μF)を通した状態での出力電圧を見ていく。負荷は単に抵抗をつなぐ。PWM出力のデューティ比は50%でやってみる(無負荷状態での出力電圧は、上の結果によると2.475V)。
10kΩ
出力電圧2.421V。

4.7kΩ
出力電圧2.400V。

1kΩ
出力電圧2.198V。

470Ω
出力電圧1.917V。

100Ω
出力電圧1.086V。

負荷が100Ωになると、CRフィルタの100Ωと1:1になるので、それだけで出力電圧は1/2になる。ATmega328Pからの出力電圧も下がっているはずなので(CH1のHighレベルが低下していることも観測できている)、ずいぶん低い電圧になってしまう。
CRフィルタのRを小さくすればそこでの電圧降下は小さく抑えられるが、当然ながらリプルは増加する(Cを増やせばリプルを低減できるけど)。
PWMの周波数による違い
Arduino UNOでは3、5、6、9、10、11ピンがPWN出力に対応している。3ピンなどはこれまで見てきたように周波数は約490Hzだけど、5ピンと6ピンは二倍の約980Hzが出力される。
3ピンは、これまで見てきたように、490Hzで、50%、無負荷の場合はこのような感じ。

5ピンでは約980Hzで、リプルは小さくなる。

まとめ
- ArduinoのanalogWrite()の出力はPWM。アナログ電圧を得たいのなら、CRフィルタを通す。
- CもRも大きい方がリプルは小さくなる
- ただし、Rによる電圧降下に要注意。
- 出力電流が多めだと電圧が下がる(ATmega328Pからの供給電圧も、CRフィルタによる電圧降下も)。
- デューティ比にできるだけ合わせた出力電圧(計算通りのの出力電圧)を得たいなら、負荷は軽く抑える。
- CRフィルタのRは小さくCは大きく。
- 負荷には直接電流を供給せずに、ドライバをかませる。
- PWMの周波数が高いほうが、リプルの点では有利。
【おまけのシミュレーション】
1Ω・1000μFのフィルタだと、リプルというよりほぼ三角波(490Hz・50%)。

コメント