« Arduino IDE アップデートしたらMsTimer2が使えなくなった・・・ | トップページ | 割り込みで処理させるwordデータの扱い »

2019年3月22日 (金)

Arduinoのアナログ基準電圧入力

Arduinoの
Arduino IDE アップデートしたらMsTimer2が使えなくなった・・・をあれこれ調べていて・・・
こんなページを発見。
  ※MsTimer2とは関係なくって、アナログ入力についてです。
この中の、
参照電圧について (要注意! きちんと守らないと故障の恐れ!)
について、ちょいと私の意見を・・・

Arduinoのアナログ・リファレンス電圧設定についてを追いかけてみます。
※状況
・調べたのはArduino-UNO。(だけ)
  ソースファイルを見たり、現物の信号をオシロで見たり・・・
・ブートローダ起動での状態:
  AREFは入力状態。
  つまり、外部基準電圧を受け入れる状態。
    analogReference(EXTERNAL)と同じ状態。
    INTERNALやDEFAULTではない。
  ブートローダのソースを見ると、A/Dのマルチプレクサ
  はリセット状態のままでリファレンス電圧入力の設定も
  外部基準電圧の状態。
・ユーザープログラムの起動:
  A/Dのクロック設定とADEN(A/D変換許可)を初期化し
  ている。
  しかし、マルチプレクサ切り替えと基準電圧の設定は
  手を付けていない。
・analogReference(INTERNAL)、analogReference(DEFAULT)
 の設定:
  内部基準電圧あるいはAVCCに切り替えても、A/D入力:
  「analogRead() 」を実行するまでは「EXTERNAL」のまま。
  analogReference()の実行だけでは、基準電圧の切り替えは
  行われない。
  analogRead()実行ではじめてanalogReference()の設定が
  有効になる。
・だもんで:
  外部から基準電圧を供給しても問題なし。
  衝突は発生しない。
この中↑の、記述で・・・
■Arduino Reference:analogReference()
Notes and Warnings
 :
Alternatively, you can connect the external reference voltage
to the AREF pin through a 5K resistor, allowing you to switch
between external and internal reference voltages.
Note that the resistor will alter the voltage that gets used
as the reference because there is an internal 32K resistor on
the AREF pin.
The two act as a voltage divider, so, for example, 2.5V
applied through the resistor will yield
  2.5 * 32 / (32 + 5) = ~2.2V at the AREF pin.
↑の概略・・・
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
外部基準電圧とAREFピンの間に5kΩの抵抗を入れておけば、
内外の切り替えの間の衝突が避けられる。
ところが、AREF入力内部の入力抵抗は32kΩ。
だもんで、5kΩの抵抗を入れるとドロップが生じて、2.5Vの
基準電圧だと実質はざっと2.2Vになる。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
これ、入力抵抗を32kΩと決め打ちして数値を出していますが、
そんなうまいことはいきません。
というか、Arduino(UNOでしか確かめてませんが)では、
ブートローダーの処理とユーザープログラムの初期化処理を
見る限り、AREFと外部基準電圧出力が衝突する心配はありま
せん。
抵抗を入れると、せっかくの外部基準電圧の精度が落ちてしま
います。
直列抵抗無しでOKというのが、私の結論です。
そして、analogReference()を設定した直後に、ダミーで
analogRead()を1回実行しておくことで、基準電圧の
切り替えがそのタイミングで行われて、以降のA/D変換が
安定するかと考えます。
※補足
アナログ入力を処理しているのが「wiring_analog.c」。
このファイルを見ると・・・
uint8_t analog_reference = DEFAULT;  ←初期値はDEFAULTだけど
                     変数に値を入れているだけで
                     A/Dのハードは操作していない。
void analogReference(uint8_t mode)   ←基準電圧区分を設定する関数
{
// can't actually set the register here because the default setting
// will connect AVCC and the AREF pin, which would cause a short if
// there's something connected to AREF.
  analog_reference = mode;       ←ここでも変数を設定しているだけ。
}
設定された「analog_referenc」をAVRマイコンのA/D変換レジスタ(ADMUX)
に書き込むのは「int analogRead(uint8_t pin)」 関数。
マルチプレクサの入力ch設定とともにADMUXに書き込まれる。
これが実行されるまでAREFピンはリセット状態のまま。
※さらに
実際にA/D変換しているところ・・・
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = (analog_reference << 4) | (pin & 0x07);  ←AREFピンとマルチプレクサ確定
#else
  ADMUX = (analog_reference << 6) | (pin & 0x07);
#endif
#endif
// without a delay, we seem to read from the wrong channel  ←★注目!
// delay(1);
#if defined(ADCSRA) && defined(ADCL)
// start the conversion
  sbi(ADCSRA, ADSC);      ←A/D開始
// ADSC is cleared when the conversion finishes
  while (bit_is_set(ADCSRA, ADSC));  ←変換終了待ち
  :
  low = ADCL;       ←10bitデータ読みだし
  high = ADCH;
  :
こんな流れ。
で、★注目のところに注目。
// delay(1); をコメントアウトしてます。
AREFとマルチプレクサを切り替えてすぐにA/D変換しちゃってる。
ほんとは、切り替え安定待ち時間が欲しい所です。

※記事へのコメント書き込みアドレスをメモ
※追記
古いバージョンのArduino-ソースでどうなっているかを追跡してみました。
ここ → Arduino - OldSoftwareReleases から、まず「1.0」をダウンロード。
関係するファイル。
まずは、ブートローダーですがこれはA/D関連レジスタを操作していません。
で、A/D変換に関係するのは以下の二つのファイル。
・wiring.c
  ADCのクロックを設定するADCSRAを操作しているがADMUXは触らず。
  AREF入力はリセット時のままで外部入力。
・wiring_analog.c
   $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $ という日付。
  ↑で説明したのと同じ処理になっています。
  つまり、外部基準入力時の注意を守る限り「衝突」は発生しません。
そして、もっと古い「0013」を見ても、基本の処理は1.0、つまり現行の
ソフトと同じです。

 

★このトラブルの発端(原因の推測)、
  setup内でanalogReference(EXTERNAL)を設定しないまま、
  analogRead()を実行したのじゃないかと・・・
analog_reference = DEFAULT;が初期値ですんで、
初回のanalogRead()の実行で、A/Dのch指定とともにADMUXの書き込みが
行われた瞬間にAREFピン(AVCCになる)と外部基準電圧ICの出力との短絡が
発生します。
これが「短絡するぞ」の原因じゃないかと考えます。

 

※さらに追記

上の方に記した
■Arduino Reference:analogReference()
  Notes and Warnings
「:」で省略した部分に大事なことが書かれてます。
     ※5kΩや32kΩに目が奪われちゃって・・・

~~~~~~~~~~~~~~~~~~~~~~~~~~
After changing the analog reference, the first
few readings from analogRead() may not be accurate.
~~~~~~~~~~~~~~~~~~~~~~~~~~

「AREFを変えた後の何回かのanalogRead()は不正確かも。」

これ、外部に基準電圧をつなぐとなれば、
analogReference(EXTERNAL)の実行はsetup内で1回だけ。
何度も変えるものじゃありません。

そして、

~~~~~~~~~~~~~~~~~~~~~~~~~~
Don’t use anything less than 0V or more than 5V
for external reference voltage on the AREF pin!
~~~~~~~~~~~~~~~~~~~~~~~~~~

「AREFピンには0V未満あるいは5V越えの電圧を加えるな。」
  ※5VというよりAVCC電圧か。Arduinoなら5Vだけど。

~~~~~~~~~~~~~~~~~~~~~~~~~~
If you’re using an external reference on the
AREF pin, you must set the analog reference to
EXTERNAL before calling analogRead().
~~~~~~~~~~~~~~~~~~~~~~~~~~

「AREFピンに外部基準電圧をつなぐ場合は、analogRead()
 実行前にEXTERNALに設定せよ。」
これが重要なわけです。

~~~~~~~~~~~~~~~~~~~~~~~~~~
Otherwise, you will short together the active
reference voltage (internally generated)and the
AREF pin, possibly damaging the microcontroller on
your Arduino board.
~~~~~~~~~~~~~~~~~~~~~~~~~~

「さもないと、内部生成された基準電圧とAREFピンが
 ショートでArduinoに乗ったマイコンがつぶれるかも。」

そこから短絡防止のための姑息な手段の「5kΩ、32kΩ」の話がくるからややこしい。

 

|

« Arduino IDE アップデートしたらMsTimer2が使えなくなった・・・ | トップページ | 割り込みで処理させるwordデータの扱い »

電子工作」カテゴリの記事

コメント

こんにちは。AREFのご指摘ありがとうございます。

あのページを書いたのはArduino Duemilanoveのmega168のころだったので、最新ハードでの回路や、ブートローダ、標準ライブラリなどの中身が進化している可能性があるとおもうので、現在のUno rev3などでは当てはまらなくなっているかも知れませんね。

当時から、CPUチップ内部でショートする可能性が…という話は、公式サイトでも会話がされていたので、すでに何らかの改善が行われているかもしれません。

ひとつ気になるのは、現在のADC周りの内部処理を追った結果、analogReference(EXTERNAL)に設定されているというお話です。
もし、参照電圧がADCの入力処理を行う時点でも「EXTERNAL」のままだと、参照電圧が直流的にはオープンのままになってしまう気がします。
(Duemilanove、Uno rev3の回路を見直してみた感じでは、CPUのAREFピンとGNDの間に0.1uFのコンデンサが繋がっているだけのようなので)

ADCのコンバート開始時に内部参照を使っているとすると、その電圧はAVccから持ってきているように思うのですが、するとやはりその時点で内部でショートするような気がします。

5kΩで保護するのは、内部抵抗との兼ね合いになるので、誤差が出そうでどうかなぁ、と当時思っていたんですが、たしか当時は内部の32kΩと外付けの5kΩで分圧って言う表記自体が無かったと記憶しています。多分、あとから追記されたのかなという気がします。やはり、5kΩ抵抗をつけるだけでは、ある程度の範囲で誤差が散らばりそうですね。

投稿: nekosan | 2019年3月23日 (土) 21時52分

えっと。
「analogReference」を使って基準電圧入力の状態を
積極的に設定しない限り、変数「analog_reference」
は「DEFAULT」のまま。
つまり、AVCCにつなぐぞ、です。
しかし、リセット起動後、ハード的にすぐにはつなぎません。


つまり・・・
「analogRead」を実行するまでは、AREFは
「EXTERNAL」(外部基準電圧入力)のままを保持。
だもんで、「analogRead」実行までは、ハード的な
短絡の危険性は無し。


しかし・・・
「analog_reference」で基準電圧の状態を設定せず
に「analogRead」でA/D値を読み取ると、
その時の「基準電圧=AREF」の接続先は「AVCC」。
AVCC=5Vが基準電圧となってしまいます。
この場合、外部基準電圧をつないだらあきません。
短絡が発生します。


だもんで・・・
外部基準電圧をつないでいるのなら・・・
setup内で
「analogReference(EXTERNAL)」を必ず実行しな
くちゃなりません。
これで、変数analog_reference が EXTERNALに変わり
その後の「analogRead」の処理では、外部基準電圧で
A/D変換が実行されます。

ということで・・・
外部基準電圧を使い、A/D入力処理を「analogRead」で行う
のなら、必ずこの手順を経ないと短絡が発生しちゃいます。


昔々のArduinoでの処理、それがどうなってたのかの
追跡はできていません。

投稿: 居酒屋ガレージ店主(JH3DBO) | 2019年3月23日 (土) 23時35分

時系列で動作を説明していただいて、どのようにショートを避けられるかが解りました。ありがとうございます。

「analogReference(EXTERNAL)」で内部変数の設定を変更しておきつつ、実際にADCを動かすときに実際のSFRを変更して、参照電圧を切替えているという手間を考えると、やはりどこかのタイミングで、このように処理内容を変更した匂いがしますね。

そして、5kΩの抵抗を…というのも、もう必要なさそうですね。

投稿: nekosan | 2019年3月25日 (月) 00時58分

Arduinoの古いソースが保存されていたので、どんなふうに変遷があったのか確かめてみました。
結果・・・ 手順を守る限り短絡は発生しません。(昔から)
おそらく・・・ 推測を記事に追記しておきました。

投稿: 居酒屋ガレージ店主(JH3DBO) | 2019年3月25日 (月) 09時11分

AREFに出てくる内部の基準電圧(Arduino-UNOなら1.1V)を外に取り出す方法を模索したことがあります。

http://act-ele.c.ooco.jp/blogroot/igarage/article/3352.html

http://act-ele.c.ooco.jp/blogroot/igarage/article/3366.html

投稿: 居酒屋ガレージ店主(JH3DBO) | 2019年3月25日 (月) 11時06分

コメントを書く



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




« Arduino IDE アップデートしたらMsTimer2が使えなくなった・・・ | トップページ | 割り込みで処理させるwordデータの扱い »