Измеритель ёмкости аккумуляторов (18650) от AlexGyver

Forvad
Offline
Зарегистрирован: 09.02.2016

Исходник http://alexgyver.ru/capacity_tester/

собрал, запустил, работает ... всё вроде бы просто и понятно. Поменял там некоторые пины, еще что-то по мелочи. Никаких проблем ...

Начал тестить аккумы - оказалось, что долго. А в порт время шлётся в секундах  и быстро осознать сколько это 27352с :) не получается - ну думаю "делов то", переведу в часы ... делю время ещё на 3600. Жму загрузка .... и облом: 

D:\Мои документы\Arduino\capacity_tester\capacity_tester.ino: In function 'void loop()':
capacity_tester:78: error: 'readVcc' was not declared in this scope
capacity_tester:79: error: 'readAnalog' was not declared in this scope
capacity_tester:84: error: 'sendData' was not declared in this scope
capacity_tester:92: error: 'disp_print' was not declared in this scope
capacity_tester:100: error: 'disp_print' was not declared in this scope
D:\Мои документы\Arduino\capacity_tester\capacity_tester.ino: In function 'void sendData()':
capacity_tester:121: error: 'disp_print' was not declared in this scope
exit status 1
'readVcc' was not declared in this scope

попробовал исходник - тоже самое, переустановил - эффекта ноль :(

Поэтому прошу помощи ... помогите разобратся, что произошло. Ведь еще вчера всё спокойно компелилось :(

зы: тему создал в проектах т.к. есть еще вопрос по доработке, а как тут дорабатывать если "всё умерло" :)

Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

Код в студию. Именно ваш, правленый.

Forvad
Offline
Зарегистрирован: 09.02.2016


#define NUM_READS 100
#include "TM1637.h"  //библиотека дисплея

byte load_pin=0; //пин нагрузки (аналоговый!!!!)

byte buzz_gnd=2; //динамик земля
byte buzz_pin=5; //динамик сигнал

byte disp_gnd=6; //земля дисплея
byte CLK = 7;  //пин дисплея
byte DIO = 8;  //пин дисплея
byte disp_vcc=10;  //питание дисплея
TM1637 disp(CLK,DIO);   //обозвать дисплей disp

byte butt_pin=11;  //состояние кнопки
byte butt_gnd=12;  //земля кнопки

byte relay_pin=3; //пин реле было 13

const float typVbg = 1.095; // 1.0 -- 1.2
float Voff = 2.5; // напряжение отсечки (для Li-ion=2.5 В, для LiPo=3.0 В)
float R = 8.455; //сопротивление нагрузки
float I;
float cap = 0; //начальная ёмкость
float V;
float Vcc;
float Wh = 0;
unsigned long prevMillis;
unsigned long testStart;

String cap_string;

void setup() {  
  pinMode(relay_pin, OUTPUT);  //пин реле как выход
  digitalWrite(relay_pin, HIGH); //выключить реле (оно обратное у меня)
  
  pinMode(buzz_pin, OUTPUT); //пищалка
  pinMode(buzz_gnd, OUTPUT); //пищалка
  digitalWrite(buzz_gnd, 0);
  
  pinMode(butt_pin, INPUT_PULLUP); //кнопка подтянута
  pinMode(butt_gnd, OUTPUT); //земля кнопки
  digitalWrite(butt_gnd, 0);

  pinMode(disp_vcc, OUTPUT); //питание дисплея
  pinMode(disp_gnd, OUTPUT); //земля дисплея
  digitalWrite(disp_vcc, 1);
  digitalWrite(disp_gnd, 0);  

  disp.init();  //инициализация дисплея
  disp.set(5);  //яркость (0-7)  

  Serial.begin(9600);  //открыть порт для связи с компом
  Serial.println("Press any key to start the test...");  //Отправьте любой символ для начала теста
  while (Serial.available() == 0) {
    disp.display(3,0);
    if (digitalRead(butt_pin)==0) {break;}  //или нажмите кнопку, чтобы начать тест!
  }
  tone(buzz_pin,1000,500);
  Serial.println("Test is launched...");
  Serial.print("s");
  Serial.print(" ");
  Serial.print("V");
  Serial.print(" ");
  Serial.print("A");
  Serial.print(" ");
  Serial.print("mAh");
  Serial.print(" ");
  Serial.print("Wh");
  Serial.print(" ");
  Serial.println("Vcc");
  digitalWrite(relay_pin, LOW); //Переключить реле (замкнуть акум на нагрузку)
  testStart = millis();  //время начала теста в системе отсчёта ардуины
  prevMillis = millis();  //время первого шага
}

void loop() {
  Vcc = readVcc(); //хитрое считывание опорного напряжения (функция readVcc() находится ниже)
  V = (readAnalog(load_pin) * Vcc) / 1023.000; //считывание напряжения АКБ
  I = V/R; //расчет тока по закону Ома, в Амперах
  cap += I*(millis()-prevMillis)/3600000*1000; //расчет емкости АКБ в мАч
  Wh += I*V *(millis() - prevMillis)/3600000; //расчет емкости АКБ в ВтЧ
  prevMillis = millis();
  sendData(); // отправка данных
  
  if (V < Voff) { //выключение нагрузки при достижении минимального напряжения
    digitalWrite(relay_pin, HIGH);  //разорвать цепь (отключить акб от нагрузки)
    Serial.println("Test is done");  //тест закончен
    
    for (int i=0; i<5; i++) {  //выполнить 5 раз
      tone(buzz_pin,1000,500);   //пищать на 3 пин частотой 100 герц 500 миллисекунд
      disp_print(cap_string);
      delay(1000);
      disp.clearDisplay();
      delay(500);
    }
    
    while (2 > 1) {  //бесконечный цикл, чтобы loop() не перезапустился + моргаем результатом!
      tone(buzz_pin,1000,500);   //пищать на 3 пин частотой 100 герц 500 миллисекунд
      disp_print(cap_string);
      delay(1000);
      disp.clearDisplay();
      delay(10000);
    }
  }
}

void sendData() {       //функция, которая посылает данные в порт
  Serial.print((millis() - testStart) / 3600000);
  Serial.print(" ");
  Serial.print(V, 3);
  Serial.print(" ");
  Serial.print(I, 1);
  Serial.print(" ");
  Serial.print(cap, 0);
  Serial.print(" ");
  Serial.print(Wh, 2);
  Serial.print(" ");
  Serial.println(Vcc, 3);   
  cap_string=String(round(cap));
  disp_print(cap_string);
}

//----------Функция точного определения опорного напряжения для измерения напряжения на акуме-------
float readAnalog(int pin) {  
  // read multiple values and sort them to take the mode
  int sortedValues[NUM_READS];
  for (int i = 0; i < NUM_READS; i++) {
    delay(25);    
    int value = analogRead(pin);
    int j;
    if (value < sortedValues[0] || i == 0) {
      j = 0; //insert at first position
    }
    else {
      for (j = 1; j < i; j++) {
        if (sortedValues[j - 1] <= value && sortedValues[j] >= value) {
          // j is insert position
          break;
        }
      }
    }
    for (int k = i; k > j; k--) {
      // move all values higher than current reading up one position
      sortedValues[k] = sortedValues[k - 1];
    }
    sortedValues[j] = value; //insert current reading
  }
  //return scaled mode of 10 values
  float returnval = 0;
  for (int i = NUM_READS / 2 - 5; i < (NUM_READS / 2 + 5); i++) {
    returnval += sortedValues[i];
  }
  return returnval / 10;
}
//----------Функция точного определения опорного напряжения для измерения напряжения на акуме КОНЕЦ-------


//----------фильтр данных (для уменьшения шумов и разброса данных)-------
float readVcc() {
  // read multiple values and sort them to take the mode
  float sortedValues[NUM_READS];
  for (int i = 0; i < NUM_READS; i++) {
    float tmp = 0.0;
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    ADCSRA |= _BV(ADSC); // Start conversion
    delay(25);
    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;
    float value = (typVbg * 1023.0) / tmp;
    int j;
    if (value < sortedValues[0] || i == 0) {
      j = 0; //insert at first position
    }
    else {
      for (j = 1; j < i; j++) {
        if (sortedValues[j - 1] <= value && sortedValues[j] >= value) {
          // j is insert position
          break;
        }
      }
    }
    for (int k = i; k > j; k--) {
      // move all values higher than current reading up one position
      sortedValues[k] = sortedValues[k - 1];
    }
    sortedValues[j] = value; //insert current reading
  }
  //return scaled mode of 10 values
  float returnval = 0;
  for (int i = NUM_READS / 2 - 5; i < (NUM_READS / 2 + 5); i++) {
    returnval += sortedValues[i];
  }
  return returnval / 10;
}
//----------фильтр данных (для уменьшения шумов и разброса данных) КОНЕЦ-------

void disp_print(String x) {
  disp.point(POINT_OFF);
  switch (x.length()) {         //кароч тут измеряется длина строки и соотвествено выводится всё на дисплей
  case 1:
    disp.display(0,18);
    disp.display(1,18);
    disp.display(2,18);
    disp.display(3,x[0]- '0');
    break;
  case 2:
    disp.display(0,18);
    disp.display(1,18);
    disp.display(2,x[0]- '0');
    disp.display(3,x[1]- '0');
    break;
  case 3:
    disp.display(0,18);
    disp.display(1,x[0]- '0');
    disp.display(2,x[1]- '0');
    disp.display(3,x[2]- '0');
    break;
  }
}

 

Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

Где и что вы изменили?

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

Переставьте все функции типа readVCC, ReadAnalog и т.п. ВЫШЕ их первого использования и всё будет нормально.

Forvad
Offline
Зарегистрирован: 09.02.2016

хм .. перенес их между void setup() и void loop() ... и вправду заработало. Интересно, но ведь так не было :)

Большое спасибо

Forvad
Offline
Зарегистрирован: 09.02.2016

Yarik.Yar пишет:
Где и что вы изменили?

В последний раз попытался поменять 

109     Serial.print((millis() - testStart) / 3600000); // вместо 1000 - поставил 3600000

а изначально, это .. но при этих изменениях все работало 



018 byte relay_pin=3; // было 13
021 float Voff = 2.5; //  было 1.5
022 float R = 8.455; //было 124
059 tone(buzz_pin,1000,500); // было 200,500
099 tone(buzz_pin,1000,500); // и добавил эту строчку чтоб пищала пока не проснусь и не вытащу аккум и не поставлю на зарядку

вроде бы всё

 

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

Поменялась версия IDE. Или Вы обновили, или сама обновилась.

Правильно именно так (объявление выше использования), но старые версии IDE эту ошибку типа исправляли за Вас. А новые не исправляют.

Forvad
Offline
Зарегистрирован: 09.02.2016

ЕвгенийП пишет:

Поменялась версия IDE. Или Вы обновили, или сама обновилась.

я её обновил с 1.6.8 до 1.6.12 .. но уже после появления ошибки

Forvad
Offline
Зарегистрирован: 09.02.2016

прохоже проблема в руских буквах в пути до файла .ino

D:\Мои документы\Arduino\capacity_tester\capacity_tester.ino

Перекинул из "D:\мои документы\Arduino\" в чисто англоязычный путь и всё заработало в старом варианте ... когда функции readVCC и другие располагаются в конце.

 

Forvad
Offline
Зарегистрирован: 09.02.2016

Хочу добавить что бы после завершения теста аккум автоматом вставал на зарядку. Скажите можно такой зарядничек запитать от самой ардуины? или на платку зарядника нужно ставить свой БП, второе реле и коммутировать оба провода?

зы: извиняюсь за дикий "фотошоп" ... лень рисовать :)


 

Yurchanin
Offline
Зарегистрирован: 22.12.2016

От Ардуины запитывать никак нельзя! У нее выходной ток по цифровым пинам максимум 30-40 миллиАмпер. А плата для зарядки лития, изображенная на фото, заряжает током 1 Ампер. Так что для зарядки однозначно нужен внешний блок питания. Для этой цели отлично подойдет зарядное устройство для смартфона, которое дает на выходе 5В/1А. Тем более на плате зарядки имеется разъем microUSB. Только при подключении к общей схеме с Ардуино, необходимо будет соединить "земли" (общий провод, GND). То есть Ваш синий провод остается, а вот красный провод, идущий к Ардуино, убираем.

Yurchanin
Offline
Зарегистрирован: 22.12.2016

Посмотрел цикл видео у AlexGyver по литиевым аккумуляторам и собрал точно такое же устройство для проверки. Настроил под свои "железки" и протестировал один АКБ с Алика. Заявлено продавцом 4800 мАч, а по факту вышло всего 656 мАч. Ну да грех жаловаться, так как за 89 рублей другого и не ожидал. )) Даже спор открывать не стал.

Но дело не в этом. Подскажите, пожалуйста, как оставить функционал схемы, но выводить все на ЖК-дисплей 1602? В программировании я практически не разбираюсь. То есть общее представление имею, но программу написать или код оптимизировать, для меня "слабо". Есть желание собрать все как автономное устройство. Что-то типа iMax B6, только проще и более узкой специализации. 

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Yurchanin пишет:

Подскажите, пожалуйста, как оставить функционал схемы, но выводить все на ЖК-дисплей 1602?

Здесь на форуме есть замечательный проект от bodriy2014, ( http://srukami.inf.ua/testbat3.htm )  где весь подобный функционал давно реализован. Проект под экран 5110, но есть моды и под 1602:

Этот (1602 с I2C модулем) я брал у пользователя arthemy .

Этот делал сам на базе двух вышеуказанных (схемка здесь посложнее).

Yurchanin
Offline
Зарегистрирован: 22.12.2016

Спасибо большое! Буду изучать!

Forvad
Offline
Зарегистрирован: 09.02.2016

Yurchanin пишет:

От Ардуины запитывать никак нельзя! У нее выходной ток по цифровым пинам максимум 30-40 миллиАмпер. 

вот и меня сомнения глодали :) вдруг не потянет ... я тогда припаяюсь наверно к УСБ разъёму ардуинки, чтоб два питания не городить, и поставлю сдвоенное реле и буду перекидывать оба питающих провода

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Forvad пишет:

я тогда припаяюсь наверно к УСБ разъёму ардуинки, чтоб два питания не городить, и поставлю сдвоенное реле и буду перекидывать оба питающих провода

Вот только к компьютеру я ардуинку после таких модификаций не подключал бы...

Forvad
Offline
Зарегистрирован: 09.02.2016

tekagi пишет:

Вот только к компьютеру я ардуинку после таких модификаций не подключал бы...

 

сначала хотел написать всеобъемлющее слово "блин" :) 

... а потом подумалось а что такого случится? в момент программирования (скажем что-то поправить в скетче) измеряемого аккума стоять не будет .. и что? ну запитана платка зарядки можно подумать много она в простое съест. А при измерениях питать сию девайсину от компа у меня даже мысль не возникала :) всяко разно внешний БП, или пауэрбанк в мобильном варианте

 

tekagi
tekagi аватар
Offline
Зарегистрирован: 07.10.2016

Релюшки тоже желательно отключать, пятивольтовые на обмотку немалый ток берут. При заряде/измерении на такой девайс БП ампера на 2 надо. Если делать отдельным устройством - можно пару съёмных джамперов поставить, или дип-переключателей.

Forvad
Offline
Зарегистрирован: 09.02.2016

tekagi пишет:

Релюшки тоже желательно отключать, пятивольтовые на обмотку немалый ток берут

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