В портативном устройстве, работающем от аккумулятора, почти обязательным «удобством» является индикатор уровня его заряда. Казалось бы, если оно собрано на основе любого современного микроконтроллера и имеет графический дисплей, ничего сложного в этом нет: нужно лишь регулярно измерять напряжение батарейки с помощью встроенного АЦП и выводить его в виде традиционной батарейки🔋, степень заполнения которой зеленой краской зависит от напряжения.  Но если так сделать в лоб, есть риск, что индикатор будет вести себя, как в известном перле «она металась, как стрелка осциллографа». В лучшем случае, он будет время от времени раздражающе подергиваться туда-сюда на один-два пикселя.  В статье описывается простая реализация индикатора разряда, лишенная этого недостатка. Причин такой нестабильности показаний индикатора несколько. Для начала, нужно отметить, что напряжение почти полностью заряженного литий-ионного аккумулятора – 4,0 В, а почти полностью разряженного  -- 3,4-3,5 В. Соответственно, перепад от 0 до 100% соответствует всего 0,5-0,6 В, то есть индикация заряда с шагом 10% требует точности измерения напряжения не хуже 1%. При этом метрологические характеристики «вольтметра», встроенного в устройство, чаще всего достаточно скверные, потому что всерьез к проектированию этого узла относятся достаточно редко. Да и само напряжение, поступающее на устройство, потребление тока которым постоянно меняется в интервале от нескольких до 150-200 миллиампер, с учетом его подключения через невысокого качества китайский разъем типа JST  – тоже непостоянно. При непостоянном токе потребления, зависимость разрядной характеристики аккумулятора от тока разряда – самое главное препятствие для точного определения заряженности по напряжению. Поэтому в смартфонах и ноутбуках для этого чаще применяют другой подход – специализированный контроллер подсчитывает кулоны, пошедшие на зарядку батареи и затраченные затем при разряде, а напряжение при этом играет вспомогательную роль.  Но мы не будем забираться в такие дебри. Способ этот дает прекрасные результаты, но он не так прост в реализации: такие контроллеры сложно достать в розницу, трудно паять вручную, и вдобавок их нужно прошивать на требуемые параметры аккумулятора с помощью платной программы и не менее платного программатора. Тем более, что простыми средствами тоже можно достичь неплохих результатов, пусть и не таких точных.  Предлагаемая идея состоит в том, что раз потребление тока устройством меняется и наибольшая просадка напряжения происходит в моменты наибольшего потребления, нужно фиксировать напряжение именно в такие моменты. Это логично, так разряженный аккумулятор еще может долгое время «тянуть» устройство, пока оно находится в малопотребляющем режиме, но быстро просядет ниже минимально допустимого напряжения, когда потребление подскочит, например, при включении дисплея. При этом очевидно, что когда аккумулятор разряжается, степень его заряженности может только снижаться, но никак не увеличиваться. И наоборот, когда аккумулятор заряжается – степень его заряженности только возрастает, несмотря на то, что измеренное значение напряжения может в какие-то моменты падать из-за помех и т.п. Поэтому давайте будем во время разряда игнорировать поступающие данные об изменениях напряжения, если оно растет, считать этот рост артефактом. Делается это элементарно – путем сравнения каждого следующего значения измеренного напряжения с ранее зафиксированным минимальным, которое обновляется каждый раз, когда измеренное значение окажется ниже него. Во время заряда мы поступим аналогично, но фиксировать будем не минимумы, а максимумы. Разумеется, нам здесь понадобится некий сигнал от зарядного устройства, информирующий о том, в каком состоянии (заряд или разряд) находится аккумулятор. Обычно контроллеры заряда литиевых аккумуляторов имеют выход на светодиод или пару светодиодов, который несложно завести на GPIO контроллера. Тут нужно учесть еще и то, что кривые разряда и заряда существенно различаются. Поэтому по смене статуса зарядного контроллера нам нужно сменить не только направление работы индикатора, но и формулу расчета процентов заряженности от напряжения. А также то, что на протяжении этапа CV, на который приходится примерно 25-30% емкости батареи и половина времени заряда, индикатор будет показывать 100%, если мы будем принимать во внимание только напряжение. Можно так и оставить (сделав внятную индикацию, что зарядка еще не окончена), а можно заморочиться и вычислять на этом этапе проценты заряженности, как линейную (или более сложную) функцию от времени.  Нижеприведенный код на Си реализует самый простой вариант описанного алгоритма. Здесь мы считаем, что полностью разряженная батарейка при разряде дает 3,4 В. Чем это обусловлено? Во-первых, тем, что примерно с этого напряжения начинается быстрый спад напряжения, и дальнейший разряд не дает существенно большего времени работы. Во-вторых, если питать МК от  аккумулятора через LDO на 3,3 В, при снижении напряжения ниже этого значения начинает падать и напряжение питания МК. В некоторых случаях это не очень желательно, и в частности, в данной задаче пришлось бы задействовать встроенный источник опорного напряжения, чтобы измерить напряжение батареи в 3,3В и ниже. Та же полностью разряженная батарея при включении заряда сразу увеличивает напряжение до 3,65 В, я же взял 3,6 В, так как тогда при том же коэффициенте наклона автоматически выходит нужное напряжение на 100% заряженном аккумуляторе 4,2 В. Далее мы в удобном месте вызываем функцию batPercent, скажем, раз в секунду, и то, что она вернула, передаем в код, рисующий батарейку.  Вот и все. Теперь никаких ненужных колебаний и шевелений, индикатор аккумулятора стоит, как вкопанный, не забывая, впрочем, убавляться по мере разряда. Данный способ, конечно, не претендует на точность измерения остатка заряда, но это обычно и не требуется. При необходимости, конечно, можно усложнить код, добавив в него учет температуры, использовав вместо линейной интерполяции более сложную и точную.  Радиохимия, неорганическая химия