Penguji kapasitas baterai sederhana pada Arduino

Baru-baru ini, saya mulai memperhatikan bahwa ponsel cerdas saya mulai mengeluarkan lebih cepat. Pencarian untuk perangkat lunak "melahap" tidak membawa energi buah, jadi saya mulai bertanya-tanya apakah sudah waktunya untuk mengganti baterai. Tetapi tidak ada kepastian absolut bahwa tidak ada alasan untuk baterai. Karena itu, sebelum memesan baterai baru, saya memutuskan untuk mencoba mengukur kapasitas sebenarnya dari yang lama. Untuk melakukan ini, diputuskan untuk merakit meter kapasitas baterai sederhana, terutama karena ide ini telah menetas untuk waktu yang lama - ada begitu banyak baterai dan akumulator di sekitar kita dalam kehidupan sehari-hari, dan akan menyenangkan untuk dapat mengujinya dari waktu ke waktu.



Gagasan yang mendasari operasi perangkat ini sangat sederhana: ada baterai yang diisi dan beban dalam bentuk resistor, Anda hanya perlu mengukur arus, tegangan dan waktu selama pengeluaran baterai, dan menurut data yang diperoleh, hitung kapasitasnya. Pada prinsipnya, Anda dapat melakukannya dengan voltmeter dan ammeter, tetapi duduk di perangkat selama beberapa jam adalah kesenangan yang meragukan, sehingga jauh lebih mudah dan lebih akurat untuk melakukan ini menggunakan data logger. Saya menggunakan platform Arduino Uno sebagai pendaftar.

1. Skema

Tidak ada masalah dengan pengukuran tegangan dan waktu di Arduino - ada ADC, tetapi Anda memerlukan shunt untuk mengukur arus. Saya mendapat ide untuk menggunakan resistor beban itu sendiri sebagai shunt. Artinya, mengetahui tegangan di atasnya dan setelah sebelumnya mengukur resistansi, kita selalu dapat menghitung arus. Oleh karena itu, versi paling sederhana dari rangkaian hanya akan terdiri dari beban dan baterai, dengan koneksi ke input analog Arduino. Tapi alangkah baiknya untuk menyediakan pelepasan beban setelah mencapai ambang tegangan pada baterai (untuk Li-Ion ini biasanya 2,5-3V). Oleh karena itu, saya menyediakan rangkaian relay yang dikendalikan oleh pin digital 7 melalui transistor. Versi terakhir dari sirkuit pada gambar di bawah ini.



Saya menempatkan semua elemen sirkuit pada sepotong papan tempat memotong roti, yang dipasang langsung di Uno. Sebagai beban, saya menggunakan spiral kawat nichrome setebal 0,5 mm dengan resistansi sekitar 3 ohm. Ini memberikan nilai yang dihitung dari arus pelepasan 0,9-1,2A.



2. Pengukuran arus

Seperti disebutkan di atas, arus dihitung berdasarkan tegangan pada koil dan hambatannya. Tetapi perlu dipertimbangkan bahwa spiral memanas, dan resistensi nichrome sangat tergantung pada suhu. Untuk mengkompensasi kesalahan, saya hanya mengambil karakteristik volt-ampere dari spiral menggunakan catu daya laboratorium dan membiarkannya memanas sebelum setiap pengukuran. Kemudian ia menurunkan persamaan garis tren di Excel (grafik di bawah), yang memberikan ketergantungan yang cukup akurat tentang i (u) dengan mempertimbangkan pemanasan. Dapat dilihat bahwa garis tidak lurus.



3. Pengukuran tegangan

Karena keakuratan tester ini secara langsung tergantung pada keakuratan pengukuran tegangan, saya memutuskan untuk memberikan perhatian khusus pada ini. Artikel lain telah berulang kali menyebutkan metode yang memungkinkan Anda mengukur tegangan paling akurat dengan pengontrol Atmega. Saya akan mengulangi hanya sebentar - intinya adalah untuk menentukan tegangan referensi internal dengan menggunakan controller itu sendiri. Saya menggunakan materi dalam artikel ini .

4. Program

Code tidak rumit:

Teks program
#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;
}




Setiap 5 detik, data tepat waktu, tegangan baterai, arus keluar, kapasitas saat ini dalam mAh dan Wh, serta tegangan suplai ditransmisikan ke port serial. Arus dihitung dengan fungsi yang diperoleh pada paragraf 2. Ketika tegangan ambang Voff tercapai, tes diakhiri.
Satu-satunya, menurut pendapat saya, titik menarik dalam kode yang saya pilih adalah penggunaan filter digital. Faktanya adalah ketika membaca voltase, nilainya pasti β€œmenari” naik turun. Pada awalnya saya mencoba mengurangi efek ini dengan hanya mengambil 100 pengukuran dalam 5 detik dan mengambil rata-rata. Tapi hasilnya tetap tidak memuaskan saya. Selama pencarian, saya menemukan itufilter perangkat lunak. Ini bekerja dengan cara yang sama, tetapi alih-alih rata-rata, ia mengurutkan semua 100 nilai pengukuran dalam urutan naik, memilih pusat 10 dan menghitung rata-rata dari mereka. Hasilnya mengesankan saya - fluktuasi pengukuran benar-benar berhenti. Saya memutuskan untuk menggunakannya untuk mengukur tegangan referensi internal (fungsi readVcc dalam kode).

5. Hasil

Data dari monitor port serial diimpor ke Excel dalam beberapa klik dan terlihat sebagai berikut:



Selanjutnya, mudah untuk membuat grafik debit baterai:



Dalam kasus Nexus 5 saya, kapasitas baterai BL-T9 yang diklaim adalah 2300 mAh. Diukur oleh saya - 2040 mAh dengan debit hingga 2,5 V. Pada kenyataannya, controller tidak memungkinkan baterai untuk duduk hingga tegangan rendah, kemungkinan besar nilai ambang 3V. Kapasitas dalam hal ini adalah 1960 mAh. Satu setengah tahun layanan telepon menyebabkan penarikan sekitar 15% dalam kapasitas. Dengan pembelian baterai baru, diputuskan untuk menunda.
Dengan bantuan penguji ini, beberapa baterai Li-Ion lainnya telah habis. Hasilnya terlihat sangat realistis. Kapasitas baterai baru yang diukur bertepatan dengan yang dinyatakan dengan penyimpangan kurang dari 2%.
Penguji ini juga cocok untuk baterai jari logam hidrida. Arus buangan dalam hal ini adalah sekitar 400 mA.

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


All Articles