Измерение литий-ионого аккумулятора, от которого работает Arduino

Я использую Arduino pro mini 5 В (со снятыми регулятором и индикатором питания).

Я читал, как точно измерить литий-ионные аккумуляторы при питании от того же аккумулятора, от которого вы пытаетесь измерить. Использование внутреннего аналогового опорного напряжения 1,1 В для измерения расхода источника VCC с помощью делителя напряжения на нем и математических расчетов для отображения преобразованного значения.

Читая форумы Arduino, я наткнулся на этот ответ.

  long readVcc() {
  long result;
  // Чтение ссылки 1,1 В относительно AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Подождите, пока Vref установится
  ADCSRA |= _BV(ADSC); // Конвертировать
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Обратный расчет AVcc в мВ
  return result;
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println( readVcc(), DEC );
  delay(1000);
}

Однако я не вижу аналогового чтения нигде в этом скетче. (Это строго внутренняя ссылка?) В конце темы кто-то говорит, что вы можете сделать это без делителя напряжения на аналоговом выводе.

Может ли кто-нибудь подтвердить или объяснить это? Я не хочу сломать свой Arduino...

, 👍7


3 ответа


Лучший ответ:

5

Использование внутреннего аналогового эталона 1,1 В для измерения разряда VCC источник с помощью делителя напряжения на нем

Вы действительно можете использовать делитель напряжения и измерить уменьшенное значение Vcc. относительно внутреннего опорного напряжения 1,1 В. Однако это не то, код, который вы разместили, делает. Вместо этого он измеряет внутреннюю ссылка на Vcc, как указано в комментарии в коде. Бит REFS0 выбирает Vcc в качестве эталона для АЦП. Биты MUX1...MUX3 выберите внутреннюю ссылку в качестве входного канала.

result = ADCL;
result |= ADCH<<8;

Эта идиома восходит к тому времени, когда компилятор не знал, как читать 16-битные регистры ввода-вывода: вам нужно было явно читать по одному байту за раз а затем объединить их в 16-битное слово. Это время давно прошло, и теперь вы можете просто получить доступ к 16-битному регистру как ADC напрямую. я даже избавился бы от переменной result и просто:

return 1126400L / ADC;  // Vcc в мВ

Правка: как было предложено Busybee, вот объяснение коэффициент 1126400: АЦП измеряет отношение своего входного напряжения к его опорное напряжение и возвращает это отношение, масштабированное с коэффициентом 1024. В в этом случае

ADC = 1024 × (Vbg ÷ Vcc)

где Vbg — опорное напряжение запрещенной зоны 1,1 В. Таким образом,

Vcc = 1024 × Vbg ÷ АЦП

Если нам нужно напряжение Vcc в милливольтах, мы добавляем к нему напряжение Vbg в милливольтах. приведенное выше уравнение и получить

Vcc (в мВ) = 1024 × 1100 ÷ АЦП = 1126400 ÷ АЦП

,

Можно добавить, что 1126400 — это 1024*1100, что масштабирует результат, и почему., @the busybee

@thebusybee: Спасибо за предложение. Добавлен., @Edgar Bonet

Выдающийся ответ, как обычно. (проголосовали), @Duncan C

Спасибо за очень подробное объяснение!, @Lindsay Cox

разве это не 1.1vx **1023** x 1000? 1023 - это 10-битное общее значение для АЦП?, @Lindsay Cox

@LindsayCox: Нет, это 1024, хотя 1023 — очень распространенная ошибка, предположительно потому, что это самое высокое значение, которое вы можете получить. Согласно техническому описанию, «_максимальное значение представляет собой напряжение на выводе AREF **минус 1 LSB**._» (выделено мной) и «ADC = Vin ⋅ **1024** ÷ Vref». Таблица данных является _единственным_ авторитетным источником. Обратите внимание, что, учитывая неопределенность в Vbg, это не имеет большого значения., @Edgar Bonet


2

Вместо вызова analogRead() этот скетч выполняет эквивалентные действия, напрямую манипулируя аппаратными регистрами, чтобы начать преобразование, дождаться завершения преобразования и получить преобразованное значение.

Простое чтение конечного значения выполняется операторами:

result = ADCL;
result |= ADCH<<8;

Все операторы, следующие за delay(2) и включая два вышеперечисленных, вместе взятые, делают то, что делает analogRead().

,

Относительно «_Все операторы после delay(2)_”: обратите внимание, что analogRead() [устанавливает ADMUX](https://github.com/arduino/ArduinoCore-avr/blob/1.8.3/cores /arduino/wiring_analog.c#L63-L72)., @Edgar Bonet

Да - я пропустил это. Спасибо, @EdgarBonet., @JRobert


3

Если кого-то еще это смущает:

Не повредит ли это вашему Arduino?

  • Нет, это внутреннее опорное напряжение между VCC & внутренний аналоговый источник опорного напряжения 1,1 В.

Нужен ли делитель напряжения?

  • Нет, если только вам не нужно измерять что-то внешнее по отношению к Arduino!

Действительно ли внутреннее опорное напряжение составляет 1,1 В?

  • Нет, кажется, что каждый pro mini, который у меня есть, эталонное напряжение 1,1 В немного отличается. У моих pro mini нет разъема для контакта AREF, поэтому вам нужно выяснить, какое значение имеет значение для каждого отдельного Arduino.

Я использовал это,

1.15 x 1023 x 1000 = [значение в кавычках от второй до последней строки в функции]

return "1125300L" / ADC; 

Я просто несколько раз увеличивал опорное напряжение 1,1 В на 0,01, пока выходное напряжение не совпало с показаниями напряжения на моем цифровом мультиметре. Я бы подумал, что с известным напряжением вы могли бы выполнить эту математику в обратном порядке, чтобы найти, что такое AREF на самом деле. Я уверен, что это было бы проще.

Большое спасибо JRobert & @ EdgarBonnet за ответы!

,