ATmarquinoでMhysicalna(身近な)コンピューティング 現状の把握と打算的対策 [ATmarquino Arduino]
結局前回まででは原因の解明ができなかった訳ですが、のりたんさんのアドバイスでより現状に近い原因を推定するに至りました。
ですが、私ものりたんさんもAVRのチップやボンディングの実際までは判らないので、これから述べる事はあくまでも仮定の話です。眉唾で読んでください。
まず共通インピーダンスの問題に付いて解説します。
AVRの内部では電源を別とするデジタルブロックとアナログブロックに別れているかと思われますが、GNDに関しては共通となっているのではないかと言う話です。図にその様子を描いて見ました。点線内部がAVRの中だと思ってください。
デジタルブロック側から流れる電流と、アナログブロック側から流れる電流が合わさって共通インピーダンスのRcに流れ込みますとそこで電圧((Id+Ia)×Rc)が発生します。
こうなるとアナログブロックは実際のGNDから共通インピーダンスで発生した電圧分浮いた状態になってしまい、LM35DZのGNDを基準としているVOUTが正確に測れなくなってしまいます。具体的にはアナログブロックはVOUT-((Id+Ia)×Rc)となって見える筈です。これが実際に入力された電圧より低く表示された理由であろうと言う話です。
せめてボンディングが別ならば!と言う話は、アナログブロックのGNDとデジタルブロックのGNDが別の端子として外部に出されていれば、アナログブロックは少なくともデジタル側の電流の影響は免れる事となるからです。
今回の温度計は7セグメントLEDを駆動する為に、ピークでは20mA程度の電流がデジタルブロックで流れます。
それがオフセットエラーを発生させている訳です。
じゃあせめてA/D変換中位は流す電流を減らしたら?。
コードを以下の様に変更してみました。全部掲載するのは面倒なので部分的に抽出したコードです。
つまりAD変換する直前にLEDを全部OFFとして電流を減らし、AD変換完了後は再びLEDをONしています。
これでやってみたところ入力に対して3mV程度低い値となりました。まだ完璧とは言えませんが継続的に電流を流し続けた場合よりは実際に近くなっています。
もちろんこの対策は表示にLEDを使っているからで、別のデバイスで同じ方法を使えるかどうかは判りません。
ですが、私ものりたんさんもAVRのチップやボンディングの実際までは判らないので、これから述べる事はあくまでも仮定の話です。眉唾で読んでください。
まず共通インピーダンスの問題に付いて解説します。
AVRの内部では電源を別とするデジタルブロックとアナログブロックに別れているかと思われますが、GNDに関しては共通となっているのではないかと言う話です。図にその様子を描いて見ました。点線内部がAVRの中だと思ってください。
デジタルブロック側から流れる電流と、アナログブロック側から流れる電流が合わさって共通インピーダンスのRcに流れ込みますとそこで電圧((Id+Ia)×Rc)が発生します。
こうなるとアナログブロックは実際のGNDから共通インピーダンスで発生した電圧分浮いた状態になってしまい、LM35DZのGNDを基準としているVOUTが正確に測れなくなってしまいます。具体的にはアナログブロックはVOUT-((Id+Ia)×Rc)となって見える筈です。これが実際に入力された電圧より低く表示された理由であろうと言う話です。
せめてボンディングが別ならば!と言う話は、アナログブロックのGNDとデジタルブロックのGNDが別の端子として外部に出されていれば、アナログブロックは少なくともデジタル側の電流の影響は免れる事となるからです。
今回の温度計は7セグメントLEDを駆動する為に、ピークでは20mA程度の電流がデジタルブロックで流れます。
それがオフセットエラーを発生させている訳です。
じゃあせめてA/D変換中位は流す電流を減らしたら?。
コードを以下の様に変更してみました。全部掲載するのは面倒なので部分的に抽出したコードです。
static unsigned short ADRead( int ch ) { unsigned short ad; pinMode(12, INPUT); //1の桁のカソードコモン pinMode(11, INPUT); //10の桁のカソードコモン ad = analogRead( ch ); //A/Dコンバーターの変換値を取得する pinMode(12, OUTPUT); //1の桁のカソードコモン pinMode(11, OUTPUT); //10の桁のカソードコモン return ad; } void loop() // run over and over again { int i; unsigned short ad; float value; for( i = 0, ad = 0; i < 16; i++ ) { ad += ADRead( 0 ); //A/Dコンバーターの変換値を取得する } ad >>= 4; value = (ad * 110.0) / 1023; //入力電圧を求める // value += 0.5; //小数点以下を四捨五入 disp_buf[0] = (int)value / 10; //10位桁 disp_buf[1] = (int)value % 10; //1位桁 Serial.print("AD="); Serial.print(ad,DEC); Serial.print(" value="); Serial.print((int)(value * 10),DEC); Serial.print("\n"); delay(500); //wait }
つまりAD変換する直前にLEDを全部OFFとして電流を減らし、AD変換完了後は再びLEDをONしています。
これでやってみたところ入力に対して3mV程度低い値となりました。まだ完璧とは言えませんが継続的に電流を流し続けた場合よりは実際に近くなっています。
もちろんこの対策は表示にLEDを使っているからで、別のデバイスで同じ方法を使えるかどうかは判りません。
Making Things Talk -Arduinoで作る「会話」するモノたち
- 作者: Tom Igoe
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/11/17
- メディア: 大型本
2009-03-30 22:26
nice!(0)
コメント(2)
トラックバック(1)
MC9S08SH4のデータシートを読んだところ、「VDDA/VREFHおよびVSSA/VREFLは、ぞれぞれVDDとVSSにダブル・ボンディングされている」との記述が見つかりました。
VDDA/VREFH and VSSA/VREFL, are double bonded to VDD and VSS respectively.
これで、ボンディングは共通インピーダンスにならず、どうしてもキャンセルできないのは、リードフレーム部分ということになります。もちろん、LM35DZのGNDが、マイコンのGNDと直接つながっている場合の話です。
そこで、リードフレーム分をもキャンセルできる画期的なアイディアをひとつ。アナログ入力をもう一つ用意してLM35DZのGNDに接続します。そして、二つのアナログ入力の差を出力として採用します。こうすれば、リードフレームもボンディングもキャンセルできます。
ただし、この回路のままでは、LM35DZのGND端子は、限りなく0Vに近いはずなので、アナログ入力としては不適切です。そこで、GND端子にダイオードを順方向に使ってゲタをはかせます。どんなダイオードでも使えるはずです。これで、電位差は内部基準電圧の範囲内で正しく求まるはずです。
「リードフレーム」や「ボンディング」についての解説は、別の機会に書きますか。
by noritan (2009-03-31 08:48)
> 「リードフレーム」や「ボンディング」についての解説は、別の機会に書きますか。
有難うございます。是非お願いします。
IC内部の構造って、写真で見たり、本に載っている簡単な解説を読んだ程度でほとんど何も知らないので、とても興味があります。
by hamayan (2009-03-31 17:37)