avatar_UriBas

Моргалка на Arduino. Этюды для начинающих.

Автор UriBas, 08 Март 2017 в 16:08

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

Dunkel

Цитата: iwizard7 от 27 Окт. 2017 в 15:52

Очень полезный  скетч, коэффициент у меня получился далек от заданного в скетче изначально

Только имейте в виду - в моих скетчах напряжение просто умножается на этот коэффициент, а в авторском скетче по другому:

float koeffU = 0.0276391555; //коэффициент делителя напряжения - подобрать опытным путем, чтобы отсечка срабатывала при Uots
float Uots1 =[b-b] Uots/koeffU*10[/b-b];

Так что, если используется авторский скетч, надо сделать одинаковые формулы в скетчах для калибровки и для моргалки.
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

iwizard7

Цитата: Dunkel от 27 Окт. 2017 в 17:16
Цитата: iwizard7 от 27 Окт. 2017 в 15:52

Очень полезный  скетч, коэффициент у меня получился далек от заданного в скетче изначально

Только имейте в виду - в моих скетчах напряжение просто умножается на этот коэффициент, а в авторском скетче по другому:

float koeffU = 0.0276391555; //коэффициент делителя напряжения - подобрать опытным путем, чтобы отсечка срабатывала при Uots
float Uots1 =[b-b] Uots/koeffU*10[/b-b];

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

Dunkel

Цитата: iwizard7 от 27 Окт. 2017 в 17:32

:facepalm: запутался совсем, вообщем думаю надо просто писать свой скетч и уже с ним разбираться

Самое правильное решение! Только так и можно разобраться.
Эта моргалка не готовое изделие, а полуфабрикат, который нужно настраивать и подгонять под себя.
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

Dunkel

Очень простая конструкция - никаких печатных плат и smd. Все, что нужно, это несколько радиодеталей, кусок провода, изолента и паяльник. Особых познаний в радиотехнике тоже не требуется, достаточно минимальных навыков пайки и умения отличить транзистор от резистора.

В качестве источника питания подойдет любой БП 18-20В. Я использовал несколько разных БП 19В от ноутбуков, замечательно работают. Ток заряда должен быть примерно 1/10 от фактической емкости АКБ. Для стартерных 40-60А/ч подойдет БП на 4-5А. Для мелких 7-12А/ч ток нужен около 1А, можно включить через китайскую понижайку с CC, либо сделать простейший ограничитель тока на LM317.

И самое главное - мозги, т.е. Ардуино. Я использую Pro Mini 328 5V, но можно взять и любой другой. Для Pro Mini не забываем про конвертер USB-UART, лучше взять CP2102.
Запитать МК можно либо через USB, либо от БП через понижайку или делитель. Резисторы для делителя нужно брать помощнее - 2-5Вт, номиналом 100-300 Ом и подбирать так, чтобы на МК было 7-9В.

Есть два варианта схемы - на P- и N-мосфете. Никаких принципиальных отличий между ними нет, работают одинаково. Различие только в способе измерения напряжения на АКБ, для N-мосфета это несколько сложнее - напряжение измеряется на двух участках схемы и потом вычитается одно из другого. Это сделано для того, чтобы не разрывать землю между БП и МК, т.е. обеспечить одинаковый потенциал земли БП и МК. В противном случае могут возникнуть неприятные сюрпризы при подключении USB.

Принцип работы - обычная моргалка с частотой импульсов около 35Гц и верхней отсечкой 14,4В.
Алгоритм адаптивный, длительность пачки импульсов и паузы изменяются в процессе работы, по достижению верхнего и нижнего порога соответственно.

После сборки необходимо сделать калибровку коэффициента делителя.
Сначала запустить скетч калибровки и подобрать коэффициент так, чтобы измеряемое напряжение соответствовало фактическому.
Потом вставить это значение в скетч моргалки.

ЗУ с P-мосфет:
Схема:
Спойлер



Скетч моргалки:
Спойлер

// 28/10/2017
// (c)dunkel
// ProMini328 5V 16Mhz, питание USB
// Pin13 - заряд, на затвор мосфета
// PinА0 - напряжение с делителя АКБ 510/2k

unsigned long time;
int zar = 30 ; //Пачка импульсов - заряд в сек
int raz = 100 ; //Пачка импульсов - пауза в 0.1сек
int imp = 14 ; //Импульс в мсек
int pause = 14 ; //Пауза в мсек
int n = zar * 1000 / (imp + pause) ; //Кол-во импульсов в пачке
float U14=14.4; // Напряжение отсечки 14.4В
float K0 = 0.002305; // Коэффициент делителя
float UK=0; //Контрольное напряжение перед зарядом (НРЦ)
float U0=0; //Напряжение АКБ
float Vcc = 0.0;
void setup() { 
  Serial.begin(9600);             
  pinMode(13, OUTPUT); // - на затвор мосфета
  digitalWrite(13, LOW);
}
void loop() {
  time = millis();
  U0=0;
  Vcc = 0.0;
  for (int j=1; j<=10; j++) {
    Vcc+= readVcc();
    U0+=analogRead(A0);  // 10 раз измеряем напряжение, потом усредняем
  }
U0 = U0 * K0; 
Vcc = Vcc/10;
U0 = U0*Vcc/5;
  UK = U0; // Напряжение НРЦ
  Serial.println(UK*1);  // *10 - масштаб графика
  if (UK >= U14) delay(10000) ; //Если НРЦ превысит 14,4 - пауза 10с
int flag = 0;
for (int i=0; i <= n; i++) { //Пачка импульсов длительностью zar
  digitalWrite(13, HIGH);
  delay(imp);                 //Импульс - заряд длительностью imp
  digitalWrite(13, LOW);
  delay(pause-10);               //Импульс - пауза длительностью pause //-10 на измерения Vcc
  U0=0; 
  Vcc = 0.0;
  for (int j=1; j<=10; j++) {
     Vcc+= readVcc();
     U0+=analogRead(A0); // 10 раз измеряем напряжение, потом усредняем
  }
  U0 = U0 * K0;
  Vcc = Vcc/10;
U0 = U0*Vcc/5;
if ( (millis()-time) >= 1000 ) {  // Выводим значение каждую сек.
Serial.println(U0*1);  // *10 - масштаб графика
  time = millis();
}
  if (U0 > U14) { //Касание 14,4В
      i = n; //Выходим из цикла - прерываем пачку импульсов
      raz = raz + 1; //Увеличиваем счетчик касаний 14,4В - увеличиваем паузу между пачками импульсов
      flag = 1;
   }
  }
 
  Serial.println(U0*1);  // *10 - масштаб графика
  for (int h=1; h <= raz; h++) { //Пачка импульсов - пауза длительностью raz
  delay(100-10); //-10 на измерения Vcc
  U0=0; 
  Vcc = 0.0;
 
  for (int j=1; j<=10; j++) {
    Vcc+= readVcc();
    U0+=analogRead(A0);  // 10 раз измеряем напряжение, потом усредняем
  }
  U0 = U0 * K0;
  Vcc = Vcc/10;
U0 = U0*Vcc/5;

if ( (millis()-time) >= 1000 ) {  // Выводим значение каждую сек.
Serial.println(U0*1);  // *10 - масштаб графика
  time = millis();
}
 
  if (U0 <= UK && flag == 1) h = raz ;// Если Напряжение ниже НРЦ и было касание 14.4 - заканчиваем паузу
  }
}

// Измерение Vcc
// https://github.com/tim4dev/arduino/blob/master/sensor-test/true_voltmeter/true_voltmeter.ino

float readVcc() {
  byte i;
  float result = 0.0;
  float tmp = 0.0;
  const float typVbg = 1.179; // 1.0 -- 1.2

// 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(1); // 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;
}

Скетч калибровки:
Спойлер

// 28/10/2017
// (c)dunkel
// ProMini328 5V 16Mhz, питание USB
// Pin13 - заряд, на затвор мосфета
// PinА0 - напряжение с делителя АКБ 510/2k

float U0=0;
float Vcc = 0.0;
float V = 0.0;

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

void loop() {

U0=0;
Vcc = 0.0;

delay(500);
 
  for (int j=1; j<=10; j++) {
    Vcc+= readVcc();
    U0+=analogRead(A0);
  }
 
U0 = U0 * 0.002305; 
Vcc = Vcc/10;
V = U0*Vcc/5;

  Serial.print("  U0  ");  Serial.print(U0);   
  Serial.print("  Vcc  ");  Serial.print(Vcc);   
  Serial.print("  V  ");  Serial.println(V); 
   
 

}


// https://github.com/tim4dev/arduino/blob/master/sensor-test/true_voltmeter/true_voltmeter.ino

float readVcc() {
  byte i;
  float result = 0.0;
  float tmp = 0.0;
  const float typVbg = 1.179; // 1.0 -- 1.2

// 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(1); // 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;
}

ЗУ с N-мосфет:
Схема:
Спойлер



Скетч моргалки:
Спойлер

// 30/10/2017
// (c)dunkel
// ProMini328 5V 16Mhz, питание USB
// Pin13 - заряд, на затвор мосфета
// PinА0 - напряжение с делителя ЗУ 700/3k
// PinА1 - напряжение с делителя Мосфет 700/3k

unsigned long time; // Измеряем время для выдачи значений для графика примерно каждую сек.
int zar = 30 ; //Пачка импульсов - заряд в сек
int raz = 100 ; //Пачка импульсов - пауза в 0.1сек
int imp = 14 ; //Импульс в мсек
int pause = 14 ; //Пауза в мсек
int n = zar * 1000 / (imp + pause) ; //Кол-во импульсов в пачке
float K0 = 0.00282; // Коэффициент делителя ЗУ 700/3k, питание от 5В
float K1 = 0.00288; // Коэффициент делителя Мосфет 700/3k, питание от 5В
float U14=14.4; // Напряжение отсечки 14.4В
float UK=0; //Контрольное напряжение перед зарядом (НРЦ)
float U=0; //Напряжение АКБ
float U0=0; //Напряжение ЗУ
float U1=0; //Напряжение на мосфете
float Vcc = 0.0; //Напряжение на контроллере
void setup() { 
  Serial.begin(9600);             
  pinMode(13, OUTPUT); // - на затвор мосфета
  digitalWrite(13, LOW);
}
void loop() {
  time = millis();
  U0=0;  U1=0;
  Vcc = 0.0;
  for (int j=1; j<=10; j++) {   // 10 раз измеряем напряжение, потом усредняем
    Vcc+= readVcc();
    U0+=analogRead(A0); U1+=analogRead(A1); 
  }
  U0 = U0 * K0;  U1 = U1 * K1;
  U = U0 - U1;
  Vcc = Vcc/10;
  U = U*Vcc/5;
  UK = U; // Напряжение НРЦ
  Serial.println(UK*1);  // *10 - масштаб графика
  if (UK >= U14) delay(10000) ; //Если НРЦ превысит 14,4 - пауза 10с
  int flag = 0;
  for (int i=0; i <= n; i++) { //Пачка импульсов длительностью zar
   digitalWrite(13, HIGH);
   delay(imp);                 //Импульс - заряд длительностью imp
   digitalWrite(13, LOW);
   delay(pause-10);               //Импульс - пауза длительностью pause //-10 на измерения Vcc
   U0=0;  U1=0;
   Vcc = 0.0; 
   for (int j=1; j<=10; j++) {  // 10 раз измеряем напряжение, потом усредняем
    Vcc+= readVcc();
    U0+=analogRead(A0); U1+=analogRead(A1);
   }
   U0 = U0 * K0;  U1 = U1 * K1;
   U = U0 - U1;
   Vcc = Vcc/10;
   U = U*Vcc/5;
   if ( (millis()-time) >= 1000 ) {  // Выводим значение каждую сек.
    Serial.println(U*1);  // *10 - масштаб графика
    time = millis();
   }
  if (U > U14) { //Касание 14,4В
      i = n; //Выходим из цикла - прерываем пачку импульсов
      raz = raz + 1; //Увеличиваем счетчик касаний 14,4В - увеличиваем паузу между пачками импульсов
      flag = 1;
   }
  }
  Serial.println(U*1);  // *10 - масштаб графика
  for (int h=1; h <= raz; h++) { //Пачка импульсов - пауза длительностью raz
   delay(100-10); //-10 на измерения Vcc
   U0=0;  U1=0;
   Vcc = 0.0;
   for (int j=1; j<=10; j++) {  // 10 раз измеряем напряжение, потом усредняем
     Vcc+= readVcc();
     U0+=analogRead(A0); U1+=analogRead(A1);
   }
   U0 = U0 * K0;  U1 = U1 * K1;
   U = U0 - U1;
   Vcc = Vcc/10;
   U = U*Vcc/5;
   if ( (millis()-time) >= 1000 ) {  // Выводим значение каждую сек.
    Serial.println(U*1);  // *10 - масштаб графика
    time = millis();
   }
   if (U <= UK && flag == 1) h = raz ; // Если Напряжение ниже НРЦ и было касание 14.4 - заканчиваем паузу
   }
}

// Измерение Vcc
// https://github.com/tim4dev/arduino/blob/master/sensor-test/true_voltmeter/true_voltmeter.ino

float readVcc() {
  byte i;
  float result = 0.0;
  float tmp = 0.0;
  const float typVbg = 1.179; // 1.0 -- 1.2

// 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(1); // 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;
}

Скетч калибровки:

Спойлер

// 30/10/2017
// (c)dunkel
// ProMini328 5V 16Mhz, питание USB
// Pin13 - заряд, на затвор мосфета
// PinА0 - напряжение с делителя ЗУ 700/3k
// PinА1 - напряжение с делителя Мосфет 700/3k

float U=0;
float U0=0;
float U1=0;

float Vcc = 0.0;

float V = 0.0;

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

void loop() {

U0=0;
U1=0;
U=0;
Vcc = 0.0;

delay(500);
 
  for (int j=1; j<=10; j++) {
    Vcc+= readVcc();
    U0+=analogRead(A0);
    U1+=analogRead(A1);
  }
 
U0 = U0 * 0.00282; 
U1 = U1 * 0.00288;
U = U0 - U1;
Vcc = Vcc/10;
V = U*Vcc/5;

  Serial.print("  U0  ");  Serial.print(U0);   
  Serial.print("  U1  ");    Serial.print(U1);   
  Serial.print("  U  "); Serial.print(U);
  Serial.print("  Vcc  ");  Serial.print(Vcc);   
        Serial.print("  V  ");  Serial.println(V); 
   
 

}


// https://github.com/tim4dev/arduino/blob/master/sensor-test/true_voltmeter/true_voltmeter.ino

float readVcc() {
  byte i;
  float result = 0.0;
  float tmp = 0.0;
  const float typVbg = 1.179; // 1.0 -- 1.2

// 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(1); // 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;
}

Для иллюстрации работы ЗУ небольшой отчет о попытке восстановления мертвой АКБ.
Итак, моргалка собрана по схеме с P-mosfet, из подручных материалов "на соплях".

Внешний вид:
Спойлер



Источник питания - БП 19,5В 3,3А,
Кандидат на восстановление - АРС 7а/ч, тестер показывает НРЦ  2,3В, т.е. труп. Но внутри ничего не гремит, так что шансы есть.
Pro Mini подключен к USB через конвертер USB-UART, от него же и запитан.

Сначала откалибруем моргалку. Для этого возьмем живую АКБ с НРЦ 12,93В.
Загружаем скетч калибровки, и подбираем коэффициент так, чтобы измеренное напряжение было 12,93В:

Спойлер



Напряжение немного скачет, но это не критично. Требуемая точность 0,1В.

Вставляем этот коэффициент в скетч моргалки, и запускаем:

Спойлер



Убеждаемся, что все работает.
Ток 3,3А слишком большой для 7а/ч, и АКБ сразу начинает подкипать. Так что прекращаем это издевательство и подключаем нашего покойника.
Для него 3,3А тоже слишком много, это делается исключительно с целью демонстрации работы ЗУ.
Не надо воспринимать это как инструкцию по восстановлению АКБ.
Посмотрим его НРЦ:

Спойлер



Под небольшой нагрузкой (делитель моргалки) НРЦ просел практически до 0. Т.е. пациент совсем труп.

Запускаем моргалку:

Спойлер



На удивление, труп реагирует вполне адекватно, так что попробуем немного позаряжать.

Через пару часов НРЦ слегка поднялся:

Спойлер



Самое время долить воды. Я долил по 15мл в банку, так чтобы над пластинами была вода. Пробки пока не закрываю, лишнее испарится.
Оставляем на ночь, пусть вода впитается.

На следующий день продолжаем процесс и наблюдаем всякие хаотичные графики:

Спойлер



Особого смысла в них нет, здоровые АКБ так себя не ведут. Но НРЦ все-таки понемногу поднимается:

Спойлер




Заодно решил попробовать другую программку для визуализации:

http://x-io.co.uk/serial-oscilloscope/

Вполне нормально работает, можно использовать как логгер:

Спойлер



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

Скетч раскачки:

Спойлер

// 28/10/2017
// (c)dunkel
// ProMini328 5V 16Mhz, питание USB
// Pin13 - заряд, на затвор мосфета
// PinА0 - напряжение с делителя АКБ 510/2k

float K0 = 0.002305; // Коэффициент делителя
float UK=0; //Контрольное напряжение перед зарядом (НРЦ)
float U0=0;
float Vcc = 0.0;

void setup() { 
  Serial.begin(9600);             
  pinMode(13, OUTPUT); // - на затвор мосфета
  digitalWrite(13, LOW);
}
void loop() {
 
  U0=0;
  Vcc = 0.0;
 
  for (int j=1; j<=10; j++) {
    Vcc+= readVcc();
    U0+=analogRead(A0);  // 10 раз измеряем напряжение, потом усредняем
  }

U0 = U0 * K0; 
Vcc = Vcc/10;
U0 = U0*Vcc/5;
 
  UK = U0; // Напряжение НРЦ
 
  Serial.println(UK);

  if (UK <= 12.0) {  //Раскачка
  for (int r=0; r < 10; r++) { //Пачка из 10 импульсов
  digitalWrite(13, HIGH);
  delay(5);                 //Импульс длительностью 5мс
  digitalWrite(13, LOW);
  delay(5);               //пауза
  }
  delay(100);
  }
 


}



// https://github.com/tim4dev/arduino/blob/master/sensor-test/true_voltmeter/true_voltmeter.ino

float readVcc() {
  byte i;
  float result = 0.0;
  float tmp = 0.0;
  const float typVbg = 1.179; // 1.0 -- 1.2

// 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(1); // 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;
}


Через несколько часов НРЦ заметно поднялся, включим опять моргалку.
График стал гораздо симпатичнее:

Спойлер



И вот на 5 день мы видим уже другую картинку:

Спойлер



Верхний порог 14,4В достигнут, пачки импульсов стали "иголками" - заряд повышенным током надо заканчивать.
Напомню, что до сих пор ток заряда был 0,5С вместо номинального 0,1С.
Для демонстрации перезаряда я продолжил заряжать повышенным током:

Спойлер



Видно, что импульсы начинают пробивать верхнюю границу, НРЦ падает.
АКБ при этом греется и кипит, т.е. ничего хорошего в этом нет.

Ограничивать ток будем очень простым способом, через  LM317:

Спойлер



Берем R=1,5 Ом, ток получается 1,25 / 1,5 = 0,83 А.

Собираем, теперь ЗУ выглядит так:

Спойлер



Включаем зарядку номинальным током, график получается не очень правильный:

Спойлер



Похоже одна банка не работает, тем не менее продолжаем зарядку и получаем такую картинку:

Спойлер



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

На этом я прервал процесс заряда, т.к. аккумулятор продолжал кипеть, а этого быть не должно.
Результат -  10,8В, т.е. получился 5-баночный аккум.
Вероятно из-за большого тока и перезаряда одна банка отвалилась.
А может она изначально такой была - не знаю.
Отсюда мораль - не стоит превышать номинальный зарядный ток.


Все это было написано для того, чтобы на живом примере продемонстрировать, что эта простое ЗУ, собранное на коленке из подручных материалов работает ничуть не хуже всяких Орионов и Кулонов.
А стоит на порядок дешевле. И собрать такую штуку может любой, кто умеет держать паяльник.

Спойлер


Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

Dunkel

Цитата: Яков93 от 31 Окт. 2017 в 22:44
Зачем создали новую тему если ее содержание полностью совпадает с существующей? Теперь что на каждый вариант моргалок на ардуино будем новую тему создавать? Если нет веских возражений я Ваше сообщение (весьма полезное) перенесу в уже существующую тему, а эту закрою.

Мне без разницы, только имейте в виду, что люди начинают читать тему с первого поста, а не с последнего.
А там в первом посте совсем другая конструкция. Боюсь, до этой зарядки мало кто дочитает.
Впрочем, это Ваше дело.
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

Vova_n

[user]Dunkel[/user],  Так прикрепите ссыль в теме про ардуино, в первом посту на вот этот ваш пост, в чём проблема то?  :bn:
Некоторые у себя в подписи прикрепляют ссылки на свои особо важные посты и опыты и таким образом они присутствуют везде где общался человек, любознательные тыкают и смотрят, а те кому ничего не интересно и не надо им побоку в любом случае.

iwizard7

Цитата: Dunkel от 31 Окт. 2017 в 20:32
Заодно решил попробовать другую программку для визуализации:

http://x-io.co.uk/serial-oscilloscope/

Вполне нормально работает, можно использовать как логгер:


А до этого какую программу использовали ?

Dunkel

Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

Яков93

Цитата: Vova_n от 01 Нояб. 2017 в 02:18
[user]Dunkel[/user],  Так прикрепите ссыль в теме про ардуино, в первом посту на вот этот ваш пост, в чём проблема то?  :bn:

Дал ссылку в первом посте этой темы на альтернативную конструкцию моргалки от Dunkel. Теперь никто мимо не пройдет.

iwizard7

Цитата: Dunkel от 01 Нояб. 2017 в 09:58
Цитата: iwizard7 от 01 Нояб. 2017 в 09:36

А до этого какую программу использовали ?

Ардуино.
Потестил немного Вашу моргалку, все вроде работает но иногда бывают какие-то аномалии.  Хотя аккумулятор (АКОМ 65Ah Ca/Ca) вроде вполне себе живой, стоит на машине и успешно ее заводит.



А это подключен неизвестный мне аккум 12v 4.5 Ah



Это продолжение его зарядки.



И дальше он же.



Вчера вечером залил в него воды, сегодня буду дальше пытать. Интересно что из этого получится.




Dunkel

[user]iwizard7[/user], Ардуиновский плоттер не умеет менять масштаб графиков, и чтобы разглядеть подробности, приходится вставлять в скетч масштабирующий коэффициент.
Serial oscilloscope в этом смысле гораздо лучше - позволяет на лету менять масштаб по вертикали/горизонтали.
Так что попробуйте, увидите больше деталей.
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

samogon318

#407
Без обид, но в скетче от [user]Dunkel[/user] творится хаос. Я только начал изучать программирование (если что assembler), но уже вижу что проц сильно загружен.
1. Во первых, чтобы задать частоту в 35 ГЦ для ардуино есть специальная библиотека с частотной модуляцией (если по датишу на проц, то там есть спец регистры, которые отвечают за частотную модуляцию вывода микроконтроллера).
2. В вашем коде повторяется запись
Спойлер

// 28/10/2017
// (c)dunkel
// ProMini328 5V 16Mhz, питание USB
// Pin13 - заряд, на затвор мосфета
// PinА0 - напряжение с делителя АКБ 510/2k

unsigned long time;
int zar = 30 ; //Пачка импульсов - заряд в сек
int raz = 100 ; //Пачка импульсов - пауза в 0.1сек
int imp = 14 ; //Импульс в мсек
int pause = 14 ; //Пауза в мсек
int n = zar * 1000 / (imp + pause) ; //Кол-во импульсов в пачке
float U14=14.4; // Напряжение отсечки 14.4В
float K0 = 0.002305; // Коэффициент делителя
float UK=0; //Контрольное напряжение перед зарядом (НРЦ)
float U0=0; //Напряжение АКБ
float Vcc = 0.0;
void setup() { 
  Serial.begin(9600);             
  pinMode(13, OUTPUT); // - на затвор мосфета
  digitalWrite(13, LOW);
}
void loop() {
  time = millis();
U0=0;
  Vcc = 0.0;
  for (int j=1; j<=10; j++) {
    Vcc+= readVcc();
    U0+=analogRead(A0);  // 10 раз измеряем напряжение, потом усредняем
  }
U0 = U0 * K0; 
Vcc = Vcc/10;
U0 = U0*Vcc/5;

  UK = U0; // Напряжение НРЦ
  Serial.println(UK*1);  // *10 - масштаб графика
  if (UK >= U14) delay(10000) ; //Если НРЦ превысит 14,4 - пауза 10с
int flag = 0;
for (int i=0; i <= n; i++) { //Пачка импульсов длительностью zar
  digitalWrite(13, HIGH);
  delay(imp);                 //Импульс - заряд длительностью imp
  digitalWrite(13, LOW);
  delay(pause-10);               //Импульс - пауза длительностью pause //-10 на измерения Vcc
  U0=0; 
  Vcc = 0.0;
  for (int j=1; j<=10; j++) {
     Vcc+= readVcc();
     U0+=analogRead(A0); // 10 раз измеряем напряжение, потом усредняем
  }
  U0 = U0 * K0;
  Vcc = Vcc/10;
U0 = U0*Vcc/5;

if ( (millis()-time) >= 1000 ) {  // Выводим значение каждую сек.
Serial.println(U0*1);  // *10 - масштаб графика
  time = millis();
}
  if (U0 > U14) { //Касание 14,4В
      i = n; //Выходим из цикла - прерываем пачку импульсов
      raz = raz + 1; //Увеличиваем счетчик касаний 14,4В - увеличиваем паузу между пачками импульсов
      flag = 1;
   }
  }
 
  Serial.println(U0*1);  // *10 - масштаб графика
  for (int h=1; h <= raz; h++) { //Пачка импульсов - пауза длительностью raz
  delay(100-10); //-10 на измерения Vcc
U0=0; 
  Vcc = 0.0;
 
  for (int j=1; j<=10; j++) {
    Vcc+= readVcc();
    U0+=analogRead(A0);  // 10 раз измеряем напряжение, потом усредняем
  }
  U0 = U0 * K0;
  Vcc = Vcc/10;
U0 = U0*Vcc/5;


if ( (millis()-time) >= 1000 ) {  // Выводим значение каждую сек.
Serial.println(U0*1);  // *10 - масштаб графика
  time = millis();
}
 
  if (U0 <= UK && flag == 1) h = raz ;// Если Напряжение ниже НРЦ и было касание 14.4 - заканчиваем паузу
  }
}

// Измерение Vcc
// https://github.com/tim4dev/arduino/blob/master/sensor-test/true_voltmeter/true_voltmeter.ino

float readVcc() {
  byte i;
  float result = 0.0;
  float tmp = 0.0;
  const float typVbg = 1.179; // 1.0 -- 1.2

// 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(1); // 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;
}
здесь можно обозначить как некотурую функцию, записать ее один раз, а потом вставлять только как функцию.
3. Что в скетче означает запись  delay(100-10); //-10 на измерения Vcc тут проц тупо отсчетает 90 и пойдет далее делать программу. Так не проще написать в скобках 90?
Есть еще немного нюансов, но в целом направление верное. Не обижайтесь что тут включил умняка, просто хочу чтоб проэкт розвивался и в правильном русле. Понимаю что здесь в основном все самоучки, но программировать надо уметь так чтоб устройство работало четко и безотказно. Было бы здорово если б кто-то оптимизировал Ваш код.
Кстати респект и уважение за найденную инфу по измерению Vcc

UstAlexei

#408
Хаос тут в другом.
Счет идет в числах с плавающей запятой! Поэтому происходят лишние операции умножения, деления. Вы ради интереса посмотрите сколько времени процессор на них тратит.
Предлагаю не заморачиваться и задавать уставки напряжений в квантах. Это упростит код.
Насчет (100-10)- компилятор не дурак и при компиляции сам напишет 90.

iwizard7

И еще один интересный момент. Если нахожу коэффициент делителя в скетче калибровки, допустим 0.002242 для 12.60 В, переношу его в рабочий скетч для p-fet, и заливаю в ардуино про мини, то при просмотре через монитор последовательного порта скетч пишет в монитор что на аккуме не те же 12.60 В а уже 13.40.

Dunkel

Цитата: iwizard7 от 05 Нояб. 2017 в 08:22
И еще один интересный момент. Если нахожу коэффициент делителя в скетче калибровки, допустим 0.002242 для 12.60 В, переношу его в рабочий скетч для p-fet, и заливаю в ардуино про мини, то при просмотре через монитор последовательного порта скетч пишет в монитор что на аккуме не те же 12.60 В а уже 13.40.

Во всех скетчах процедура измерения напряжения одинаковая.
Напряжение может измениться из-за подключения БП.

Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

Dunkel

Цитата: samogon318 от 04 Нояб. 2017 в 23:46
Было бы здорово если б кто-то оптимизировал Ваш код.
Кстати респект и уважение за найденную инфу по измерению Vcc

Коллеги, я не возражаю против оптимизации, модификации и т.п.  Для того и выложил все исходники.
Только мне совершенно непонятна цель оптимизации загрузки процессора. Он и так большую часть времени простаивает.

А вот совершенствование алгоритма работы самой моргалки было бы действительно интересно.
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

iwizard7

Цитата: Dunkel от 05 Нояб. 2017 в 09:22
Цитата: iwizard7 от 05 Нояб. 2017 в 08:22
И еще один интересный момент. Если нахожу коэффициент делителя в скетче калибровки, допустим 0.002242 для 12.60 В, переношу его в рабочий скетч для p-fet, и заливаю в ардуино про мини, то при просмотре через монитор последовательного порта скетч пишет в монитор что на аккуме не те же 12.60 В а уже 13.40.

Во всех скетчах процедура измерения напряжения одинаковая.
Напряжение может измениться из-за подключения БП.

Не подключал блок питания не при калибровке ни про залитии скетча. Даже USB порт не менял.
Это то меня и удивило.

Dunkel

Цитата: iwizard7 от 05 Нояб. 2017 в 10:08

Не подключал блок питания не при калибровке ни про залитии скетча. Даже USB порт не менял.
Это то меня и удивило.

Не подключал БП в розетку или к моргалке?
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/