В первую очередь необходимо припаять к штекеру питания два резистора по 1 к? вот этой схеме делителя напряжения:
Таким образом, если выходное напряжение полностью заряженных аккумуляторов не превышает 10В, то напряжение после делителя будет меньше 5В, а значит, будет адекватно распознаваться аналого-цифровым преобразователем.
Теперь необходимо подключить выход делителя к любому аналоговому входу на Arduino. В моем случае это ножка А5. Затем попробуем считать напряжение с батареек:
void setup() {
Serial.begin(9600);
pinMode(A5, INPUT);
}
void loop() {
float k = 2;
float voltage = k*analogRead(A5);
}
Получается непонятно что, так как мы забыли конвертировать значение в десятеричную систему счисления. Для этого делим все на 1024:
void loop() {
float k = 2/1024;
float voltage = k*analogRead(A5);
}
Теперь подбираем при помощи вольтметра коэффициент, при котором voltage будет примерно равно реальному напряжению:
float k = 2*1.12;
float voltage = k*4.5f/1024*analogRead(A5);
Мы получили сильно прыгающее вверх-вниз напряжение, зачастую не схожее с требуемым. Для исправления этой ошибки добавляем низкочастотную фильтрацию с наиболее оптимальным для вашего проекта коэффициентом сглаживания:
void loop() {
float k = 2*1.12;
float voltage = k*4.5f/1024*analogRead(A5);
float chargeLevel_procents;
float chargeLevel;
float y;
int z;
//Сглаживание значения заряда батареи
float A_v = voltage; //Значение
float A_K = 0.3; //Коэффициент сглаживания
static float A_y; //Выходное значение
A_y = A_y - A_K * (A_y - A_v);
}
Теперь осталось измерить напряжение на полностью заряженных аккумуляторах и полностью разряженных. В моем случае разница составляет ровно 1В.
После этого необходимо найти заряд аккумулятора в процентах:
y = A_y / 8.4 * 100;
chargeLevel_procents = y;
chargeLevel = z;
Нам осталось только перевести это в значок батарейки (или в квадратики, как у меня) и вывести в консоль:
if(chargeLevel_procents >= 0 && chargeLevel_procents < 33) {
z = 1; // 1/3 заряда
}
else if(chargeLevel_procents >= 33 && chargeLevel_procents < 66) {
z = 2; // 2/3 заряда
}
else if(chargeLevel_procents >= 66 && chargeLevel_procents <= 100) {
z = 3; // Полный заряд
}
Serial.print("\t Voltage: ");
Serial.print(A_y);
Serial.print(" V ");
Serial.print("\t Charge: ");
if(z == 1) {
Serial.print("¦");
}
else if(z == 2) {
Serial.print("¦¦");
}
else if(z == 3) {
Serial.print("¦¦¦");
}
else {
Serial.print("ERROR");
}
Serial.print("\r\n");
Для просмотра результата рекомендую использовать PuTTY, т. к. она поддерживает любые кодировки, в отличие от обычного «монитора порта» в Arduino IDE.
Комментарии (33)
Visphord
24.02.2016 12:05Эх, жаль не универсально (ваш код будет работать только с вашим типом аккумуляторов).
У меня в домашних поделках примерно такой-же код, строго завязанный на литий (3.0-4.2В).
zirus
24.02.2016 12:11+6Ваша схема будет выжирать из аккумулятора 120мА*ч каждые сутки. Номиналы резисторов можно легко сделать 100кОм без особого ущерба точности. Я в своих схемах устанавливал даже мегаомные резисторы на делитель, но тут уже надо учитывать входное сопротивление АЦП. На нижнее плечо можно поставить конденсатор номиналом 1 мкФ, шумы уменьшатся.
Также, ваше предположение, что заряд(количество энергии в аккумуляторе в процентах) пропорционален напряжению, неверно. Для определения на глазок — сойдёт, а вообще точность будет, думаю, процентов 30. При использовании литий-ионных аккумуляторов уровень заряда у вас опустится до 50 процентов, зависнет на этом уровне некоторое время, и дальше резко уйдёт в ноль. См. google://"li-ion discharge graph".Meklon
24.02.2016 12:18Можно еще буферный операционный усилитель поставить в теории. Чтобы точно не отъедать энергию при измерении и не влиять на напряжение.
Zolg
24.02.2016 12:40+2И сам делитель в данном случае имеет смысл делать 10:1 и использовать внутренний Vref атмеги (1.1v для 328'ой).
FireWind
24.02.2016 12:57Можно измерять напряжение раз в минуту, скажем, поставив на цепь измерения запирающий полупроводник. Тогда можно использовать лубой номинал сопротивлений. Естественно, следует учесть падение напряжения на полупроводнике для точности.
IronHead
24.02.2016 13:23+1А смысл городить лишние элементы? Выше уже подсказали как нужно правильно делать. Внутренний опорник и делитель на резисторах большого сопротивления.
Plone
24.02.2016 13:57+2Еще замечу, что называть деление на 1024 «переводом в десятеричную систему» неверно («десятичную», кстати). По сути это перевод в проценты (вы делите полученное значение на максимально возможное). Далее нужно просто умножить на 10, т.к. в вашем случае 100% — это 10 вольт. Ну, а потом поправочные коэффициенты добавить. Желательно несколько (по всей длине рабочего диапазона), с учетом нелинейной зависимости емкости от напряжения, как уже заметили выше.
vladimir_open-dev
24.02.2016 14:01+1Таким методом об уровне заряда аккумулятора не узнать ничего… и, как правильно сказали выше этот делитель потребляет энергию постоянно(и в конце концов испортит батарею). Если хотите измерять уровень заряда, то ищите по словам GasGauge/FuelGauge ic. Пост полная чушь(не завидую тому, кто не подумав повторит).
zirus
24.02.2016 14:57FuelGauge ic — крутая тема. В ноутбучных аккумуляторах стоит. По каким только параметрам не считает ёмкость. Даже саморазряд учтён, температурные зависимости, падение ёмкости в зависимости от цикла заряда-разряда. И много чего ещё. Не один день надо сидеть, чтобы понять
Delics
24.02.2016 15:46> Таким методом об уровне заряда аккумулятора не узнать ничего
Совсем недавно хотел сделать подобную систему через делитель (собственно, на первый взгляд, вполне логичное решение) — как только экспериментальные аккумуляторы выдавали 14В, получалось, что они заряжены, при 9В — разряжены.
Делителем легко это перевести в диапазон до 5В и дальше уже накапливать данные и анализировать.
Поясните, пожалуйста, почему это может не сработать? (я пока так и не сделал свой делитель и анализатор, т.к. нашёл стандартную схему контроля зарядки, но хотелось бы на будущее иметь в виду такую возможность)IronHead
24.02.2016 15:56Посмотрите график разряда любого современного АКБ. Он выглядит примерно так http://img.fcenter.ru/imgmat/article/cases/Ni_MH_batteries/128780.png
То есть просадка напряжения будет в самом конце, когда емкости уже не осталось. А до этого, емкость будет уменьшаться, а напряжение — нет.
Это если совсем уж простым языком.Delics
24.02.2016 16:15График монотонно убывающий.
Значит для измерения заряда и разряда он должен однозначно подходить.
Про красивый progressbar уровня зарядки, понятно, речи не идет.
Zolg
24.02.2016 16:01Ну не то, что бы совсем ничего, но точность будет невысока.
1) Зависимость нелинейна.
2) Ни у одного серьезного производителя я не встречал один «график зависимости напряжения от заряда». В даташитах присутствуют графикИ зависимости напряжения от заряда для различных температур/разрядных токов.Delics
24.02.2016 16:23> Зависимость нелинейна.
Линейно и не нужно. Важно, что монотонно убывающая.
> я не встречал один «график зависимости напряжения от заряда»
Так устройство делается на один конкретный тип аккумуляторов.
Универсальная зарядка — понятно, что задача другого уровня.Zolg
24.02.2016 16:29Линейно и не нужно. Важно, что монотонно убывающая.
Точность «полностью заряжен»/«севший в ноль» обеспечить получится.
устройство делается на один конкретный тип аккумуляторов
у одного конкретного аккумулятора будут разные кривые в зависимости от условий эксплуатации.
vladimir_open-dev
24.02.2016 16:08Уже правильно ответили + еще можно добавить, что кривая в графике смещается от температуры и поэтому дома будет 70%, а на улице 0%...
mrigi
24.02.2016 16:33+1А есть тут практики, реализовавшие "battery monitor ic"? А то рассказы про великий гугл они конечно замечательные, но реальные проекты найти не так уж и легко. Хотелось бы технически обоснованное бюджетное решение ($0.5-2.5), вымученное чьим-то опытом. Желательно в виде готового модуля. Вполне достаточно индикации из 3-5 диодов. На алиэкспрессе ничего приличного найти не могу.
Delics
24.02.2016 16:38Выпаял платку из старого зарядника. Найти готовое решение за приемлемые деньги также не получилось.
vladimir_open-dev
24.02.2016 17:54Пожалуйста...bq34z100-G1
4 диода + необходимость программирования и обучения(для одного типа АКБ можно делать единожды) + отсутствие балансировки и защиты + уже не 2,5 бакса. Но в этих задачах такой ценник это нормально(не стоит забывать цену датчика тока).
ofStatic
27.02.2016 01:10Чтобы определить процент по напряжению, надо хотя-бы примерно учитывать далеко не линейную разрядную кривую и делать замеры при том токе нагрузки, для которого эта кривая задана (в идеале при нулевом). Потому что под заметной нагрузкой некоторому напряжению может соответствовать, например, уровень заряда в 70%, а без нагрузки — 30%. Можно, конечно, измерять еще и ток и делать поправку на внутреннее сопротивление аккумулятора, но оно плавает от температуры сильно, это костыли. И да, это справедливо для лития, для никеля по напряжению вообще почти нереально определить уровень заряда на участке от 20 до 80%, кривая очень плоская.
Для точности в три палки кое-как пойдет, если делать замеры только при минимальном потреблении.
Если хочется точнее, то можно, как уже говорили выше, взять спец-микросхему или, интегрируя в реальном времени потребляемый ток, считать непосредственно ампер-часы. С точностью до погрешности измерений (специальная микруха в общем-то так и делает).
ForTheHorde
27.02.2016 01:17Показания будут сильно врать в зависимости от температуры, деградации ёмкостей и тока разряда. Для проверки аккумуляторов на работе делал похожее устройство, считал через определённые промежутки времени протекающий во время зарядки ток, интегрировал показания и получал текущую ёмкость аккумулятора. На разряде также интегрировал ток и в совокупности с информацией о мгновенном напряжении получал более-менее достоверную информацию о заряде.
mappa
27.02.2016 01:20Если необходимо измерить напряжение питания самого МК, можно поступить еще изящнее и обойтись без делителя совсем: за опорное напряжение принять напряжение питания (неизвестное), а измерить относительное напряжение на внутреннем опорном источнике (известное заранее, обычно 1.1, как указали выше). Затем не хитрыми математическими операциями получить напряжение питания контроллера AVR.
EngineerArt
27.02.2016 01:20Теперь подбираем при помощи вольтметра коэффициент, при котором voltage будет примерно равно реальному напряжению:
Так делать нельзя!
Реальное значение напряжения в Вольтах будет = (Полученное значение) * (Опорное Напряжение)/(дискретность АЦП)
Meklon
Субъективно лучше использовать дифференциальный АЦП и измерять между его ножками. Например, ads1115 — 16 бит, 4 канала. Можно и дифференциально измерять и относительно опорного. Не очень быстрый, но китайцы готовый breakout за копейки продают.
Delics
Написано, максимальное входное напряжение — 5,5В. А если больше надо, то что посоветуете? Через делитель напряжения? Или есть подходящий АЦП для 24В?
Meklon
Делитель, с резисторами точной выборки.
Вот, я для проекта делал симуляцию. У меня только плечо делителя с переменным сопротивлением, но принцип тот же. Еще проще. В этом варианте источник напряжения будет переменным.
Симуляция
Полная схема:
Еще можно посмотреть библиотеки RunningAverage и RunningMedian для сглаживания.
Хотя это и дикий перебор для обычного измерения батареи.
Delics
Спасибо!
Meklon
Извините за простынь, спойлер поломал при редактировании.
Zolg
А зачем? Все равно измерением только напряжения остаточную емкость можно определить с точностью плюс-минус пол слоновьей филейной части. Лишняя точность АЦП будет действительно лишней.
Если уж ставить дополнительный корпус, то есть спец микросхемы для контроля (в том числе) заряда батареи.
Google(«battery monitor IC»)
anticyclope
Беда в том, что почти нет fuel gauge в удобных для Arduino-поделок корпусах.
vladimir_open-dev
И правильно, что нет — там порог входа высокий.
anticyclope
Не прослеживаю связь :)