вольтметр постоянного напряжения

draco
Offline
Зарегистрирован: 14.12.2017

пытаюсь осуществить измерение постоянного напряжения питания ардуино

использую алгоритм из интернета основанный на функции измерения Vcc и использовании этого значения для калибровки опорного http://tim4dev.com/arduino-secret-true-voltmeter/

измеряемое программой напряжение не сходится с показаниями мультиметра

помогите пожалуйста разобраться

схема и код ниже

 

draco
Offline
Зарегистрирован: 14.12.2017

схема

/*
 * Copyright 2015 Yuriy Tim http://tim4dev.com
 * На основе оригинального кода (c) Scott Daniels http://provideyourown.com
 *
 * В ATmega есть внутренний источник опорного напряжения 1.1В (другое название internal bandgap reference voltage), которое не зависит от Vcc.
 *
 * Даташит на ATMEGA 328
 * http://www.atmel.com/devices/atmega328p.aspx?tab=documents
 *   "bandgap reference voltage" :
 *   min = 1.0
 *   typical = 1.1
 *   max = 1.2
 */

// для отладки через консоль
const byte debug = 2;


// резисторы делителя напряжения
const float r1 = 100800;  // 100K  100800
const float r2 =  9860;  // 10K  9860

// эту константу (typVbg) необходимо откалибровать индивидуально
const float typVbg = 1.076; // 1.0 -- 1.2

float Vcc = 0.0;
float MaxVoltage = 0.0;

#define A_PIN 1
#define COUNT 5

int i;
float curVoltage;
char *stime;



/****************************************************************************
 * Главная программа
 ****************************************************************************/

void setup() {
  if (debug > 1) {
    Serial.begin(9600);
  }

  // определение опорного напряжения
  analogReference(DEFAULT);  // DEFAULT INTERNAL использовать Vcc как AREF
  delay(100);
  Vcc = readVcc();
  MaxVoltage = Vcc / (r2 / (r1 + r2));
  analogWrite(A_PIN, 0);

  if (debug > 1) {
    Serial.print("Vcc = ");
    Serial.println(Vcc);
    Serial.print("Max V. = ");
    Serial.println( MaxVoltage );
    Serial.println("---");
  }
  
  delay(2000);
}

void loop() {
  Vcc = readVcc();
  stime = TimeToString(millis()/1000);
  // считываем точное напряжение с A0, где будет находиться наш вольтметр с делителем напряжения
  curVoltage = 0.0;
  for (i = 0; i < COUNT; i++) {
      curVoltage = curVoltage + analogRead(A_PIN);
      delay(10);
  }
  curVoltage = curVoltage / COUNT;
  float v  = (curVoltage * Vcc) / 1024.0;
  float v2 = v / (r2 / (r1 + r2));

  if (debug > 1) {
    v2=analogRead(A_PIN)*Vcc/1024;
    Serial.print("V = ");
    Serial.print(v2);
  }
  // clear
  if (debug > 1) Serial.println();
  analogWrite(A_PIN, 0);
  delay(1000);
  Serial.print("Vcc________ = ");
    Serial.println(Vcc);
    delay(2000);
}



/****************************************************************************
 * Функции
 ****************************************************************************/

float readVcc() {
  byte i;
  float result = 0.0;
  float tmp = 0.0;

  for (i = 0; i < 5; i++) {
    // Read 1.1V reference against AVcc
    // set the reference to Vcc and the measurement to the internal 1.1V reference
    #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
        ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
        ADMUX = _BV(MUX5) | _BV(MUX0);
    #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
        ADMUX = _BV(MUX3) | _BV(MUX2);
    #else
        // works on an Arduino 168 or 328
        ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #endif

    delay(3); // Wait for Vref to settle
    ADCSRA |= _BV(ADSC); // Start conversion
    while (bit_is_set(ADCSRA,ADSC)); // measuring

    uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
    uint8_t high = ADCH; // unlocks both

    tmp = (high<<8) | low;
    tmp = (typVbg * 1023.0) / tmp;
    result = result + tmp;
    delay(5);
  }

  result = result / 5;
  return result;
}

// t is time in seconds = millis()/1000;
char * TimeToString(unsigned long t)
{
  static char str[12];
  long h = t / 3600;
  t = t % 3600;
  int m = t / 60;
  int s = t % 60;
  sprintf(str, "%04ld:%02d:%02d", h, m, s);
  return str;
}

результат консоли

draco
Offline
Зарегистрирован: 14.12.2017

typVbg я подобрал таким образом, чтобы измеряемое функцией Vcc совподало с напряжением между выводом 5в и зем ардуино

однако, при таком значении измеряемое на А0 напряжение не соответствует действительному - измеренному мульт-ом (ни преобразованное после делителя значение, ни снятое с делителя до пересчета(как в коде выше))

я подбирал  typVbg  такое, что бы имзеряемое напряжение совподало с мульт-ом, но тогда отличалось измеряемое функцией Vcc...

P.S. парамметры резисторов имзеренны мульт-ом и забиты в код но они по факту не должны влиять - см. выше "снятое с делителя до пересчета"

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

1.
Статья на которую Вы ссылаетесь - по сути плагиат вот с этой. Причём оригинал точнее и полнее. Толи автор плагиата не до конца разобрался в вопросе, толи не счёл нужным подробно расписывать. Найдите в статье оригинале заголовок "Detecting low voltage" и посмотрите на технику замера внутреннего опорного напряжения (оно уникально для каждой микросхемы) и т.п. Я сейчас не помню в чём именно различия оригинала и плагиата, но оно есть - сами разберётесь.

2.
При измерениях и отладке не используйте ни компьютерное USB, ни какой бы то ни было другой импульсный источник питания. Только тёплое ламповое батарейное питание.

3.
Внимательно читайте даташит, там в каких-то случаях надо первый результат выбрасывать на помойку.

4.
Убедитесь что в момент измерения нет никакой активности контроллера (лучше использовать технику Noise reduction (см. даташит, разд. 14.5 и разд. 28.6).

И всё у Вас получится отлично. Не ждите идеального совпадения, т.к. точность ADC - 2lsb, а точность Вашего мультиметра см. сами, но в пределах этих допусков всё нормально получается.

draco
Offline
Зарегистрирован: 14.12.2017

ЕвгенийП спасибо за ссылку!

arduinec
Offline
Зарегистрирован: 01.09.2015

draco пишет:

пытаюсь осуществить измерение постоянного напряжения питания ардуино

http://arduino.ru/forum/programmirovanie/sysinfo-arduino