Определение напряжения питания микроконтроллера

Микроконтроллеры ATmega (как и некоторые модели семейства ATtiny) имеют 10-битные модули АЦП, которые могут использоваться для измерения аналогового напряжения. Эти АЦП являются логометрическими, то есть они производят измерение относительно некоего базового уровня (обычно Vcc).
В случае Arduino-совместимых плат, которые запитываются стабилизированным напряжением 5 В, это означает, что у вы можете  производить измерения в диапазоне 0..5 В, различая уровни 0..1023, достигая при этом разрешения около 5 мВ на шаг.
Если есть “вольтметр”, то рано или поздно возникнет желание контролировать с его помощью напряжение, подаваемое на выводы питания микроконтроллера.
Первое решение, приходящее в голову – соединить ногу Vcc с одним из аналоговых входов и вызвать функцию analogRead(). Не тут то было – какое бы напряжение ни подавалось в качестве питания микроконтроллера, АЦП будет возвращать одну и ту же величину – 1023.
Так как же определить, что за напряжение питает наш микроконтроллер? Ведь это жизненно необходимо при автономном питании, так как может своевременно выявить момент исчерпания заряда батарей.
На помощь может прийти имеющийся в каждой (ну, ладно – почти в каждой) модели ATmega/ATtiny источник опорного напряжения, выдающий ровно (ну, ладно – примерно) 1,1 В. Если мы прочитаем это напряжение, используя в качестве опорного напряжение питания (Vcc), то, выполнив нескольких арифметических действий, сможем получить вожделенное значение. Итак:

  • предположим, что наш АЦП вернул значение “x”, которое соответствует напряжению 1.1 В
  • имея 5 В в качестве Vcc, мы должны будем получить значение, примерно равное 1100 / 5000 * 1023 = 225
  • ну, а если бы то же самое мы проделали бы при Vcc=3.3 В, то должны были получить значение 1100 / 3300 * 1023 = 341
  • или в общем случае: 1100 / Vcc * 1023 = x
  • выполнив несложные преобразования, найдем, что Vcc = 1100 / x * 1023

То есть, нам необходимо измерить внутреннее опорное напряжение 1,1 В, и тогда мы сможем сказать, что же за напряжение Vcc питает наш микроконтроллер!
“Нормально, Григорий? Отлично, Константин!”
Но погодите радостно потирать руки: к превеликому сожалению широко используемую в Arduino-кругах функцию analogRead() не удастся заставить измерить внутреннее опорное напряжение. Придется идти в обход…

А точнее – заглянуть в даташит и, почерпнув там некоторые сведения, произвести нужное преобразование вручную. Вот так это будет выглядеть для Arduino:

static int vccRead(byte us =250) {
  ADMUX = 1<<REFS0; // опорное напряжение - Vcc
  ADMUX |= 0x0E;    // объект измерения - внутренний источник
                    // стабилизированного напряжения 1.1В
  delayMicroseconds(us);

  ADCSRA |= 1<<ADSC;         // запуск АЦ-преобразования
  while(ADCSRA & (1<<ADSC)); // и ожидание его завершения
  word x = ADC;
  return x ? (1100L * 1023) / x : -1;
}

void setup() {
  Serial.begin(9600);
  Serial.println("\n(bandgap)");
  analogRead(0);
}

void loop() {
  Serial.println(vccRead());
  delay(5000);
}

 

В код функции vccRead введена задержка us, позволяющая стабилизировать результаты измерений и повысить их точность. Небольшой числовой эксперимент показывает, что оптимальные результаты достигаются при задержке от 100 мкс.

Вот какие результаты получились у меня для разных значений задержки при питании от USB:

10 мкс 50 мкс 100 мкс 200 мкс 300 мкс
3049
4278
4295
4137
4167
4311
4311
4152
4121
4311
3827
4829
4871
4808
4748
4829
4850
4829
4829
4808
4669
5068
5091
5068
5068
5091
5091
5068
5068
5091
5138
5138
5138
5138
5161
5138
5138
5138
5161
5138
3641
4688
4768
4768
4688
4748
4768
4768
4748
4650

Leave a Reply

Your email address will not be published. Required fields are marked *

*