Testador simples de capacidade da bateria no Arduino

Recentemente, comecei a perceber que meu smartphone começou a descarregar mais rapidamente. A busca pelo software “devourer” não trouxe energia para as frutas, então comecei a me perguntar se era hora de trocar a bateria. Mas não havia certeza absoluta de que não havia razão para a bateria. Portanto, antes de encomendar uma nova bateria, decidi tentar medir a capacidade real da antiga. Para fazer isso, decidiu-se montar um medidor simples de capacidade da bateria, especialmente porque essa idéia existe há muito tempo - há tantas baterias e acumuladores ao nosso redor na vida cotidiana, e seria bom poder testá-los de vez em quando.



A própria ideia subjacente à operação do dispositivo é extremamente simples: há uma bateria carregada e uma carga na forma de um resistor, você só precisa medir a corrente, tensão e tempo durante a descarga da bateria e, de acordo com os dados obtidos, calcular sua capacidade. Em princípio, você pode usar um voltímetro e um amperímetro, mas ficar sentado nos dispositivos por várias horas é um prazer duvidoso, por isso é muito mais fácil e preciso fazer isso usando o registrador de dados. Eu usei a plataforma Arduino Uno como tal registrador.

1. Esquema

Não há problemas com a medição de tensão e tempo no Arduino - existe um ADC, mas você precisa de uma derivação para medir a corrente. Tive a ideia de usar o próprio resistor de carga como derivação. Ou seja, conhecendo a tensão e medindo previamente a resistência, sempre podemos calcular a corrente. Portanto, a versão mais simples do circuito consistirá apenas de uma carga e uma bateria, com uma conexão à entrada analógica do Arduino. Mas seria bom fornecer uma redução de carga quando a tensão limite da bateria for atingida (para Li-Ion isso geralmente é de 2,5 a 3V). Portanto, eu forneci no circuito um relé controlado pelo pino digital 7 através de um transistor. A versão final do circuito na figura abaixo.



Coloquei todos os elementos do circuito em um pedaço da tábua de pão, que é instalada diretamente no Uno. Como carga, usei uma espiral de fio nicrômico de 0,5 mm de espessura com uma resistência de cerca de 3 ohms. Isso fornece um valor calculado da corrente de descarga de 0,9-1,2A.



2. Medição de corrente

Como mencionado acima, a corrente é calculada com base na tensão na bobina e em sua resistência. Mas vale a pena considerar que a espiral esquenta, e a resistência do nicrromo é praticamente dependente da temperatura. Para compensar o erro, simplesmente removi a característica de volt-ampère da espiral usando uma fonte de alimentação de laboratório e deixando-a aquecer antes de cada medição. Em seguida, ele derivou a equação da linha de tendência no Excel (o gráfico abaixo), que fornece uma dependência bastante precisa de i (u) levando em consideração o aquecimento. Pode-se ver que a linha não é reta.



3. Medição de tensão

Como a precisão deste testador depende diretamente da precisão da medição de tensão, decidi prestar atenção especial a isso. Outros artigos mencionaram repetidamente o método que permite medir a tensão com mais precisão com os controladores Atmega. Vou repetir apenas brevemente - a essência é determinar a tensão de referência interna por meio do próprio controlador. Eu usei os materiais neste artigo.

4. O programa

Code não é nada complicado:

Texto do programa
#define A_PIN 1
#define NUM_READS 100
#define pinRelay 7

const float typVbg = 1.095; // 1.0 -- 1.2
float Voff = 2.5; //  
float I;
float cap = 0;
float V;
float Vcc;
float Wh = 0;
unsigned long prevMillis;
unsigned long testStart;

void setup() {
  Serial.begin(9600);
  pinMode(pinRelay, OUTPUT);
  Serial.println("Press any key to start the test...");
  while (Serial.available() == 0) {
  }
  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");
  digitalWrite(pinRelay, HIGH);
  testStart = millis();
  prevMillis = millis();
}

void loop() {
  Vcc = readVcc(); //  
  V = (readAnalog(A_PIN) * Vcc) / 1023.000; //  
  if (V > 0.01) I = -13.1 * V * V + 344.3 * V + 23.2; //    
  else I=0;
  cap += (I * (millis() - prevMillis) / 3600000); //    
  Wh += I * V * (millis() - prevMillis) / 3600000000; //    
  prevMillis = millis();
  sendData(); //     
  if (V < Voff) { //     
    digitalWrite(pinRelay, LOW);
    Serial.println("Test is done");
    while (2 > 1) {
    }
  }
}

void sendData() {
  Serial.print((millis() - testStart) / 1000);
  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);
}


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;
}




A cada 5 segundos, os dados de tempo, tensão da bateria, corrente de descarga, capacidade de corrente em mAh e Wh, bem como a tensão de alimentação são transmitidos para a porta serial. A corrente é calculada pela função obtida no parágrafo 2. Quando a tensão limite Voff é atingida, o teste para.
O único, na minha opinião, ponto interessante no código que eu destacaria é o uso de um filtro digital. O fato é que, ao ler a tensão, os valores inevitavelmente "dançam" para cima e para baixo. No começo, tentei reduzir esse efeito simplesmente fazendo 100 medições em 5 segundos e medindo a média. Mas o resultado ainda não me satisfez. No decorrer da busca me deparei com umfiltro de software. Funciona de maneira semelhante, mas, em vez de calcular a média, classifica todos os 100 valores de medição em ordem crescente, seleciona o 10 central e calcula a média deles. O resultado me impressionou - as flutuações da medição pararam completamente. Decidi usá-lo para medir a tensão de referência interna (função readVcc no código).

5. Resultados Os

dados do monitor da porta serial são importados para o Excel em apenas alguns cliques e têm a seguinte aparência:



Em seguida, é fácil criar um gráfico de descarga da bateria:



No caso do meu Nexus 5, a capacidade da bateria reivindicada BL-T9 é de 2300 mAh. Medido por mim - 2040 mAh com uma descarga de até 2,5 V. Na realidade, o controlador dificilmente permite que a bateria fique com uma tensão tão baixa, provavelmente um valor limite de 3V. A capacidade neste caso é de 1960 mAh. Um ano e meio de serviço telefônico levou a um rebaixamento de aproximadamente 15% da capacidade. Com a compra de uma bateria nova, foi decidido adiar.
Com a ajuda deste testador, várias outras baterias de íon de lítio já foram descarregadas. Os resultados parecem muito realistas. A capacidade medida das pilhas novas coincide com a declarada com um desvio inferior a 2%.
Este testador também é adequado para baterias digitais de hidreto de metal. A corrente de descarga neste caso será de cerca de 400 mA.

Source: https://habr.com/ru/post/pt389105/


All Articles