Medidor de teste de carga e capacidade de bateria de íons de lítio DIY 18650 usando Arduino

Tempo de leitura: 9 minutes

Existem vários Baterias de lítio disponível no mercado com maiores opções de capacidade. Não há entanto, como todos os sabemos, como as baterias de título pré-candidato a cargas, as descarregadas ou as armas de uma maneira específica para prolongar sua vida útil. Neste projeto, explore um circuito que desça até a bateria completa e faça o resultado de quanta capacidade a bateria possui. Além disso, é uma mansão de identificações com o derrota ou as ruínas das baterias, mesmo baterias com reivindicações de capacidade falsificada. Este projeto terá como segundas opções e recursos que são úteis para testar uma bateria –

  • Dois botões para definir a corrente
  • Um OLED O visor mostrará o resultado e a interface do usuário
  • Um termistor para detectar a temperatura da bateria

Componentes necessários para o teste de capacidade da bateria de construção

Os seguintes componentes são necessários para tornar este testador de capacidade da bateria:

  • Arduino Nano
  • SSD1306 Tela OLED de 0,96”
  • LM358 Op-Amp
  • IRLZ44N MOSFET
  • Resistor de 0,5R 5Watt (para carga)
  • Bateria de íon de lítio 18650 – para testes
  • 10K NTC – Para obter a temperatura da bateria
  • Resistor 1M
  • Resistor 10K
  • Resistor 4.7K x2
  • 100nF x2 Capacitor
  • 220uF Capacitor
  • Interruptores táteis – 2 peças
  • Conector DC Barrel
  • Um monte de fios
  • Placa Universal  (PCB)

Diagrama do circuito do testador da capacidade da bateria

Esquema completo para a construção de um 18650 Testador de capacidade é dado abaixo

Este testador de capacidade circuito consiste em 4 partes

  • Circuito de carga de corrente constante
  • Seção Medição da bateria
  • Seção Temperatura da bateria
  • Seção de interface do usuário

Todas essas seções são explicadas abaixo :

Circuito de carga de corrente constante

O principal componente deste projeto é Amplificador duplo LM358. LM358 é um amplificador duplo em um único pacote.  No entanto, neste projeto, apenas um op-amp é necessário. A saída PWM do Arduino. Pin 3 está conectado ao pino não invertido do primeiro amplificador operacional. O PWM é filtrado através de um filtro passa-baixo para obter uma tensão analógica equivalente. Visto que a entrada Inverting está agindo como feedback para o amplificador operacional que está conectado entre o IRFZ44N MOSFET pino de origem e o resistor de derivação 0.5R.

Este op-amp, R4, e o MOSFET constrói um circuito de carga de corrente constante. Quando ajustamos a tensão no pino de entrada que não inverte, o op-amp liga o MOSFET e tenta obter a mesma tensão no R4. A tensão aparece devido à lei ohms, à medida que a corrente flui através do resistor, uma queda de tensão deve aparecer. Então agora podemos controlar a corrente através do resistor de carga (0.5R) alterando a largura do pulso do sinal PWM.

Seção de medição de tensão da bateria 

A tensão da bateria é medida pela entrada analógica do Arduino alfinete A0. Dois capacitores. C1 e C2 são usados para filtrar os ruídos provenientes do circuito de carga de corrente constante que pode degradar o desempenho da conversão do ADC.

Seção de temperatura da bateria

A temperatura da bateria foi medida usando um 10K Termistor NTC. A resistência do termistor muda com a temperatura. Como este é um termistor NTC, quando a temperatura aumenta, a resistência diminui.

Por essa característica do NTC, adicionar resistência em série e criar um divisor de tensão pode efetivamente converter a diferença de temperatura em termos de alterações na tensão de saída desse divisor. A tensão de saída do divisor é lida pela entrada analógica do Arduino alfinete A1, podemos calcular a temperatura em tempo real da bateria.

Seção de interface do usuário

O circuito da interface do usuário consiste em dois botões e um visor I2C OLED de 0,96 “. O botão Para cima e para baixo é aumentar ou diminuir a largura do pulso PWM. R5 e R6 são resistores de tração para os botões de pressão para cima e para baixo. O terceiro botão (RST) é usado para redefinir o Arduino

Como funciona o testador de capacidade da bateria?

A teoria é baseada na comparação de tensão do invertido (pin-2) e o não invertido (pino-3) entradas do Op-Amp, configuradas como um amplificador de unidade. Quando você define a tensão aplicada à entrada que não inverte ajustando o sinal PWM, a saída do Op-Amp abre a porta do MOSFET. À medida que o MOSFET liga, a corrente passa por R1, o que cria uma queda de tensão, que fornece feedback negativo ao Op-Amp. Ele controla o MOSFET de tal maneira que as tensões em suas entradas invertidas e não invertidas sejam iguais. Portanto, a corrente através do resistor de carga é proporcional à tensão na entrada não invertida do Op-Amp. O sinal PWM do Arduino é filtrado usando um circuito de filtro passa-baixo (R3 e C3).

Capacidade da bateria(mAh) = Corrente(I) em mA x Hora(T) em Horas

Para calcular a capacidade da bateria (mAh) usando a equação acima, precisamos conhecer a corrente em mA e o tempo em Hora. O circuito projetado é um circuito de carga de corrente constante, portanto a corrente de descarga permanece constante durante todo o período de teste. A corrente de descarga pode ser ajustada pressionando o botão Para cima e para baixo. A duração do tempo é medida usando um timer no código do Arduino.

Solda dos componentes no painel Perf

Agora, como esse circuito consiste em uma bateria, decidimos soldar todos os componentes na placa universal, como mostrado abaixo.

Programação de Arduino para o testador de bateria

Depois de soldar os componentes no painel perf, vamos programar o Arduino Nano para testar a capacidade da bateria usando as leituras de tempo e corrente. O código completo pode ser encontrado no final do documento. Aqui estamos explicando o código completo linha por linha.

Então, como de costume, inicie o código incluindo todos os arquivos da biblioteca necessários. Aqui JC_Button.h biblioteca é usada para ler os estados dos botões e Adafruit_SSD1306.h A biblioteca é usada para imprimir as leituras no visor OLED. Ambas as bibliotecas podem ser instaladas no gerenciador de bibliotecas do Arduino IDE.

#include<JC_Button.h>
#include <Adafruit_SSD1306.h>

Em seguida, nas próximas linhas, defina todas as variáveis usadas neste código

int ThermistorPin = A1;
int Vo;
float R1 = 10000;
float logR2, R2, T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

A próxima linha de código é usada para definir a tensão de referência. O Vcc é a variável mais importante neste projeto para detectar a tensão da bateria. Para definir o Vcc, primeiro conecte o Arduino à fonte de energia externa de 7 a 12 volts. Em seguida, meça a tensão do pino Arduino 5V usando o Multímetro. Em seguida, defina o valor de Vcc neste código.

float Vcc = 5.04 ; // Voltage of Arduino 5V pin ( Mesured by Multimeter after connecting external 9V Supply )
const int Current [] = {0,70,100,190,350,400,500,620,700,830,910,1000};
const int PWM_RES [] = {0, 1, 2, 4, 8, 9, 12, 15, 17, 20, 22, 24};

Medindo a diferença de tensão entre R4 avaliar a corrente usando a fórmula:

V = I X R
So, I = V/R
Let, I = 100mA/0.1A, and R4 = 0.5R
So required voltage = 0.1 x 0.5 = 0.05V

Portanto, defina um valor PWM para obter o pino Op-Amp de entrada de tensão 3 para atingir a tensão através de R4. É assim que é possível obter um conjunto adequado de PWM para a corrente de saída relacionada.

int ThermistorPin = A1;
int Vo;
float R1 = 10000;
float logR2, R2, T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

Podemos usar uma equação que aproxima a temperatura da curva de resposta do termistor para calcular a temperatura. Por exemplo, a equação de Steinhart-Hart amplamente usada é mostrada abaixo

1/T=A+B*ln(R)+C*(ln(R))^3

Pode ser derivado usando dados medidos de resistência à temperatura. Usaremos a equação do parâmetro Beta (ou B) mais simples mostrada abaixo. Embora não seja tão preciso quanto a equação de Steinhart-Hart, ainda fornece bons resultados em uma faixa de temperatura mais estreita.

1/T=1/T0+1/B*ln(R/R0)

A variável T é a temperatura ambiente em Kelvin, T0 é geralmente a temperatura ambiente, também em Kelvin (25°C = 298,15K), B é a constante beta, R é a resistência do termistor na temperatura ambiente (igual a Rt acima), e R0 é a resistência do termistor na temperatura T0. Os valores para T0, B e R0 podem ser encontrados na folha de dados do fabricante. Você pode calcular o valor de R conforme descrito anteriormente para Rt.

Se a tensão da fonte do divisor de tensão e Vref forem iguais, você não precisa saber R0 ou encontrar R para calcular a temperatura. Lembre-se de que você pode escrever a equação para a resistência do termistor em termos da proporção dos valores ADC

R=R0*((adcMax/adcVal)-1)

então

1/T=1/T0+1/B*ln(R0*((adcMax/adcVal)-1)/R0) R0 cancels out, which leaves:
1/T=1/T0+1/B*ln((adcMax/adcVal)–1)

Faça o recíproco do resultado para obter a temperatura em Kelvin. Por exemplo, suponha que um circuito divisor de tensão termistor esteja conectado a um ADC de 10 bits. A constante beta para o termistor é 3380, a resistência do termistor (R0) a 25°C é 10K ohms e o ADC retorna um valor de 366.

1/T=1/298.15+1/3380*ln((1023/366)-1)
1/T=0.003527
T = 283.52K – 273.15K = 10.37°C

Isso se refletiu ainda mais na função de detecção de temperatura –

void temp() {

       Vo = analogRead(ThermistorPin);
       R2 = R1 * (1023.0 / (float)Vo - 1.0);
       logR2 = log(R2);
       T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
       T = T - 273.15;
}

Na função de loop, os estados do botão são lidos corretamente no início. Sempre que o botão é pressionado, a corrente aumenta ou diminui. Enquanto pressiona o botão por 1000ms, a contagem regressiva do tempo é iniciada.

void loop() {
  UP_Button.read();
  Down_Button.read();
  if (UP_Button.wasReleased() && l < 11 && calc == false) {
      l=l+1;
  }
  if (Down_Button.wasReleased() && l > 0 && calc == false) {
      l=l-1;
  }
  if (UP_Button.pressedFor (1000) && calc == false) {
      analogWrite(PWM_Pin,PWM_RES[l]);
      digitalWrite(Buzzer, HIGH);
      delay(1500);
      digitalWrite(Buzzer, LOW);
      timerInterrupt();
  }
}

 

Testando o testador de capacidade da bateria

Agora, como tudo está conectado no local e o Arduino programado para calcular a capacidade da bateria, vamos conectar uma bateria e testar seu desempenho. Todas as leituras, como corrente de descarga, capacidade da bateria, etc., serão exibidas no display OLED.

Bem, este projeto pode ser construído usando um PCB para um desempenho ideal e resultados precisos. O vídeo de trabalho completo e o código completo são fornecidos abaixo. Se você tiver dúvidas ou sugestões relacionadas a este projeto, você pode colocá-las na seção de comentários ou em nosso fórum.

 

Código

#include <JC_Button.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int ThermistorPin = A1;
int Vo;
float R1 = 10000;
float logR2, R2, T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
const int Current [] = {0,70,100,190,350,400,500,620,700,830,910,1000};
const int PWM_RES [] = {0, 1, 2, 4, 8, 9, 12, 15, 17, 20, 22, 24};
int l = 0;
const float Low_BAT_level = 3.4;
const byte PWM_Pin = 3;
const byte Buzzer = 9;
const int BAT_Pin = A0;
int PWM_Value = 0;
unsigned long Capacity = 0;
int ADC_Value = 0;
float Vcc = 5.04 ; // Voltage of Arduino 5V pin ( Mesured by Multimeter after connecting external 9V Supply )
float BAT_Voltage = 0;
float sample =0;
byte Hour = 0, Minute = 0, Second = 0;
bool calc = false, Done = false;
Button UP_Button(11, 25, false, true);
Button Down_Button(12, 25, false, true);

void setup () {
  Serial.begin(9600);
  pinMode(PWM_Pin, OUTPUT);
  pinMode(Buzzer, OUTPUT);
  analogWrite(PWM_Pin, PWM_RES[l]);
  UP_Button.begin();
  Down_Button.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(WHITE);
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(2,15);
  display.print("Adj Curr:");
  display.setCursor(2,40);
  display.print("UP   Down:");
  display.print("0");
  display.display();  
}
//************************* End of Setup function *******************************
void loop() {
  UP_Button.read();
  Down_Button.read();
 if (UP_Button.wasReleased() && l < 11 && calc == false)
 {
  l=l+1;
  display.clearDisplay();
  display.setCursor(2,25);
  display.print("Curr:");  
  display.print(String(Current[l])+"mA");
  display.display(); 
 }
 if (Down_Button.wasReleased() && l > 0 && calc == false)
 {  
  l=l-1;
  display.clearDisplay();
  display.setCursor(2,25);
  display.print("Curr:");  
  display.print(String(Current[l])+"mA");
  display.display(); 
 }
 if (UP_Button.pressedFor (1000) && calc == false)
 {
  analogWrite(PWM_Pin,PWM_RES[l]);
  digitalWrite(Buzzer, HIGH);
  delay(1500);
  digitalWrite(Buzzer, LOW);
  display.clearDisplay();
  timerInterrupt();  
 }
}
//************************* End of Loop function *******************************
void timerInterrupt(){
  calc = true;
  while (Done == false)  {
     Second ++;
    if (Second == 60)  {
      Second = 0;
      Minute ++;     
    }
    if (Minute == 60)  {
      Minute = 0;
      Hour ++;
    }
 //************ Measuring Battery Voltage ***********
  for(int i=0;i< 100;i++)
  {
   sample=sample+analogRead(BAT_Pin); //read the Battery voltage
   delay (2);
  }
  sample=sample/100;
  BAT_Voltage = sample * (Vcc/ 1024.0);
  temp();
 //*********************************************
    display.clearDisplay();
    display.setTextSize(2);
    display.setCursor(20,5);
    display.print(String(Hour) + ":" + String(Minute) + ":" + String(Second));
    display.setTextSize(1);
    display.setCursor(0,25);
    display.print("Disch Curr: ");  
    display.print(String(Current[l])+"mA");
    display.setCursor(2,40);  
    display.print("Bat:" + String(BAT_Voltage)+"V" );
    display.setCursor(63,40);
    display.print("Temp:"+String(T,1));
    display.setCursor(116,35);
    display.print(".");
    display.setCursor(122,40);
    display.print("C");
    Capacity =  (Hour * 3600) + (Minute * 60) + Second;
    Capacity = (Capacity * Current[l]) / 3600;
    display.setCursor(2, 55);
    display.print("Capacity:" + String(Capacity) + "mAh");
    display.display();
    if (BAT_Voltage < Low_BAT_level)
    {
      Capacity =  (Hour * 3600) + (Minute * 60) + Second;
      Capacity = (Capacity * Current[l]) / 3600;
      display.clearDisplay();
      display.setTextSize(2);     
      display.setCursor(2,15);    
      display.print("Capacity:");
      display.setCursor(2,40); 
      display.print(String(Capacity) + "mAh");
      display.display();
      Done = true;
      l = 0;
      analogWrite(PWM_Pin, PWM_RES[l]);
      digitalWrite(Buzzer, HIGH);
      delay(100);
      digitalWrite(Buzzer, LOW);
      delay(100);
      digitalWrite(Buzzer, HIGH);
      delay(100);
      digitalWrite(Buzzer, LOW);
      delay(100);
    }
       delay(1000);
  }   
}
    
void temp()
{
   Vo = analogRead(ThermistorPin);
   R2 = R1 * (1023.0 / (float)Vo - 1.0);
   logR2 = log(R2);
   T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
   T = T - 273.15;
}