Testeur de capacité de batterie simple sur Arduino

Récemment, j'ai commencé à remarquer que mon smartphone commençait à se décharger plus rapidement. La recherche du logiciel «dévoreur» n'a pas apporté d'énergie fruitière, j'ai donc commencé à me demander s'il était temps de remplacer la batterie. Mais il n'y avait aucune certitude absolue qu'il n'y avait aucune raison pour la batterie. Par conséquent, avant de commander une nouvelle batterie, j'ai décidé d'essayer de mesurer la capacité réelle de l'ancienne. Pour ce faire, il a été décidé d'assembler un simple compteur de capacité de batterie, d'autant plus que cette idée est née depuis longtemps - il y a tellement de piles et d'accumulateurs qui nous entourent dans la vie quotidienne, et ce serait bien de pouvoir les tester de temps en temps.



L'idée même qui sous-tend le fonctionnement de l'appareil est extrêmement simple: il y a une batterie chargée et une charge sous forme de résistance, il suffit de mesurer le courant, la tension et le temps pendant la décharge de la batterie, et selon les données obtenues, de calculer sa capacité. En principe, vous pouvez le faire avec un voltmètre et un ampèremètre, mais rester assis sur les appareils pendant plusieurs heures est un plaisir douteux, il est donc beaucoup plus facile et plus précis de le faire à l'aide de l'enregistreur de données. J'ai utilisé la plate-forme Arduino Uno en tant que registraire.

1. Régime

Il n'y a aucun problème avec la mesure de la tension et du temps dans Arduino - il y a un ADC, mais vous avez besoin d'un shunt pour mesurer le courant. J'ai eu l'idée d'utiliser la résistance de charge elle-même comme shunt. Autrement dit, en connaissant la tension et en ayant préalablement mesuré la résistance, nous pouvons toujours calculer le courant. Par conséquent, la version la plus simple du circuit consistera uniquement en une charge et une batterie, avec une connexion à l'entrée analogique d'Arduino. Mais il serait bien de prévoir un délestage lorsque la tension de seuil sur la batterie est atteinte (pour Li-Ion c'est généralement 2,5-3V). Par conséquent, j'ai fourni dans le circuit un relais contrôlé par la broche numérique 7 à travers un transistor. La version finale du circuit dans la figure ci-dessous.



J'ai placé tous les éléments du circuit sur un morceau de la planche à pain, qui est installé directement sur Uno. Comme charge, j'ai utilisé une spirale en fil nichrome de 0,5 mm d'épaisseur avec une résistance d'environ 3 ohms. Cela donne une valeur calculée du courant de décharge de 0,9 à 1,2 A.



2. Mesure du courant

Comme mentionné ci-dessus, le courant est calculé en fonction de la tension sur la bobine et de sa résistance. Mais il vaut la peine de considérer que la spirale chauffe, et la résistance du nichrome dépend à peu près de la température. Pour compenser l'erreur, j'ai simplement supprimé la caractéristique volt-ampère de la spirale en utilisant une alimentation de laboratoire et en la laissant se réchauffer avant chaque mesure. Il a ensuite dérivé l'équation de la ligne de tendance dans Excel (le graphique ci-dessous), ce qui donne une dépendance assez précise de i (u) en tenant compte du chauffage. On peut voir que la ligne n'est pas droite.



3. Mesure de tension

Étant donné que la précision de ce testeur dépend directement de la précision de la mesure de tension, j'ai décidé d'y porter une attention particulière. D'autres articles ont mentionné à plusieurs reprises la méthode qui vous permet de mesurer la tension le plus précisément avec les contrôleurs Atmega. Je ne répéterai que brièvement - l'essentiel est de déterminer la tension de référence interne au moyen du contrôleur lui-même. J'ai utilisé les matériaux de cet article.

4. Le programme

Code n'a rien de compliqué:

Texte du programme
#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;
}




Toutes les 5 secondes, les données sur le temps, la tension de la batterie, le courant de décharge, la capacité de courant en mAh et Wh, ainsi que la tension d'alimentation sont transmises au port série. Le courant est calculé par la fonction obtenue au paragraphe 2. Lorsque la tension de seuil Voff est atteinte, le test est terminé.
Le seul point, à mon avis, intéressant dans le code que je voudrais souligner est l'utilisation d'un filtre numérique. Le fait est qu'à la lecture de la tension, les valeurs «dansent» inévitablement de haut en bas. Au début, j'ai essayé de réduire cet effet en prenant simplement 100 mesures en 5 secondes et en prenant la moyenne. Mais le résultat ne m'a toujours pas satisfait. Au cours de la recherche , je suis tombé sur unfiltre logiciel. Il fonctionne de manière similaire, mais au lieu de faire la moyenne, il trie les 100 valeurs de mesure dans l'ordre croissant, sélectionne le 10 central et calcule la moyenne d'entre elles. Le résultat m'a impressionné - les fluctuations de mesure ont complètement cessé. J'ai décidé de l'utiliser pour mesurer la tension de référence interne (fonction readVcc dans le code).

5. Résultats Les

données du moniteur de port série sont importées dans Excel en quelques clics et se présentent comme suit:



Ensuite, il est facile de construire un graphique de décharge de la batterie:



Dans le cas de mon Nexus 5, la capacité de la batterie BL-T9 revendiquée est de 2300 mAh. Mesuré par moi - 2040 mAh avec une décharge jusqu'à 2,5 V. En réalité, le contrôleur ne permet guère à la batterie de s'asseoir à une tension aussi basse, très probablement une valeur de seuil de 3V. La capacité dans ce cas est de 1960 mAh. Un an et demi de service téléphonique a entraîné une baisse de capacité d'environ 15%. Avec l'achat d'une nouvelle batterie, il a été décidé de reporter.
Avec l'aide de ce testeur, plusieurs autres batteries Li-Ion ont déjà été déchargées. Les résultats semblent très réalistes. La capacité mesurée des batteries neuves coïncide avec celle déclarée avec un écart inférieur à 2%.
Ce testeur convient également aux batteries à doigts à hydrure métallique. Le courant de décharge dans ce cas sera d'environ 400 mA.

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


All Articles