google-site-verification: google3bd66dd162ef54c7.html
fc2ブログ

外付け部品無しでArduinoの電源電圧を測定する

 ArduinoのCPUのADコンバーターの入力セレクタで面白い機能を作る話の続きです。前回はCPU温度計を作りましたが、今回は電源電圧を測定してみます。

▼測定原理
ADCのVrefとINPUTの関係図
 Arduino (ATmega328P) で電源電圧を測定する場合、左の図のようにVccを抵抗で分圧してADCに入力し、ADCのVrefには内部基準電圧である1.1Vを使うのが普通のやり方です。

 ところで、ADコンバーターの入力は1.1Vの基準電圧にも接続出来るようになっています。ということは、右の図のようにVrefにVccを接続することで、1.1Vに対するVccの比率を知ることが出来ます。1.1Vに対する比率が判るということはVccの絶対値が判る、つまり電源電圧の測定が出来るということになります。

 右の図の回路なら分圧抵抗がいりません。さらに、この状態はCPU内のレジスタ設定だけで作ることが出来るので、配線は不要です。またI/Oピンすら使いません。

 まあいろいろな事情で、こういうことが出来るようになっているのだと思いますが、入っているなら使わないと損です。

 ということで、いきなりプログラムというかスケッチです。

▼電源電圧読み出しデモプログラム
/*
 CPU温度センサーと電源電圧の読み出し、表示デモ
 2014/7/19 ラジオペンチ
 http://radiopench.blog96.fc2.com/
 */

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  pinMode(13, OUTPUT);
  lcd.begin(16, 2);
  lcd.print("Starting...");
  delay(1000);
  Serial.begin(9600); 
}

void loop() {
  float temp, Vcc;
  digitalWrite(13, HIGH);
  temp = cpuTemp();                  // CPU温度測定
  Vcc  = cpuVcc();                   // 電源電圧測定
  digitalWrite(13, LOW);

  Serial.print("Temp= ");           // シリアルに温度を出力
  Serial.print(temp,1);
  Serial.print(", Vcc= ");          // シリアルにVccを出力
  Serial.println(Vcc,2);

  lcd.setCursor(0, 0);               // 液晶に表示
  lcd.print("Temp= ");
  lcd.print(temp,1);                 // 温度、小数点以下1桁表示
  lcd.print("c ");                   // ゴミ消し
  lcd.setCursor(0, 1);
  lcd.print("Vcc = ");               // Vcc
  lcd.print(Vcc,2);
  lcd.print("V ");                   // ゴミ消し

  delay(500);
}

// 流用する場合は以下を全てコピーする

float cpuTemp(){                     // CPU温度測定関数
  long sum=0;
  adcSetup(0xC8);                    // Vref=1.1V, input=ch8
  for(int n=0; n < 100; n++){
    sum = sum + adc();               // adcの値を読んで積分
  }
  return (sum * 1.1/102.4)- 342.5;   // 温度を計算して戻り値にする。-342.5は要調整
}

float cpuVcc(){                      // 電源電圧(AVCC)測定関数
  long sum=0;
  adcSetup(0x4E);                    // Vref=AVcc, input=internal1.1V
  for(int n=0; n < 10; n++){
    sum = sum + adc();               // adcの値を読んで積分
  }
  return (1.1 * 10240.0)/ sum;       // 電圧を計算して戻り値にする
}

void adcSetup(byte data){            // ADコンバーターの設定
  ADMUX = data;                      // ADC Multiplexer Select Reg.
  ADCSRA |= ( 1 << ADEN);            // ADC イネーブル
  ADCSRA |= 0x07;                    // AD変換クロック CK/128
  delay(10);                         // 安定するまで待つ
}

unsigned int adc(){                  // ADCの値を読む
  unsigned int dL, dH;
  ADCSRA |= ( 1 << ADSC);            // AD変換開始
  while(ADCSRA & ( 1 << ADSC) ){     // 変換完了待ち
  }
  dL = ADCL;                         // LSB側読み出し 
  dH = ADCH;                         // MSB側
  return dL | (dH << 8);             // 10ビットに合成した値を返す
}
 せっかくなので、前の記事のCPU温度センサー読み出しプログラムと合体させ、サブルーチンを共用するようにしました。

▼実行するとシリアルモニタに温度と電圧を表示
シリアルモニタ

▼液晶シールドがあれば
Arduinoで温度と電圧測定
 こんなふうに表示します。なお、液晶シールドを繋がなくてもプログラムは動くので、シリアルモニタへの表示は問題無く行います。I/Oコネクタに何も接続しなくても動くので、初心者にもお勧めしたいプログラムです。なお、動作確認はArduino1.0.5で行っています。

 温度計はCPUのチップの温度を測っているので、電源ON直後と比べると5℃くらい徐々に温度が上昇します。ポートにたくさん電流を流したりすると更に温度上昇するはずです。ということで、気温を正確に測定することは出来ません。

 温度測定プログラムはcpuTemp()、電源電圧測定プログラムはcpuVcc()という名前の関数で、それぞれの測定結果を浮動小数点形式で返してきます。プログラムリストの44行目以降を全部コピペしてこの関数を呼べば温度や電圧を手軽に測定できるようになります。何か他の目的のプログラムに混ぜて使うと、面白いことが出来ると思います。

 以上、2回に分けてArduino UNOのCPU(ATmega328P)のADコンバーターのちょっと面白い使い方について紹介しました。

 このあたりの話は日本語のWebではあまり見かけないのですが、記事を書きながら検索してみると、同じようなことをやっている英語の資料がいろいろ出てきました。代表的と思われる資料のリンクを以下に置いておきます。

Internal Temperature Sensor, Arduino Playground
AVR122: Calibration of the AVR's internal temperature reference
Can Arduino measure its own Vin?, Arduino Forum
関連記事

コメントの投稿

管理者にだけ表示を許可する

No title

こんにちは、edyと申します。
LCDシールドを作ったので、スケッチをコピーさせていただきました。無事動きました。
Arduinoは初心者ですので、これからもいろいろと参考にさせていただきます。
ありがとうございました。

edyさん今晩は

うまく動いたみたいで良かったです。

adyさんって、PSoCやられてる、迷走の果ての方ですよね。以前からブログ拝見してます。

今後ともよろしくお願い致します。

No title

だいぶ年月が経っていますが、発想が非常に面白く
大変参考になりました。

部分的にコードを利用させていただきます。

良い記事をありがとうございます。

コメンテーターさん、おはようございます

記事を読んで頂いてありがろうございます。
何かのお役に立てたらうれしいです。

参考になります。

こんにちは。

私も50代ミドルの南と申します。

ただいま、Iot真っ盛りですね。

社内で、簡単な遠隔監視回路等を試作しています。

スリープモード、電源電圧測定等々、

ラジオペンチさんのブログは大変参考になります。

ありがとうございます。御礼まで。

re:参考になります。

南さん今晩は。

ありがとうございます、そんなふうに言っていただくと励みになります。

ATtiny85にて

素晴らしい発想ですね。
ArduinoUNO/ArduinoNANOでは上手く行きましたがATtiny85ではVcc測定値=1.1V になるようです。Vcc電圧を3.0V位から可変しても測定値は常に1.1Vのままです。
ATtiny85ではこの方式は使えないのか、設定方法が違うのか、分かれば教えて下さい。
Li-Poバッテリー電圧を是非この方式で測定し監視したいと思っています。
宜しくお願い致します。

re:ATtiny85にて

ATtiny85のデーターシートを見ると、ADCのVref(フルスケール)を電源に接続することは出来ないし、ADCの入力を基準電圧に接続することも出来ないようです。
ということで、この記事の方法で電源電圧を測定することは出来ないです。
もしピンが余ってるなら電源電圧を分圧してそのピンを使って測定すれば良いのですが、こういう質問しているということは、たぶんピンが余ってないのでしょうね。

re:ATtiny85にて

早々のご返信ありがとうございます。
悪い予感が的中しましたね。
Vccを抵抗分圧方式で対応策を検討します。

re:ATtiny85にて

ADMUXレジスタの構成がATmega328Pとは異なります。

ATtiny85のデータシート
https://avr.jp/user/DS/PDF/tiny45.pdf
p.82の図17-1 ADMUXレジスタ

REFS2,1,0で基準電圧を選択 表17-3
  X00でVccに

MUX3,2,1,0で入力マルチプレクサ選択 表17-4
  1100で1.1V/2.56Vを

これで、Vccを基準にして内部基準電圧の
1.1V/2.56Vを計ることができるはずですが、
入力チャンネル1.1Vと2.56Vの切り替え方法が
不明です。
しかし、英文データシートではMUX=1100での
選択は「VBG」となっています。
VBGは1.1Vです。

re:ATtiny85にて

居酒屋ガレージ店主(JH3DBO)さん、ご指摘ありがとうございます。

和文のデーターシートがあるのですね。コメントをざっと読んでからデーターシートを読んだら、こうすれば出来るじゃん!と気付いた内容が全部書き込んでいただいたコメントに全部書かれてました。

この先はhamaさんにも読んでいただきたいので、次のコメントに書くことにします。

hamaさんへ、コメントの訂正があります

すみません、先に私が書いた回答は間違っていました。
居酒屋ガレージ店主(JH3DBO) さんからコメントで頂いた設定をすればご希望の測定が出来そうです。

そのロジックはコメントを読んでいただくとして、具体的には55行目の
adcSetup(0x4E); を
adcSetup(0x0C); に変更すればたぶん行けるような気がします。
実機が無いので確認出来ていませんが、お試しください。

ATtiny85にて

間が空いてしまいましたが、下記変更で上手く行きました。
adcSetup(0x4E); を
adcSetup(0x0C); に変更
これで入力回路無しでバッテリー電圧測定出来るようになりました。
有り難うございました。

re:ATtiny85にて

hamaさん、その設定でいけたのですね。
連絡ありがとうございます。
カレンダー
02 | 2024/03 | 04
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 - - - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。
記事の内容のご利用は読者の自己責任でお願いします。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード