Не могу правильно считать напряжение батарейки из RTC

osetroff
Offline
Зарегистрирован: 27.08.2014

Arduino pro mini.

Хочется сделать контроль напряжения аккумулятора в часах реального времени RTC.

Взял таблетку lir2032, измерил напряжение 3,9В.

Подключил минус таблетки к GND, плюс через резистор 2,2Мом к A7.

Резистор нужен, чтобы при отключении питания arduino не разрядить таблетку, т.к. в отключке таблетка начинает со скоростью миллиамперов разряжаться через arduino.

Запускаю такой скетч

 





void loop() {
  int lu=readvcc();
  Serial.print("Vcc ");
  Serial.println(lu);
  delay(100);
  
  adcnr(_60,t20);//режим adcnoisereduction 60ms
  int la7=analogRead(A7);
  Serial.print("A7 ");
  Serial.print(la7);
  Serial.print(" Vbat ");
  Serial.println((long)la7*lu/1023);
  
  delay(1000);
}

 

Вывод в serial



Vcc 5068
A7 655 Vbat 3244
Vcc 5068
A7 643 Vbat 3185
Vcc 5068
A7 653 Vbat 3234
Vcc 5068
A7 671 Vbat 3324
Vcc 5068
A7 674 Vbat 3339
Vcc 5068
A7 660 Vbat 3269
Vcc 5068
A7 644 Vbat 3190
Vcc 5068
A7 661 Vbat 3274
Vcc 5068
A7 672 Vbat 3329
Vcc 5068
A7 666 Vbat 3299

Главный вопрос: почему так скачет напряжение?

Ведь опорное правильно считывается и оно стабильно.

long readvcc() {
  // 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
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #endif  

  delay(75); // 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

  long result = (high<<8) | low;

  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in millivolts
}

Благодарю.

Ivizil
Offline
Зарегистрирован: 29.03.2013

Присоединяюсь к вопросу. При измерении напряжения в наручных часах сильно пригает напряжение. Использую встроенный ИОН на 1,1 вольт. Измеряю напряжение на батарйке CR3230 через делитель 330кОм и 1МОм. Показания пляшут от 2.32 до 2.58 вольт.

nevkon
Offline
Зарегистрирован: 20.01.2015

Здесь вопрос как подключаете. Даже если в специальном держателе , то будет плавать. А если на макетке или в руках, то еще сильнее. Вообще разброс слишком сильный получился, обычно не более +/- 5 если даже соединение не очень, а если хорошее, то обычно получается +/- 2.

osetroff
Offline
Зарегистрирован: 27.08.2014

Если конденсатор в параллель + и - таблетки поставить, чтобы сглаживал колебания?

Только как рассчитать номинал конденсатора, чтобы саморазряд через него был небольшой?

Может есть спец микросхемы для определения напряжения на vbat (ну и параллельно с драйвером для зарядки Li ion)?

osetroff
Offline
Зарегистрирован: 27.08.2014

Пока решил программно, понаблюдав за скачками и сделав выводы:

1) отбрасываем первые два значения,

2) на нескольких последовательных измерениях находим мин и макс,

3) усредняем.

void loop() {
int lu=readvcc();
Serial.print("Vcc ");
Serial.println(lu);
delay(100);
byte ln=6;
int la=analogRead(A7);
la=analogRead(A7);
uint lmax=analogRead(A7);
uint lmin=lmax;
do{
int la=analogRead(A7);
//Serial.println(la);
if (la>lmax) {lmax=la;}
else if (la<lmin) {lmin=la;}
} while (--ln>0);
Serial.print("min ");
Serial.print(lmin);
Serial.print(" max ");
Serial.print(lmax);
Serial.print(" mid ");
uint lmid=(lmax+lmin)>>1;
Serial.print(lmid);
Serial.print(" Vbat ");
Serial.println((long)lmid*lu/1023);
dms(1000);
}

Результат

min 762 max 783 mid 772 Vbat 3824
Vcc 5068
min 764 max 784 mid 774 Vbat 3834
Vcc 5068
min 762 max 784 mid 773 Vbat 3829
Vcc 5068
min 760 max 784 mid 772 Vbat 3824
Vcc 5068
min 761 max 783 mid 772 Vbat 3824
Vcc 5068
min 760 max 783 mid 771 Vbat 3819
Vcc 5068
min 762 max 784 mid 773 Vbat 3829
Vcc 5068
min 762 max 784 mid 773 Vbat 3829
Vcc 5068

 

Клапауций 911
Offline
Зарегистрирован: 18.10.2015

osetroff, проверь для начала аппаратную часть - подключи батарею без мегаомных резисторов.

osetroff
Offline
Зарегистрирован: 27.08.2014

Подключил

A7 781 Vbat 3886
Vcc 5068
A7 781 Vbat 3869
Vcc 5091
A7 781 Vbat 3886
Vcc 5091
A7 780 Vbat 3881
Vcc 5068
A7 781 Vbat 3869
Vcc 5091
A7 781 Vbat 3886
Vcc 5068
A7 781 Vbat 3869
Vcc 5068
A7 781 Vbat 3869
Vcc 5091
A7 781 Vbat 3886

Да, теперь еще и опорное пляшет :(

Понаблюдаю еще.

nevkon
Offline
Зарегистрирован: 20.01.2015

Зато показания пина стали стабильными. Отсюда вывод - сопротивление было выбрано слишком большое и внешние наводки давали соответствующий результат.

Клапауций 911
Offline
Зарегистрирован: 18.10.2015

osetroff пишет:

Да, теперь еще и опорное пляшет :(

напряжение питания у тебя скачет

osetroff
Offline
Зарегистрирован: 27.08.2014

nevkon, благодарю!

Взял mosfet bss138:

pin10-1k-gate,+ на drain,source - на аналоговый вход.

Между gate и GND 10k для стекания заряда на землю при отключении arduino.

Теперь и во включенном и в отключенном состоянии arduino таблетка не расходуется.

А для измерения подаю HIGH на pin10.

Теперь с делителем повожусь и отчитаюсь.

 

osetroff
Offline
Зарегистрирован: 27.08.2014

Вопрос: а внутреннее опорное 1,1В тоже пляшет в зависимости от внешнего VCC?

 

nevkon
Offline
Зарегистрирован: 20.01.2015

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

Ivizil
Offline
Зарегистрирован: 29.03.2013

Всё верно. Внутренний источник опорного напряжения не зависит от питания контроллера  и генерирует от 1,2 до 1 вольта.  Это напряжение индивидуально для каждой микросхемы и должно определяться опытным путем. 

 

osetroff
Offline
Зарегистрирован: 27.08.2014

Пока у меня на 5V pro mini работает так:

1) усредняем опорное напряжение при каждом его считывании;

2) пропускаем два первых считывания;

3) считываем n раз, определяя минимальное напряжение;

4) рассчитываем Vbat от усредненного опорного + константа-корректор и минимального считанного напряжения.





uint _vcc;
byte _vcc_n;
//corrector
#define _vcc_cor 2
//pin
#define pin_vcc A3
#define pin_vcc_en 10
//analogread
#define _vcc_ar analogRead(pin_vcc)
//read enable
#define _vcc_en(en) digitalWrite(pin_vcc_en,en)

void setup() {
 sb(38400);
 pinMode(pin_vcc,INPUT);
 pinMode(pin_vcc_en,OUTPUT);
 _vcc=readvcc();_vcc_n=1;
}

void loop() {
  _vcc+=readvcc();_vcc_n++;
  uint lvcc=_vcc/_vcc_n;  
  if (_vcc_n>100) {_vcc=lvcc;_vcc_n=1;}  
  
  _vcc_en(1);
  cli();
  uint la=_vcc_ar;
  la=_vcc_ar;
  uint lmin=_vcc_ar;
  byte ln=4;
  while (ln-->0) {
   la=_vcc_ar;if (la<lmin) {lmin=la;}
  } 
  sei();
  _vcc_en(0);
  
  Serial.print("Vcc ");
  Serial.print(lvcc/100);
  Serial.print('.');
  Serial.print(lvcc%100);
  Serial.print(" min ");
  Serial.print(lmin);
  Serial.print(" Vbat ");
  long lv=(long)lmin*(lvcc+_vcc_cor)/1023;
  Serial.print(lv/100);
  Serial.print('.');
  Serial.println(lv%100);
  dms(1000);
}

Вывод

Vcc 5.0 min 794 Vbat 3.89
Vcc 5.0 min 794 Vbat 3.89
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.98 min 794 Vbat 3.88
Vcc 4.98 min 794 Vbat 3.88
Vcc 4.98 min 794 Vbat 3.88
Vcc 4.98 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.98 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 794 Vbat 3.88
Vcc 4.99 min 795 Vbat 3.89
Vcc 4.99 min 794 Vbat 3.88

Позже попробую с делителем.

Интересно, наводки на резисторы делителя еще ухудшат точность, чем в моем случае, когда сигнал с + таблетки подается через mosfet на аналоговый вход?

Клапауций 911
Offline
Зарегистрирован: 18.10.2015

osetroff пишет:

4) рассчитываем Vbat от усредненного опорного + константа-корректор и минимального считанного напряжения.

почему бы просто не печатать "4.99"?

osetroff
Offline
Зарегистрирован: 27.08.2014

Все получилось.

После mosfet поставил делитель r1=2,2Mom (2190000 Om, измерял тестером), r2=680K (656000 Om).

Код:


//divider after mosfet!
#define _vcc_r1 2190000
#define _vcc_r1k (_vcc_r1/1000)
#define _vcc_r2 656000
#define _vcc_r2k (_vcc_r2/1000)
uint _vcc;
byte _vcc_n;
#define _vcc_cor 3
//pin
#define pin_vcc A7
#define pin_vcc_en A3
//analogread
#define _vcc_ar analogRead(pin_vcc)
//read enable
#define _vcc_en(en) digitalWrite(pin_vcc_en,en)

void setup() {
 sb(38400);
 pinMode(pin_vcc,INPUT);
 pinMode(pin_vcc_en,OUTPUT);
 _vcc_en(0);
 analogReference(INTERNAL);
_vcc=readvcc();_vcc_n=1;
}

void loop() {
  _vcc+=readvcc();_vcc_n++;
  uint lvcc=_vcc/_vcc_n;  
  if (_vcc_n>4) {_vcc=lvcc;_vcc_n=1;}  

  _vcc_en(1);
  uint la=_vcc_ar;
  cli();
  la=_vcc_ar;
  uint lmin=_vcc_ar;
  byte ln=4;
  while (ln-->0) {la=_vcc_ar;if (la<lmin) {lmin=la;}} 
  sei();
  _vcc_en(0);

Serial.print("V ");
  Serial.print((lvcc+_vcc_cor)/100);
  Serial.print('.');
  uint lvccd=(lvcc+_vcc_cor)%100;
  if (lvccd<10) {Serial.print('0');}
  Serial.print(lvccd);
  
  Serial.print(" mi ");
  Serial.print(lmin);
  
  Serial.print(" Vmi ");
  uint lv=((ulong)lmin*1.1*1000/1024);
  uint lvd=lv/10;
  Serial.print(lvd/100);
  Serial.print('.');
  lvd=lvd%100;
  if (lvd<10) {Serial.print('0');}
  Serial.print(lvd);
  
  Serial.print(" Vb ");
  uint lvb=((ulong)lv*(_vcc_r1k+_vcc_r2k))/_vcc_r2k;
  
  lvd=lvb/10;
  Serial.print(lvd/100);
  Serial.print('.');
  lvd=lvd%100;
  if (lvd<10) {Serial.print('0');}
  Serial.println(lvd);

  dms(1000);
}

Вывод

V 5.01 mi 803 Vmi 0.86 Vb 3.73
V 5.01 mi 800 Vmi 0.85 Vb 3.72
V 5.02 mi 806 Vmi 0.86 Vb 3.75
V 5.01 mi 803 Vmi 0.86 Vb 3.73
V 5.01 mi 805 Vmi 0.86 Vb 3.74
V 5.01 mi 801 Vmi 0.86 Vb 3.73
V 5.01 mi 802 Vmi 0.86 Vb 3.73
V 5.02 mi 805 Vmi 0.86 Vb 3.74
V 5.01 mi 803 Vmi 0.86 Vb 3.73
V 5.01 mi 800 Vmi 0.85 Vb 3.72
V 5.01 mi 806 Vmi 0.86 Vb 3.75
V 5.00 mi 801 Vmi 0.86 Vb 3.73
V 5.00 mi 805 Vmi 0.86 Vb 3.74

Нужно только правильный mosfet, чтобы через 1k с пина открывался полностью (для 5В bss138 работает,для 3.3В - нет). И с gate на землю не нужен 10k, т.к. через пин замечательно все стекает. Даже пробовал установить пин в 1 а потом убрать питание arduino.