June 9, 2012

Arduino における正確な ADC について

Arduinoにおいて、正確なADCを行うにはコツがいるようだ。
AVccの揺れを補償してやる必要がある。

http://hacking.majenko.co.uk/node/57
http://code.google.com/p/tinkerit/wiki/SecretVoltmeter
によると、
long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}
という関数を作って、
unsigned int ADCValue;
double Voltage;
double Vcc;

Vcc = readVcc()/1000.0;
ADCValue = analogRead(0);
Voltage = (ADCValue / 1024.0) * Vcc;
という形で、対処してやる必要があるようだ。

_BV()はビットシフトするマクロでREFS0,MUX3,MUX2,MUX1,ADSCは
arduino-1.0.1\hardware\tools\avr\avr\include\avr\iom328p.hに定義されている。


ADC周りのレジスタについては
http://www9.plala.or.jp/fsson/NewHP_elc/AVR/Avr_ADC.html
を参照のこと。

これを踏まえて、readVccにコメントを付けるとするなら、
long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);// ARefに1.1Vを出力し,基準電圧1.1Vをアナログ入力チャンネルに指定
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // 変換開始
  while (bit_is_set(ADCSRA,ADSC));// 変換完了待ち
  result = ADCL;// 変換結果取得(下位8bit)
  result |= ADCH<<8;// 変換結果取得(上位2bit)
  result = 1126400L / result; // 1126400 / ( 1024 * 1.1 / AVcc ) = AVcc*1000(mV)
  return result;
}
という感じか。