дешёвый параллельный измеритель ёмкости 18650

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Приветствую.

Делаю простой измеритель ёмкости элементов 18650 по старой статье Измеритель ёмкости аккумуляторов на Arduino.

У меня задача - получить простое и дешёвое устройство для быстрой оценки остаточной ёмкости элементов от старых ноутбучных батарей и, соответственно, отбраковки негодных.
Поэтому сделал некоторые изменения: взял экранчик Futaba M204SD02A (программируется так же, как и HD4478, только знакогенератор немного другой), поставил N-канальный MOSFET вместо реле (всего 5мОм падение), сделал 4 канала вместо одного. Транзисторы 50N024 взял из старой материнки (стояли в синтезаторе напряжения процессора), резисторы 500к выпаял из компьютерного блока питания (стояли в цепях разрядки высоковольтных конденсаторов), экранчик Futaba взял из блока автобусной навигации BIN-02, резисторы 4 Ом сделал из нихромовой проволоки от старого утюга (собираюсь потом спиральки залить в формочки с алебастром, чтобы улучшить отвод тепла). Из покупного - только сама Arduino pro mini.

Один канал отладил, работает. По аналогии сделал остальные, теперь скетч вешается через некоторое время. Не представляю, как его отлаживать, потому прошу помощи.
scheme.png

Скетч тут:
Код:
// include the library code:
#include <LiquidCrystal.h>
#include <OneWire.h>
OneWire ds(10);

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
//               RS , E , D4 , D5 , D6 , D7
//int i, j, n, m;


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

byte Bat_pin[4] = { 0, 1, 2, 3 }; //пин нагрузки (аналоговый!!!!)
#define  buzz_gnd 6 //динамик земля
#define  buzz_pin 7 //динамик сигнал
#define  butt_pin 8 //состояние кнопки
#define  butt_gnd 9 //земля кнопки
byte  relay_pin[4] = { 13, 10, 9, 8 }; //пин нагрузки ячеек
//byte disp_gnd = 6; //земля дисплея
//byte CLK = 7;  //пин дисплея
//byte DIO = 8;  //пин дисплея
//byte disp_vcc = 10; //питание дисплея
//TM1637 disp(CLK,DIO);   //обозвать дисплей disp

uint32_t sec = 0;
int timeHours = 0;
int timeMins = 0;


//const float typVbg = 1.095; // 1.0 -- 1.2
const float typVbg = 1.122; // 1.0 -- 1.2
const float Voff = 2.5; // напряжение отсечки (для Li-ion=2.5 В, для LiPo=3.0 В)
const float Vdetect = 0.5; // напряжение при котором считаем, что вставлен аккумулятор
const float Von = 3; // напряжение, при котором можно стартовать заряд (меньше 3В нет смысла насиловать аккум.)
const float R[4] = { 4, 4, 4, 4 }; //сопротивление нагрузки
float I[4];
float cap[4] = { 0, 0, 0, 0 }; //начальная ёмкость
float V[4];
float Vcc;
float Wh[4] = { 0, 0, 0, 0 };
unsigned long prevMillis[4];
unsigned long testStart[4];

String cap_string;
String V_string;
byte State[4] = { 0, 0, 0, 0 }; // Состояние ячейки 1: 0 - нет аккума, 1 - разряд, 2 - заряд, 3 - стоп
byte cell; // номер ячейки для цикла
/////////////////////



////////////////////////////////////////////////////////////////////
// initialize display
// 3rd parameter is a string containing some needed russian characters from "БГДЖЗИЙЛПУФЦЧШЩЬЪЫЭЮЯ"
// up to 16 letters, but recommended not more than 8, anyway, i can use 16 on my lcd :)
////////////////////////////////////////////////////////////////////
static byte addon_letters[16];
void init_rus(const char* letters_use )
{
  // custom characters
  static byte letters[][8]   = {
    { B11111, B10000, B10000, B11111, B10001, B10001, B11111, B00000 },//Б
    { B11111, B10000, B10000, B10000, B10000, B10000, B10000, B00000 },//Г
    {  B00000, B01111, B01001, B01001, B01001, B01001, B11111, B10001 },//Д
    {  B01010, B00000, B11111, B10000, B11110, B10000, B10000, B11111 }, //Ё
    { B10101, B10101, B10101, B01110, B10101, B10101, B10101, B00000 },//Ж
    { B01110, B10001, B00001, B00110, B00001, B10001, B01110, B00000 },//З
    { B10001, B10001, B10011, B10101, B11001, B10001, B10001, B00000 },//И
    { B10101, B10101, B10011, B10101, B11001, B10001, B10001, B00000 },//Й
    { B00111, B01001, B10001, B10001, B10001, B10001, B10001, B00000 },//Л
    { B11111, B10001, B10001, B10001, B10001, B10001, B10001, B00000 },//П
    { B10001, B10001, B10001, B01111, B00001, B10001, B01110, B00000 },//У
    {  B00000, B01110, B10101, B10101, B10101, B01110, B00100, B00100 },//Ф
    { B10001, B10001, B10001, B10001, B10001, B10001, B11111, B00001 },//Ц
    { B10001, B10001, B10001, B01111, B00001, B00001, B00001, B00000 },//Ч
    {  B00000, B10101, B10101, B10101, B10101, B10101, B10101, B11111 },//Ш
    { B10101, B10101, B10101, B10101, B10101, B10101, B11111, B00001 },//Щ
    {  B00000, B10000, B10000, B10000, B11110, B10001, B10001, B11110 },//Ь
    { B11000, B01000, B01110, B01001, B01001, B01001, B01110, B00000 },//Ъ
    { B10001, B10001, B10001, B11101, B10101, B10101, B11101, B00000 },//Ы
    {  B00000, B11110, B00001, B00001, B01111, B00001, B00001, B11110 },//Э
    { B10111, B10101, B10101, B11101, B10101, B10101, B10111, B00000 },//Ю
    { B01111, B10001, B10001, B01111, B10001, B10001, B10001, B00000 },//Я
  };
  static char chars[] = {'Б', 'Г', 'Д', 'Ё', 'Ж', 'З', 'И', 'Й', 'Л', 'П', 'У', 'Ф', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ъ', 'Ы', 'Э', 'Ю', 'Я'};
  static byte empty[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  int index = 0, cl = sizeof(chars) / sizeof(char), i, j, symb;
  memset(addon_letters, 0, sizeof(addon_letters));
  for ( j = 0; j < strlen(letters_use) && j < 16; j++ )
    lcd.createChar(j, empty);

  for ( j = 0; j < strlen(letters_use) && j < 16; j++ )
  {
    symb = -1;
    for ( i = 0; i < cl; i++ ) if ( chars[i] == letters_use[j] ) {
        symb = i;
        addon_letters[index] = letters_use[j];
        break;
      }
    if ( symb != -1 ) {
      lcd.createChar(index, letters[symb]);
      index++;
    }
  }
}
////////////////////////////////////////////////////////////////////
// print russian chars
////////////////////////////////////////////////////////////////////
void print_rus(char *str) {
  static char rus_letters[] =   {'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я' };
  static char trans_letters[] = {'A', 0x80, 'B', 0x92, 0x81, 'E', 0xCB, 0x82, 0x83, 0x84, 0x85, 'K', 0x86, 'M', 'H', 'O', 0x87, 'P', 'C', 'T', 0x88, 0xA2, 'X', 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x62, 0x8F, 0xAC, 0xAD};
  int lcount = sizeof(rus_letters) / sizeof(char), i, j;
  for ( i = 0; i < strlen(str); i++ )
  {
    if ( byte(str[i]) == 208 ) continue; // 208 ignore
    int found = 0;
    for (j = 0; j < 16; j++) if ( addon_letters[j] != 0 && byte(str[i]) == byte(addon_letters[j]) ) {
        lcd.write(j);
        found = 1;
        break;
      }
    if (!found) for (j = 0; j < lcount; j++) if ( byte(str[i]) == byte(rus_letters[j]) ) {
          lcd.write(trans_letters[j]);
          found = 1;
          break;
        }
    if (!found) lcd.write(byte(str[i]));
  }
}
void print_rus(int x, int y, char *str) {
  lcd.setCursor(x, y);
  print_rus(str);
}
////////////////////////////////////////////////////////////////////



static byte degree[8] = { B01100, B10010, B10010, B01100, B00000, B00000, B00000, B00000 };// Значок градуса

void setup() {
  lcd.begin(20, 4); // Задаём режим работы индикатора: 4 строки по 20 символов

  lcd.command(1);  //очистка дисплея  команда 4-4-1
  lcd.command(12);  // включить дисплей
  // Команды не нужны, работает без них

  init_rus("ДЭШЩФЬЁ"); // Загружаем нужные символы в программируемые ячейки (максимум 8 символов)
  //  lcd.createChar(7, degree);
  //  print_rus(0, 0, "ТЕМПЕРАТУРА:20.6 С");
  //  print_rus(0, 1, "1234567890()+-={}[]/");
  print_rus(0, 1, "ПАРАЛЛЕЛЬНЫЙ");
  print_rus(0, 2, "РАЗРЯДНИК");
  //  lcd.setCursor(19, 3);
  //  lcd.write(0xa4);
        delay(1000);
             lcd.clear();

  pinMode(relay_pin, OUTPUT);  //пин реле как выход
  digitalWrite(relay_pin, LOW); //выключить мосфет

  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, 200, 500);
  Serial.println("Test is launched...");
  /*    Serial.print("s");
      Serial.print(" ");
      Serial.print("V");
      Serial.print(" ");
      Serial.print("mA");
      Serial.print(" ");
      Serial.print("mAh");
      Serial.print(" ");
      Serial.print("Wh");
      Serial.print(" ");
      Serial.println("Vcc"); */
  Serial.println("s\tV\tmA\tmAh\tWh\tVcc");
  for (int cell  = 0; cell  < 4; cell++) {
  digitalWrite(relay_pin[cell], LOW); // Состояние Low - нагрузка отключена
  testStart[cell] = millis();  //время начала теста в системе отсчёта ардуины
  prevMillis[cell] = millis();  //время первого шага
  }


}

void loop() {
/*  //-----------------
  byte data[2];
  ds.reset();
  ds.write(0xCC);
  ds.write(0x44);
  //delay(750);
  ds.reset();
  ds.write(0xCC);
  ds.write(0xBE);
  data[0] = ds.read();
  data[1] = ds.read();
  int Temp = (data[1] << 8) + data[0];
  Temp = Temp >> 4;
  //                lcd.setCursor(12,0);
  //                lcd.print(Temp);
  //                lcd.write(7);
  //                lcd.print("C  ");
  //-----------------
*/
  //////////////////////////////////
  Vcc = readVcc(); //хитрое считывание опорного напряжения (функция readVcc() находится ниже)

  for (int cell  = 0; cell  < 4; cell++) {

    V[cell] = (readAnalog(Bat_pin[cell]) * Vcc) / 1023.000; //считывание напряжения АКБ
    I[cell] = V[cell] / R[cell]; //расчет тока по закону Ома, в Амперах
    /*
      cap += I * (millis() - prevMillis) / 3600000 * 1000; //расчет емкости АКБ в мАч
      Wh += I * V * (millis() - prevMillis) / 3600000; //расчет емкости АКБ в ВтЧ
      prevMillis = millis();  */

//    sendData(); // отправка данных и вывод на дисплей

//////////////////////////////////
  Serial.print((millis() - testStart[cell]) / 1000);
  Serial.print("\t");
  Serial.print(V[cell], 3);
  Serial.print("\t");
  Serial.print(I[cell] * 1000, 1);
  Serial.print("\t");
  Serial.print(cap[cell], 0);
  Serial.print("\t");
  Serial.print(Wh[cell], 2);
  Serial.print("\t");
  Serial.println(Vcc, 3);
  cap_string = String(round(cap[cell]));
  lcd.setCursor(7, cell);
  switch (cap_string.length()) {         // В зависимости от длины строки дополняем спереди пробелами
    case 1:
      lcd.print("   ");
      break;
    case 2:
      lcd.print("  ");
      break;
    case 3:
      lcd.print(" ");
      break;
  }
  lcd.print(cap_string);
  print_rus("mAh");
//////////////////////

    V_string = String(V[cell], 3);
    lcd.setCursor(0, cell); // 0 строка соответствует 0 ячейке (нумеруем с нуля)
    lcd.print(V_string);
    print_rus("В");

    switch (State[cell]) {         // Переход на нужный режим
      case 0:                   // Состояние без аккумулятора. Рисуем "_" и ждём появления напряжения > 3В
        lcd.setCursor(14, cell);
        lcd.print("_");
        if ( V[cell] > Von ) {
          State[cell] = 1; // Если напряжение стало >3В, значит вставили аккумулятор, переключаем режим на 1 - разрядка
          digitalWrite(relay_pin[cell], HIGH); // Включить состояние High - нагрузка включена
          testStart[cell] = millis();  // Установить время начала теста
          prevMillis[cell] = millis();  //время первого шага
          cap[cell] = 0; // Сбрасываем начальную ёмкость мАч
          Wh[cell] = 0; // Сбрасываем начальную ёмкость мВтч
          //        lcd.setCursor(7, 0);
          //        lcd.print("      "); //  Подчищаем место для мАч
          lcd.setCursor(14, cell);
          lcd.write(0x19); //  Рисуем значок "v"
        }
        break;
      case 1: // Состояние разрядки.
        lcd.setCursor(14, cell);
        lcd.write(0x19); //  Рисуем значок "v"
        cap[cell] += I[cell] * (millis() - prevMillis[cell]) / 3600000 * 1000; //расчет емкости АКБ в мАч
        Wh[cell] += I[cell] * V[cell] * (millis() - prevMillis[cell]) / 3600000; //расчет емкости АКБ в ВтЧ
        prevMillis[cell] = millis();
        sec = (millis() - testStart[cell]) / 1000ul;
        timeHours = (sec / 3600ul) % 24;
        timeMins = (sec % 3600ul) / 60ul;
        lcd.setCursor(15, cell);
        if (timeHours < 10)      lcd.write("0"); // "0"
        lcd.print(timeHours); // часы
        lcd.write(":"); // Рисуем значок ":"
        if (timeMins < 10)      lcd.write("0"); // "0"
        lcd.print(timeMins); // минуты

        if (V[cell] < Voff) {
          State[cell] = 3; // Если напряжение стало <2.5В, значит аккумулятор разрядился, переключаем режим на 3 - стоп
          digitalWrite(relay_pin[cell], LOW); // Включить состояние Low - нагрузка отключена
          lcd.setCursor(14, cell);
          lcd.write(0x16); //  Рисуем значок "#"
        }
        break;
      case 2: // Состояние зарядки. Пока не реализовано. Заглушка
        lcd.setCursor(14, cell);
        lcd.write(0x18); // Рисуем значок "^"
        break;
      case 3: // Состояние остановки. Ждём вытаскивания аккумулятора V = 0
        lcd.setCursor(14, cell);
        lcd.write(0x16); //  Рисуем значок "#"

        if ( V[cell] < Vdetect ) {
          State[cell] = 0; // Если напряжение стало <0.5В, считаемЮ, что аккумулятор вынули, переключаем режим на 0 - нет аккумулятора
          lcd.setCursor(14, cell);
          lcd.print("_");
          //        digitalWrite(relay_pin, LOW); // Включить состояние Low - нагрузка отключена
        }
        break;
    }

    //отладка
    //  lcd.setCursor(0, 1);
    //  lcd.print(State1);


  }



  /*  if (V < Voff) { //выключение нагрузки при достижении минимального напряжения
      digitalWrite(relay_pin, HIGH);  //разорвать цепь (отключить акб от нагрузки)
      Serial.println("Test is done");  //тест закончен
    //    print_rus(0, 0, "ТЕСТ ОКОНЧЕН");

      for (int i = 0; i < 5; i++) { //выполнить 5 раз
        tone(buzz_pin, 200, 500); //пищать на 3 пин частотой 100 герц 500 миллисекунд
              disp_print(cap_string);
        delay(1000);
        //      disp.clearDisplay();
        delay(500);
      }

      while (2 > 1) {  //бесконечный цикл, чтобы loop() не перезапустился + моргаем результатом!
              disp_print(cap_string);
        lcd.command(0b00101100);  //команда 4-4-6  установка яркости 100%
        delay(1000);
        //      disp.clearDisplay();
        lcd.command(0b00101111);  //команда 4-4-6  установка яркости 25%
        delay(500);
      }
    }*/


}
////////////////////////
/*
void sendData() {       //функция, которая посылает данные в порт
  Serial.print((millis() - testStart[cell]) / 1000);
  Serial.print("\t");
  Serial.print(V[cell], 3);
  Serial.print("\t");
  Serial.print(I[cell] * 1000, 1);
  Serial.print("\t");
  Serial.print(cap[cell], 0);
  Serial.print("\t");
  Serial.print(Wh[cell], 2);
  Serial.print("\t");
  Serial.println(Vcc, 3);
  cap_string = String(round(cap[cell]));
  lcd.setCursor(7, cell);
  switch (cap_string.length()) {         //кароч тут измеряется длина строки и соотвествено выводится всё на дисплей
    case 1:
      lcd.print("   ");
      break;
    case 2:
      lcd.print("  ");
      break;
    case 3:
      lcd.print(" ");
      break;
  }
  lcd.print(cap_string);
  print_rus("mAh");
}
*/
//----------Функция точного определения опорного напряжения для измерения напряжения на акуме-------
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;
}
//----------фильтр данных (для уменьшения шумов и разброса данных) КОНЕЦ-------
20200602_080932.jpg

Вот такая картинка после некоторого времени работы.
 
Изменено:

PiratFox

★★★★★✩✩
13 Фев 2020
1,695
472
@Sonya, а нельзя ли полную картину? Желательно видео. А то, судя по скетчу, Вы в область данных залезли... В Протеус загрузить не пробовали?
 

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
@Sonya, а нельзя ли полную картину? Желательно видео. А то, судя по скетчу, Вы в область данных залезли... В Протеус загрузить не пробовали?
Хотел было снять, но там долго ждать, первый раз оно час нормально проработало.


Нашёл один косяк: три раза объявил cell (причём по-разному). Убрал, стало стабильнее.
Выделил вывод часов в отдельную функцию, получил более жёсткие глюки.
Есть подозрение, что это связано с функцией деления при выводе времени, т.к. при комментировании этого кода глюки уходят.
Код:
  sec = (millis() - testStart[cell]) / 1000ul;
  timeHours = (sec / 3600ul) % 24;
  timeMins = (sec % 3600ul) / 60ul;
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,695
472
Так в Протеус не пробовали? А то у меня матюкается чего-то...
 

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Так в Протеус не пробовали? А то у меня матюкается чего-то...
Не, симулятор я пока не освоил.

PS: Нашёл ещё один косяк: забыл объявить остальные пины на выход:
Код:
    pinMode(Load_pin[cell], OUTPUT);  //пин реле как выход
Сунул этот кусок кода в ещё один цикл в setup.
Уже час крутится, пока полёт нормальный.
 

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Похоже, глюк был аппаратным: несмотря на наличие конденсатора по питанию, arduino подглючивала от USB порта. Запитал от отдельного источника питания, всю ночь проработало нормально.
 

Wan-Derer

★★★★★✩✩
Команда форума
31 Июл 2018
2,005
406
Москва
wan-derer.ru
@Sonya, затворы транзисторов лучше притянуть к земле через резисторы 100 кОм. Иначе они могут случайно открываться при отсутствии питания на Ардуино.
 
  • Лойс +1
Реакции: Sonya

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Тоже верно. Ещё нужен резистор на 500к параллельно аккумулятору, т.к. при отсутствии аккумулятора, напряжение скачет, а должен быть ноль для нормальной работы детектора наличия аккумулятора.
 
Изменено:

PiratFox

★★★★★✩✩
13 Фев 2020
1,695
472
Товарищи инженеры, мне немного непонятно вот что. Зачем в цепях затворов полевиков резисторы аж по 10 килоом? Это же много, что увеличивает время переключения, и транзисторы греться от этого будут. В идеале там, конечно, драйверы затвора нужны, но можно и без них. Как по мне, так хотя бы по килоому, или немного меньше.
 
Изменено:

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Товарищи инженеры, мне немного непонятно вот что. Зачем в цепях затворов полевиков резисторы аж по 10 килоом? Это же много, что увеличивает время переключения, и они греться от этого будут. В идеале там, конечно, драйверы затвора нужны, но можно и без них. Как по мне, так хотя бы по килоому, или немного меньше.
Можно и без них, но не вижу разницы: MOSFET управляется напряжением, а не током. А ёмкость затвора ничтожна, чтобы наш резистор оказал какое-либо влияиние. Можно провести простой эксперимент - подать тестером напряжение на затвор, транзистор так и останется включенным после отключения щупов, сопротивление затвора огромно, и 10к не сыграют никакой разницы.

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

PiratFox

★★★★★✩✩
13 Фев 2020
1,695
472
Можно провести простой эксперимент - подать тестером напряжение на затвор, транзистор так и останется включенным
Ну так от тестера максимум 2ma. Я сталкивася с управлением подобными транзисторами . Там в импульсе амперы нужны. Очень короткий импульс. Иначе греются, собаки...

А ёмкость затвора ничтожна
Ну, это смотря на каком времени. Про время закрывания - открывания забыли? Ни хочу ни с кем спорить, но пока я драйверы не применил в затвор так дела не было.
 

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Ну так от тестера максимум 2ma. Я сталкивася с управлением подобными транзисторами . Там в импульсе амперы нужны. Очень короткий импульс. Иначе греются, собаки...
Это вы их в импульсном режиме используете, а тут транзистор открыт. И в открытом состоянии сопротивление сток-исток всего 5 мОм. Сейчас потрогал - холодные.
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,695
472
@Sonya, ага, я чуть не прав! Я именно про импульсный режим! Возникали проблемы в этом режиме с перегревом транзисторов, но это решаемо.
 

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Так а что, в этом режиме транзюки не греются? Интересное что - то у Вас происходит.... Может, я чего - то и не понимаю...
Греются в момент переключения. Уже который пост мусолим один вопрос... Тут в схеме транзистор вместо реле используется. Нагрев в открытом состоянии ничтожный, да и время переключения при включении нагрузки ничтожно, чтобы транзистор успел нагреться.


Конечно, по-хорошему, нужно было делать ШИМ, цеплять мощный транзистор на радиаторе, ставить шунт для измерения тока. И такие схемы уже есть готовые. Не забываем про название темы - дешёвый измеритель.

PS: По теме: скетч живёт вторые сутки, разрядил уже кучу аккумуляторов, результат в сравнении с imax b6 меньше на 100-200мА, меня это вполне устраивает. Объясняется это просто - imax при приближении к 3В, снижает ток и высасывает весь заряд, у меня же в скетче разрядный ток в конце разряда больше, и после отключения нагрузки, на элементе 3.3В, значит некоторый заряд ещё остался.

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

АндрейБонд

✩✩✩✩✩✩✩
2 Мар 2022
1
0
Такой вопрос, а можно ли сделать так чтобы ардуино запоминал результат, а при подключении к компу их переносил на пк, ну или сразу чтобы в пк записывались значения?
 

Sonya

✩✩✩✩✩✩✩
2 Июн 2020
38
3
www.cctvsp.ru
Избыточное цитирование. Отредактируй или сообщение будет удалено
Такой вопрос, а можно ли сделать так чтобы ардуино запоминал результат, а при подключении к компу их переносил на пк, ну или сразу чтобы в пк записывались значения?
UART свободен, сделайте туда вывод и считывайте на компе. Для сохранения использовать библиотеку eeprom, я до неё так и не добрался.

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