« Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMを使おう | トップページ | Arduino デューティー計測のためのインプットキャプチャータイミング »

2020年8月16日 (日)

Arduino UNOのPWM出力を(ちょっと精密に)確かめる

Arduino UNOが装備する、6つのPWM出力を確かめる
プログラムを書いてみました。
シリアルモニターでval値を入力するとその値(0~255)で
6つのPWMを出力します。

P11
※プログラム:ダウンロード - test_analog_wr1.c
(ファイルタイプを.cとしています)

現状、このようにATmega328Pが内蔵する3つのタイマーで
6つのPWM出力が得られます。

・タイマー0 OC0AとOC0B出力

8bit高速PWM動作でイニシャルされている。
val=0でL固定、255でH固定。
1でデューティ 2/256。 2でデューティ 3/256。
127でデューティ128/256。128でデューティ129/256。
254でデューティ255/256。
 ▼問題点
   val=1~254で欲しいデューティ値から1ずれる。

・タイマー1 OC1AとOC1B出力
・タイマー2 OC2AとOC2B出力

8bit位相基準PWM動作でイニシャルされている。
val=0でL固定、255でH固定。
1でデューティ 1/255。 2でデューティ 2/255。
127でデューティ127/255。128でデューティ128/255。
254でデューティ254/255。
 ▼問題点
   ベースが1/255なので、127あるいは128とセット
   してもデューティ50%が得られない。

■確認
タイマー1のインプットキャプチャー機能を使って、
ICP1に入力されたパルスのデューティー比と周波数を
計ってみました。

P12
プログラム:ダウンロード - duty_checker1.c
  (ファイルタイプを.cとしています)

1秒ごとにデューティ、周波数、H区間とL区間のパルス数
(Arduino unoの16MHzクロック数)をシリアル出力します。
   パルスが無ければ「No pulse」。
   ↑↓パルスが接近して割り込み処理が間に合わないと
   「Overlap pulse」と警告メッセージを出します。

Arduino基板を2枚用意して、PWM出力とICP1入力をつなぎ替えながら
↑の問題点を実際に見てみます。
  (ICPクロック同期の関係で1~2発のズレが出ます)

・タイマー0
 val=1
   0.78%  0.977kHz    128  16255
 val=2
   1.17%  0.977kHz    192  16191
 val=127
   50.00%  0.977kHz   8191   8192
 val=128
   50.39%  0.977kHz   8255   8128
 val=254
   99.61%  0.977kHz   16319    64

   このように、val値と実値が1/256ずれています。
   1/2デューティのつもりで128をセットすると129/256
   になってしまいます。
     ※もう一度言います。
        0.4%の誤差が勝手に発生するのです。

・タイマー1と2
 val=1
   0.39%  0.490kHz    128  32510
 val=2
   0.78%  0.490kHz    256  32382
 val=127
   49.80%  0.490kHz   16255  16383
 val=128
   50.20%  0.490kHz   16384  16255
 val=254
   99.61%  0.490kHz   32510   128

  1/255が設定単位で、1周期のベースが
  64*2*255=32640クロックです。
  そのため1/2デューティが設定できません。
  127でも128でも0.5/255ずれてしまいます。


●改善方法

・タイマー0
  前記事に書きましたように「反転動作」「255-val」と
  することで、val=0~255で正しいデューティー比
  得られます。
  また、val=0の時も0判定無しで0/256=L固定が得られます

  その確認
 val=1
   0.39%  0.977kHz    64  16319
 val=128
   50.00%  0.977kHz   8192   8192
 val=255
   99.61%  0.977kHz   16319    64

   ※プログラム例
    analogWrite( 5, val);    // PD5 OC0B
  のかわりに
    b = TCCR0A & 0b11001111;   // COM0B
    TCCR0A = b | 0b00110000;   // 反転出力
    OCR0B = 255 - val;       // top値255からの差で

・タイマー1、タイマー2
  残念ながら「8bit位相基準PWM動作」を使う限り
  改善できません
  タイマー0と同じように「8bit高速PWM動作」にイニシャルし
  直しでしょう。
  あるいは、タイマー1は「TOP値=ICR1による高速PWM動作」
  使えます。
  高分解能なPWMを得ることができますので、この利用をおすす
  めします。


※関連
2020年8月13日:Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMを使おう
2020年2月10日:ArduinoのanalogWrite 1/255なの?
2020年2月 4日:Arduinoのタイマー OCRレジスタは「n」じゃなく「n - 1」の値を設定せよ





|

« Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMを使おう | トップページ | Arduino デューティー計測のためのインプットキャプチャータイミング »

Arduino」カテゴリの記事

コメント

・2020年8月18日:Arduino デューティー計測のためのインプットキャプチャータイミング
http://igarage.cocolog-nifty.com/blog/2020/08/post-21a70b.html

投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年8月18日 (火) 11時22分

コメントを書く



(ウェブ上には掲載しません)




« Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMを使おう | トップページ | Arduino デューティー計測のためのインプットキャプチャータイミング »