اختبار قدرة البطارية بسيط على اردوينو

في الآونة الأخيرة ، بدأت ألاحظ أن هاتفي الذكي بدأ في التفريغ بشكل أسرع. لم يجلب البحث عن برنامج "devourer" طاقة الفاكهة ، لذلك بدأت أتساءل عما إذا كان الوقت قد حان لاستبدال البطارية. ولكن لم يكن هناك يقين مطلق بعدم وجود سبب للبطارية. لذلك ، قبل طلب بطارية جديدة ، قررت أن أحاول قياس السعة الحقيقية للبطارية القديمة. للقيام بذلك ، تقرر تجميع مقياس بسيط لسعة البطارية ، خاصة وأن هذه الفكرة تفقس لفترة طويلة - هناك الكثير من البطاريات والمراكم التي تحيط بنا في الحياة اليومية ، وسيكون من الجيد أن تكون قادرًا على اختبارها من وقت لآخر.



إن الفكرة الأساسية وراء تشغيل الجهاز بسيطة للغاية: هناك بطارية مشحونة وحمل في شكل مقاوم ، ما عليك سوى قياس التيار والجهد والوقت أثناء تفريغ البطارية ، ووفقًا للبيانات التي تم الحصول عليها ، احسب سعتها. من حيث المبدأ ، يمكنك القيام بذلك باستخدام مقياس الفولتميتر والمقياس ، ولكن الجلوس على الأجهزة لعدة ساعات أمر مشبوه ، لذلك من الأسهل والأكثر دقة القيام بذلك باستخدام مسجل البيانات. استخدمت منصة Arduino Uno كمسجل.

1. مخطط

لا توجد مشاكل في قياس الجهد والوقت في Arduino - هناك ADC ، ولكنك تحتاج إلى تحويلة لقياس التيار. حصلت على فكرة استخدام مقاوم الحمل نفسه كتحويل. بمعنى ، معرفة الجهد الكهربائي عليه وقياس المقاومة مسبقًا ، يمكننا دائمًا حساب التيار. لذلك ، ستتكون أبسط نسخة من الدائرة فقط من حمل وبطارية ، مع اتصال بمدخل Arduino التناظري. ولكن سيكون من الجميل توفير سفك الحمل عند الوصول إلى عتبة الجهد على البطارية (بالنسبة لـ Li-Ion ، يكون هذا عادةً 2.5-3V). لذلك ، قدمت في الدائرة مرحلًا يتم التحكم فيه بواسطة دبوس رقمي 7 من خلال ترانزستور. النسخة النهائية للدائرة في الشكل أدناه.



لقد وضعت جميع عناصر الدائرة على قطعة من اللوح ، والتي يتم تثبيتها مباشرة على Uno. كحمل ، استخدمت لولب سلك نيتشروم بسماكة 0.5 مم بمقاومة حوالي 3 أوم. هذا يعطي قيمة محسوبة لتيار التفريغ 0.9-1.2A.



2. قياس التيار

كما ذكر أعلاه ، يتم حساب التيار على أساس الجهد على الملف ومقاومته. ولكن تجدر الإشارة إلى أن اللولب يسخن ، ومقاومة نيتشروم تعتمد إلى حد كبير على درجة الحرارة. للتعويض عن الخطأ ، أخذت ببساطة خاصية فولت أمبير من اللولب باستخدام مصدر طاقة مختبري وتركه يسخن قبل كل قياس. ثم اشتق معادلة خط الاتجاه في Excel (الرسم البياني أدناه) ، والتي تعطي اعتمادًا دقيقًا إلى حد ما على i (u) مع مراعاة التسخين. يمكن ملاحظة أن الخط ليس مستقيماً.



3. قياس الجهد

لأن دقة هذا المختبر تعتمد بشكل مباشر على دقة قياس الجهد ، قررت أن تولي اهتماما خاصا لذلك. ذكرت مقالات أخرى بشكل متكرر الطريقة التي تسمح لك بقياس الجهد بدقة أكبر باستخدام وحدات تحكم Atmega. سأكرر بإيجاز فقط - الجوهر هو تحديد الجهد المرجعي الداخلي عن طريق وحدة التحكم نفسها. لقد استخدمت المواد في هذه المقالة.

4. برنامج

الكود ليس معقدًا:

نص البرنامج
#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;
}




كل 5 ثوان ، يتم نقل البيانات في الوقت المحدد ، جهد البطارية ، تيار التفريغ ، السعة الحالية بـ mAh و Wh ، وكذلك جهد الإمداد إلى المنفذ التسلسلي. يتم حساب التيار بالوظيفة التي تم الحصول عليها في الفقرة 2. عند الوصول إلى عتبة الجهد Voff ، يتم إنهاء الاختبار.
النقطة الوحيدة المثيرة للاهتمام ، في رأيي ، في الشفرة التي سأميزها هي استخدام مرشح رقمي. والحقيقة هي أنه عند قراءة الجهد ، فإن القيم لا محالة "ترقص" صعودا وهبوطا. في البداية حاولت تقليل هذا التأثير ببساطة عن طريق أخذ 100 قياس في 5 ثوانٍ وأخذ المتوسط. لكن النتيجة لا تزال لا ترضي. أثناء البحث ، صادفت مثل هذامرشح البرمجيات. يعمل بطريقة مماثلة ، ولكن بدلاً من حساب المتوسط ​​، يقوم بفرز جميع قيم القياس المائة بترتيب تصاعدي ، ويحدد 10 المركزية ويحسب متوسطها. لقد أعجبتني النتيجة - توقفت تقلبات القياس تمامًا. قررت استخدامه لقياس الجهد المرجعي الداخلي (وظيفة readVcc في الكود).

5. النتائج

يتم استيراد البيانات من شاشة المنفذ التسلسلي إلى Excel ببضع نقرات وتبدو على النحو التالي:



بعد ذلك ، من السهل إنشاء رسم بياني لتفريغ البطارية:



في حالة جهاز Nexus 5 الخاص بي ، تبلغ سعة بطارية BL-T9 المطالب بها 2300 مللي أمبير في الساعة. تم قياسها بواسطتي - 2040 مللي أمبير مع تفريغ يصل إلى 2.5 فولت. في الواقع ، بالكاد تسمح وحدة التحكم للبطارية بالوقوف عند هذا الجهد المنخفض ، على الأرجح قيمة عتبة 3 فولت. السعة في هذه الحالة 1960 مللي أمبير. أدت سنة ونصف من الخدمة الهاتفية إلى انخفاض في السعة بنسبة 15٪ تقريبًا. مع شراء بطارية جديدة ، تقرر التأجيل.
بمساعدة هذا المختبر ، تم تفريغ العديد من بطاريات Li-Ion الأخرى بالفعل. تبدو النتائج واقعية للغاية. تتوافق السعة المقاسة للبطاريات الجديدة مع المعلنة بانحراف أقل من 2٪.
هذا المختبر مناسب أيضًا لبطاريات إصبع هيدريد المعادن. سيكون تيار التفريغ في هذه الحالة حوالي 400 مللي أمبير.

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


All Articles