В идеальном случае батарея должна иметь внутреннее сопротивление равное нулю. Но ничто в этом мире не совершенно, в том числе и батареи, а электроды батареи не являются на 100% проводниками, что создает небольшое сопротивление внутри батареи, которое называют ее внутренним сопротивлением. На практике, батареи практически всегда обладают некоторым внутренним сопротивлением. К примеру, для алкалиновой батарейки форм-фактора AA на "бумаге" оно составляет около 0.1Ω, для 9-вольтовой алкалиновой батареи – около 1Ω, для литий-полимерного аккумулятора – от 20 до 30mΩ. При этом внутреннее сопротивление батареи может значительно изменяться из-за высокой нагрузки на батарею.
В данной статье мы рассмотрим создание простого измерителя внутреннего сопротивления батареи на микроконтроллере AVR ATtiny85. С помощью него мы сможем измерять внутреннее сопротивление любой литиевой батареи и отображать его на экране OLED дисплея. Схема проекта собрана на печатной плате, изготовленной с помощью сервиса pcbway.
Ранее на нашем сайте мы рассматривали следующие аналогичные проекты разнообразных измерителей:
- тестер емкости литий-ионных батарей 18650 на Arduino;
- тестер емкости аккумуляторов 18650 на основе Arduino;
- умный измеритель электроэнергии на ESP12 и Arduino.
Необходимые компоненты
- Микроконтроллер Attiny85 (купить на AliExpress).
- Операционный усилитель LM358 (купить на AliExpress).
- Резистор 1 Ом 5 Вт – 2 шт. (купить на AliExpress).
- Резистор 1 кОм (купить на AliExpress).
- Low VGS Mosfet.
- Кнопка.
- OLED дисплей с разрешением 128X64 с поддержкой интерфейса I2C (купить на AliExpress).
- Держатель для батареи.
- Конденсатор 0,1 мкФ (купить на AliExpress).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Общие принципы работы измерителя внутреннего сопротивления батареи
Один из самых простых способов измерения внутреннего сопротивления батареи – это использование делителя напряжения. Его мы и применим в нашем проекте. Мы будем использовать составной резистор, собранный из двух резисторов, сопротивлением 2 Ома. Но резисторы, выпускаемые современной промышленностью, имеют определенные допуски на свои номиналы, в большинстве своем сейчас этот допуск составляет 5%. Поэтому реальное сопротивление резистора для нашего проекта желательно измерить с помощью мультиметра.
Как вы можете видеть из представленного рисунка, мультиметр показал сопротивление нашего составного резистора равное 1,7 Ом. Но необходимо принять во внимание погрешность мультиметра и допуск резистора. После недолгих раздумий мы решили, что наш резистор с теоретическим сопротивлением 2 Ома имеет реальное сопротивление 1,2 Ома, поэтому это значение мы и будем использовать в наших расчетах.
Примечание: мультиметры в большинстве случаев не очень хорошо подходят для измерения сопротивления, к слову сказать, напряжение они измеряют гораздо лучше. В этом случае можно значительно повысить точность измерения сопротивления мультиметром используя источник постоянного тока 500mA или 1A, пропуская данный ток через резистор и измеряя мультиметром падение напряжения на резисторе.
А в нашем случае нам необходимо измерять напряжение ненагруженной батареи как показано на следующем рисунке.
Как видно из рисунка напряжение батареи составляет 3,85 Вольта, а нам необходимо рассчитать теоретический ток, который будет течь через резистор если мы подключим его к батарее. Для этого мы применим известный закон Ома – I = V/R:
1 |
I = 3.85/1.2 =3.236 Amps |
То есть если мы подключим к этой батарее резистор 1,2 Ома через него потечет ток 3,22 А. При подключенной нагрузке нам также необходимо измерить напряжение.
Как можно видеть из представленного рисунка, напряжение батареи под нагрузкой составляет Vload = 3.72 В. Если мы вычтем это значение напряжения из значения напряжения батареи без нагрузки, то мы получим падение напряжения на внутреннем сопротивлении батареи.
1 |
Vinternal = 3.85-3.72 = 0.13V |
Теперь, чтобы определить внутреннее сопротивление батареи, нам необходимо просто разделить это полученное падение напряжения на рассчитанный ток.
1 |
ISR = (Vdrop-internal / Current) = 0.13/3.236 = 0.04017 ohms |
Мы получили значение внутреннего сопротивления батареи равное 0.04017 Ома. Давайте сравним его со значением, полученным с помощью профессионального измерителя.
Как вы можете видеть из представленного рисунка, полученное нами значение достаточно близко к значению, полученному с помощью профессионального инструмента.
Примечание: когда вы будете использовать описанный способ измерения внутреннего сопротивления батареи с помощью микроконтроллера Attiny85 вам необходимо будет принимать во внимание внутреннее сопротивление MOSFET транзистора и сопротивление проводников на печатной плате нашего проекта.
Some MOSFETS are not fully on at 5V so you need to consider all those in your code and calibrate the code according to that value.
Схема проекта
Схема измерителя внутреннего сопротивления батареи на ATtiny85 представлена на следующем рисунке. Схема разделена на несколько частей чтобы вы могли лучше понять ее суть.
Сначала рассмотрим часть схемы, отвечающую за контроль тока от батареи (Battery Current Controller). Основная цель данной части схемы – защитить MOSFET от значительных перепадов тока. Как вы можете видеть, на не инвертирующий вход (pin3) операционного усилителя мы подаем ШИМ (широтно-импульсная модуляция) сигнал от микроконтроллера. Данный сигнал фильтруется с помощью конденсатора на 100 нФ и резистора на 100 кОм и затем этот отфильтрованный сигнал поступает на контакт 3 операционного усилителя. Когда напряжение на этом не инвертирующем входе больше напряжения на инвертирующем входе, на выходе операционного усилителя будет уровень high. Этот уровень high переводит MOSFET в открытое состояние и в результате через резистор R1 начинает течь ток, соответственно, на нем будет создаваться падение напряжения. Если это падение напряжения будет больше чем уровень напряжения на не инвертирующем входе операционного усилителя, то на выходе операционного усилителя будет уровень low и ток через резистор перестанет течь. Этот процесс будет продолжаться до тех пор пока у ШИМ сигнала не будет уровень логического 0.
Основным управляющим центром нашей схемы является микроконтроллер ATtiny85, который формирует ШИМ сигнал для управления работой операционного усилителя и измеряет напряжение батареи чтобы на его основе рассчитать внутреннее сопротивление батареи. Запитывается микроконтроллер ATtiny85 через разъем USB, через него же производится и программирование микроконтроллера.
На OLED дисплее мы будем отображать измеренное напряжение батареи и рассчитанное значение ее внутреннего сопротивления. Также в схеме у нас есть коннектор батареи (для подключения батареи) и переключатель для сброса микроконтроллера.
Изготовление печатной платы для нашего проекта
Для данного проекта измерителя внутреннего сопротивления батареи его авторы (ссылка на оригинал приведена в конце статьи) решили изготовить печатную плату, ее дизайн приведен на следующем рисунке.
Данная печатная плата спроектирована в программном обеспечении EAGLE PCB и имеет размеры 90х55 мм. Для ее самостоятельного изготовления вы можете скачать Gerber файлы на нее.
Фронтальная часть печатной платы нашего проекта приведена на следующем рисунке.
На ней мы разместили все компоненты нашей схемы, а на тыльной стороне платы мы разместили только соединения. Печатная плата двухслойная.
Тыльная часть печатной платы нашего проекта приведена на следующем рисунке.
А на следующем рисунке представлена 3D модель нашего измерителя внутреннего сопротивления батареи. На ней вы можете увидеть расположение всех компонентов схемы нашего проекта, включая радиатор, резистор 5W, разъем micro USB и переключатель.
Операционный усилитель и микроконтроллер ATtiny85 расположены на обратной стороне платы, 3D модель которой представлена на следующем рисунке.
Заказ печатной платы для проекта
Авторы проекта заказали изготовление печатной платы для него на сервисе PCBWay. Разумеется, вы можете заказать ее изготовление на любом другом сервисе, с которым привыкли работать. Для заказа изготовления печатной платы на сервисе PCBWay выполните следующую последовательность шагов:
Шаг 1. Перейдите на сайт www.pcbway.com и зарегистрируйтесь на нем если у вас там еще нет аккаунта. Затем на его вкладке PCB Prototype введите размеры вашей печатной платы, число ее слоев и число экземпляров платы, которые вам необходимо изготовить.
Шаг 2. Затем нажмите на кнопку ‘Quote Now’. После этого вы попадете на страницу где вам необходимо ввести ряд дополнительных параметров для изготовления печатной платы: ее материал, толщину, число слоев и т.п. Большинство из них вы можете оставить такими, какие сервис предлагает по умолчанию.
Шаг 3. Загрузите Gerber файлы вашей печатной платы на сервис PCBWAY, он проверит их на корректность, после чего вы можете перейти к оплате заказа.
Сборка конструкции проекта
Через несколько дней после заказа изготовления печатной платы авторы проекта получили ее в готовом виде (в упаковке). Фронтальная и тыльная сторона изготовленной печатной платы показаны на следующем рисунке. Как и следовало ожидать, качество изготовления печатной платы оказалось на высоте.
После этого автор проекта припаял на данную печатную плату необходимые компоненты и в результате у него получилась следующая собранная конструкция измерителя внутреннего сопротивления батареи.
Объяснение программы Arduino для загрузки в микроконтроллер Attiny85
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Перед написанием кода программы необходимо скачать библиотеку для работы с OLED дисплеем с контроллером SSD1306 и установить ее в вашу Arduino IDE.
Первым делом в коде программы подключим необходимые библиотеки.
1 2 |
#include "SSD1306_minimal.h" #include <avr/pgmspace.h> |
Далее создадим объект для работы с OLED дисплеем.
1 |
SSD1306_Mini oled |
Затем объявим все необходимые переменные и дадим осмысленные имена используемым контактам.
1 2 3 4 5 6 7 8 9 |
//#define OLED_RESET 4 // OLED reset pin #define vIn A2 // raw battery voltage #define gate 1 // xsistor base pin float v1 = 0.000; // unloaded battery voltage float v2 = 0.000; // loaded battery voltage float i = 0.000; // unloaded current // loaded current float intRes = 0.000; // battery internal resistance in Ohms float vCal = 4.97; // calculated vRef (measure between 5V & Gnd) float load_resistance = 2; // load resistance in Ohms |
После этого в функции setup() установим режим работы используемого аналогового контакта на ввод данных, а режим работы используемого цифрового контакта – на вывод данных, на нем мы будем формировать сигнал ШИМ, в качестве защиты от ложных срабатываний первоначально установим на нем уровень low. Затем инициализируем OLED дисплей с необходимым адресом I2C и очистим его экран. Далее произведем вызов функции measure_value().
1 2 3 4 5 6 7 8 9 10 11 12 |
void setup() { // Serial.begin( 9600 ); pinMode(vIn, INPUT); // set A0 as input pinMode(gate, OUTPUT); // set D9 as output digitalWrite(gate, LOW); delay(100); oled.init(0x3C); // Initializes the display to the specified address oled.clear(); // Clears the display delay(1000); // Delay for 1 second measure_value(); //print_to_screen(); } |
В функции measure_value() мы используем метод startscreen() для очистки экрана дисплея.
1 2 |
oled.startScreen(); oled.clear(); // Clears the display |
Затем мы будем измерять напряжение ненагруженной батареи и рассчитывать теоретическое значение тока через резистор – его мы будем выводить на экран OLED дисплея.
1 2 3 4 5 6 7 8 9 10 11 12 |
char buff[10]; v1 = (analogRead(vIn) * vCal) / 1023; delay(5); dtostrf(v1, 4, 3, buff); oled.cursorTo(0, 0); // x:0, y:0 oled.printString(" Voltage1:"); oled.printString(buff); i = (v1 / load_resistance); dtostrf(i, 4, 3, buff); oled.cursorTo(0, 10); // x:0, y:0 oled.printString(" Current:"); oled.printString(buff); |
Затем на контакт ШИМ микроконтроллера мы будем подавать уровень high и рассчитывать падение напряжения на резисторе.
1 2 3 4 5 6 7 8 9 10 |
digitalWrite(gate, HIGH); delay(5); v2 = (analogRead(vIn) * vCal) / 1023; delay(1); dtostrf(v2, 4, 3, buff); oled.cursorTo(0, 20); // x:0, y:23 oled.printString(" Voltage2:"); oled.printString(buff); delay(3); digitalWrite(gate, LOW); |
Теперь у нас есть все необходимые значения чтобы рассчитать внутреннее сопротивление батареи.
1 2 3 4 5 |
intRes = (((v1 - v2) / i) + 0.017); dtostrf(intRes, 4, 3, buff); oled.cursorTo(0, 30); // x:0, y:23 oled.printString(" IntRes:"); oled.printString(buff); |
Тестирование работы проекта
После сборки аппаратной части проекта и загрузки кода программы в микроконтроллер мы можем приступить к тестированию работы проекта. Первым делом подадим питание на схему проекта и убедимся в том, что на операционный усилитель и микроконтроллер поступает напряжение 5V. Также убедимся в том, что в схеме нет никаких коротких замыканий.
После начала работы кода программы вы должны увидеть на экране дисплея измеренное значение внутреннего сопротивления батареи в милли Омах. Для проверки точности работы схемы также измерим это сопротивление с помощью профессионального измерителя.
Как вы можете видеть, погрешность работы нашего измерителя внутреннего сопротивления батареи по сравнению с профессиональным инструментом сравнительно невелика.
Возможные проблемы при работе с проектом и способы их решения
К сожалению, изготовленная печатная плата имела некоторые недостатки.
Первой из проблем была проблема с MOSFET. Как оказалось, его соединения на плате были сделаны зеркально, поэтому авторам проекта пришлось подключить MOSFET в обратном направлении.
Для того чтобы MOSFET открывался, необходимы такие MOSFET'ы как, например, IRLZ44N, IRF540. Но на момент сборки у автора проекта их не было, поэтому ему пришлось поместить SMD MOSFET вместо TO-220.
Следующая основная проблема была связана с питанием проекта. Основное питание проект получает по USB кабелю и в зависимости от длины данного кабеля питающее напряжение на входе схемы может изменяться, а от него, в свою очередь, зависит точность работы АЦП (аналого-цифрового преобразователя), причем достаточно сильно.
Также авторы проекта не предусмотрели на печатной плате разъем для программирования микроконтроллера, поэтому для программирования микроконтроллера в первый раз вам необходимо либо припаять проводники к соответствующим контактам микроконтроллера, либо же вам будет нужен разъем SMD ZIF.
Рассмотренный нами в данной статье проект не позволяет измерять внутреннее сопротивление батарей, напряжение на выходе которых менее 3 Вольт.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#include "SSD1306_minimal.h" #include <avr/pgmspace.h> SSD1306_Mini oled; //#define OLED_RESET 4 // контакт сброса OLED дисплея #define vIn A2 // контакт, на котором измеряется напряжение с батареи #define gate 1 // контакт, к которому подключена база транзистора float v1 = 0.000; // напряжение батареи без нагрузки float v2 = 0.000; // напряжение батареи с нагрузкой float i = 0.000; // ток без нагрузки float intRes = 0.000; // внутреннее сопротивление батареи в Омах float vCal = 4.97; // рассчитанное опорное напряжение vRef (measure between 5V & Gnd) float load_resistance = 2; // сопротивление нагрузочного резистора void setup() { // Serial.begin( 9600 ); pinMode(vIn, INPUT); // режим работы A0 – на ввод данных pinMode(gate, OUTPUT); // режим работы D9 – на вывод данных digitalWrite(gate, LOW); delay(100); oled.init(0x3C); // инициализируем дисплей с заданным адресом oled.clear(); // очищаем экран дисплея delay(1000); // задержка на 1 секунду measure_value(); //print_to_screen(); } void loop() { // oled.startScreen(); // oled.clear(); // Clears the display // //int sensorValue = analogRead(4); // // analogResult = analogRead(A2); // // char buff[10]; // // dtostrf(analogResult, 4, 3, buff); // oled.cursorTo(0, 0); // x:0, y:0 // oled.printString(" Voltage1:"); // oled.printString(buff); // // //analogWrite(gate, 255); // int value; // float volt; // // // // value = analogRead( vIn ); // // // volt = value * 4.68 / 1023.0; // //// // // Serial.print( "Value: " ); // // Serial.print( value ); // // Serial.print( " Volt: " ); // // Serial.println( volt ); // // // delay(1); } float measure_value() { oled.startScreen(); oled.clear(); // очищаем экран дисплея char buff[10]; v1 = (analogRead(vIn) * vCal) / 1023; delay(5); dtostrf(v1, 4, 3, buff); oled.cursorTo(0, 0); // x:0, y:0 oled.printString(" Voltage1:"); oled.printString(buff); i = (v1 / load_resistance); dtostrf(i, 4, 3, buff); oled.cursorTo(0, 10); // x:0, y:0 oled.printString(" Current:"); oled.printString(buff); digitalWrite(gate, HIGH); delay(5); v2 = (analogRead(vIn) * vCal) / 1023; delay(1); dtostrf(v2, 4, 3, buff); oled.cursorTo(0, 20); // x:0, y:23 oled.printString(" Voltage2:"); oled.printString(buff); delay(3); digitalWrite(gate, LOW); intRes = (((v1 - v2) / i) + 0.017); dtostrf(intRes, 4, 3, buff); oled.cursorTo(0, 30); // x:0, y:23 oled.printString(" IntRes:"); oled.printString(buff); } |