Как известно, литий-ионные батареи (Li-Ion Battery) являются в настоящее одними из самых эффективных типов аккумуляторов. Но чтобы обеспечить им «долгую жизнь», их необходимо специальным образом заряжать, разряжать и даже хранить. В данной статье мы рассмотрим создание тестера емкости литий-ионных батарей 18650 на основе платы Arduino, который будет полностью разряжать батарею и на основе этого определять ее емкость. Таким образом, можно будет выявлять неисправные или мало пригодные (вследствие их малой емкости) для дальнейшего использования аккумуляторы.
Наше устройство будет обладать следующими основными техническими особенностями:
- две кнопки для установки тока;
- OLED дисплей для отображения пользовательского интерфейса и результатов измерения емкости;
- термистор (терморезистор) для определения температуры батареи.
Ранее на нашем сайте мы рассматривали аналогичный тестер емкости аккумуляторов 18650 на основе Arduino, но в нем не предусмотрена регулировка тока разряда и измерение температуры батареи. Также в нем используется ЖК дисплей вместо OLED дисплея, применяемого в данном проекте для более наглядного отображения информации по сравнению с обычным ЖК дисплеем.
Также ранее на нашем сайте мы рассматривали двухрежимное зарядное устройство литиевых батарей на основе Arduino – можете посмотреть если интересно. Еще можете просмотреть все проекты силовой электроники на нашем сайте.
Необходимые компоненты
- Плата Arduino Nano (купить на AliExpress).
- OLED дисплей SSD1306 с диагональю экрана 0.96” (купить на AliExpress — для данного проекта выбирайте вариант дисплея с 4 контактами).
- Операционный усилитель LM358 (купить на AliExpress).
- MOSFET RLZ44N.
- Резистор 0,5 Ом 5 Вт (для нагрузки) (купить на AliExpress).
- 18650 Li-ion Battery (для тестирования).
- Терморезистор 10 кОм NTC типа.
- Резисторы 1 МОм, 10 кОм, 4,7 кОм (2 шт.) (купить на AliExpress).
- Конденсатор 100 нФ – 2 шт. (купить на AliExpress).
- Конденсатор 220 мкФ (купить на AliExpress).
- Тактильные переключатели/кнопки (Tactile Switches) – 2 шт.
- Держатель (отсек) для батареи 18650.
- Перфорированная плата.
- Соединительные провода.
Реклама: ООО «АЛИБАБА.КОМ (РУ)» ИНН: 7703380158
Схема проекта
Схема тестера емкости литий-ионных батарей 18650 на Arduino представлена на следующем рисунке.
Схема нашего тестера состоит из 4-х основных элементов:
- схема нагрузки постоянного тока;
- схема измерения емкости батареи;
- схема измерения температуры батареи;
- пользовательский интерфейс.
Рассмотрим каждый из этих элементов более подробно.
Схема нагрузки постоянного тока
Основным компонентом данной схемы является двойной операционный усилитель LM358 (в едином корпусе). Тем не менее, в нашем проекте необходим только один операционный усилитель. ШИМ выход с контакта 3 платы Arduino подключен к неинвертирующему входу первого операционного усилителя (ОУ). Сигнал ШИМ фильтруется с помощью ФНЧ для получения эквивалентного аналогового напряжения. В то же время инвертирующий вход операционного усилителя работает в качестве обратной связи для выхода операционного усилителя, который подключен между IRFZ44N MOSFET и шунтирующим резистором 0,5 Ом.
Этот операционный усилитель, резистор R4 и MOSFET образуют схему нагрузки постоянного тока (constant current load circuit). Когда мы устанавливаем напряжение на неинвертирующем входе ОУ, то ОУ включает MOSFET чтобы вызвать такое же падение напряжения на резисторе R4 – падение напряжения на данном резисторе создается исходя из-за закона Ома вследствие протекания по нему тока. Таким образом, мы можем контролировать величину тока, протекающего через нагрузочный резистор (0,5 Ом) изменяя ширину импульса сигнала ШИМ, поступающего на неинвертирующий вход ОУ.
Схема измерения емкости батареи
Напряжение на батарее измеряется с помощью аналогового контакта A0 платы Arduino. Два конденсатора (C1 и C2) используются для фильтрации шумов от схемы нагрузки постоянного тока, которые могут ухудшить точность аналого-цифрового преобразования (АЦП).
Схема измерения температуры батареи
Температура батареи измеряется с помощью терморезистора 10 кОм с отрицательным температурным коэффициентом (NTC). Сопротивление терморезистора изменяется в зависимости от температуры. Поскольку это терморезистор NTC типа, то при увеличении температуры его сопротивление уменьшается.
Используя делитель напряжения, состоящий из терморезистора и обычного резистора сопротивлением 10 кОм, мы можем с помощью измерения напряжения в средней точке этого делителя измерять текущую температуру (за счет изменения сопротивления терморезистора). Напряжение со средней точки делителя напряжения подается на аналоговый контакт A1 платы Arduino для измерения напряжения.
Пользовательский интерфейс
Пользовательский интерфейс в нашем проекте состоит из двух кнопок и 0.96″ OLED дисплея с интерфейсом I2C. Кнопки (Up и Down) используются для изменения ширины импульса ШИМ сигнала. Третья кнопка (RST) используется для сброса платы Arduino.
Принцип работы тестера емкости батарей
Принцип работы нашего тестера емкости батарей основан основан на сравнении напряжений на инвертирующем (контакт 2) и неинвертирующем (контакт 3) входах операционного усилителя. Когда мы подаем на неинвертирующий вход определенный уровень напряжения с помощью ШИМ сигнала, выход ОУ открывает затвор MOSFET транзистора. А когда он открывается, то через резистор R1 начинает протекать ток, который создает на нем падение напряжения, которое используется как сигнал отрицательной обратной связи для ОУ. Он управляет MOSFET транзистором таким образом, чтобы уровни напряжений на инвертирующем и неинвертирующем входах операционного усилителя были примерно одинаковы. Таким образом, ток через нагрузочный резистор будет пропорционален напряжению на неинвертирующем входе ОУ. ШИМ сигнал с выхода Arduino фильтруется с помощью ФНЧ, состоящего из R3 и C3.
Таким образом, для определения емкости батареи получаем формулу:
Battery Capacity (mAh) = Current (I ) in mA x Time ( T ) in Hours
То есть чтобы рассчитать емкость батареи в мАч (mAh) нам необходимо знать ток в мА и время в часах. Наша схема нагрузки постоянного тока позволяет разряжать батарею постоянным током на протяжении всего времени разрядки. Ток разряда можно отрегулировать с помощью кнопок. Время разряда измеряется программным способом с помощью таймера в Arduino.
Сборка конструкции проекта
Собрать всю конструкцию проекта мы решили на перфорированной плата как показано на следующем рисунке.
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Первым делом в программе подключим все используемые библиотеки. Библиотека JC_Button.h используется для считывания состояния кнопок, а библиотека Adafruit_SSD1306.h – для взаимодействия с OLED дисплеем. Обе эти библиотеки можно установить с помощью менеджера библиотек (library manager) в Arduino IDE.
1 2 |
#include<JC_Button.h> #include <Adafruit_SSD1306.h> |
Далее объявим все переменные, которые будем использовать в программе.
1 2 3 4 5 |
int ThermistorPin = A1; int Vo; float R1 = 10000; float logR2, R2, T; float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07; |
Затем установим в программе величину опорного напряжения (reference voltage). Это значение напряжения (Vcc) играет очень важную роль в нашей программе поскольку позволяет идентифицировать напряжение батареи. Для установки значения Vcc сначала соедините плату Arduino с внешним источником питания напряжением 7-12 Вольт. Затем измерьте напряжение на контакте 5V платы Arduino с помощью мультиметра. После этого установите измеренное значение Vcc в коде программы.
1 2 3 |
float Vcc = 5.04 ; // Voltage of Arduino 5V pin ( Mesured by Multimeter after connecting external 9V Supply ) const int Current [] = {0,70,100,190,350,400,500,620,700,830,910,1000}; const int PWM_RES [] = {0, 1, 2, 4, 8, 9, 12, 15, 17, 20, 22, 24}; |
После этого рассчитаем значение напряжения на резисторе R4 зная величину тока через него.
1 2 3 4 |
V = I X R Таким образом, I = V/R Допустим, I = 100mA/0.1A, и R4 = 0.5R Тогда необходимое напряжение = 0.1 x 0.5 = 0.05V |
Затем установим значение коэффициента заполнения ШИМ сигнала, подаваемого на контакт 3 операционного усилителя, чтобы достигнуть требуемого значения падения напряжения на резисторе R4. Также зададим аппроксимирующие коэффициенты рабочей характеристики терморезистора.
1 2 3 4 5 |
int ThermistorPin = A1; int Vo; float R1 = 10000; float logR2, R2, T; float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07; |
Мы можем использовать уравнение Стейнхарта-Харта (приведено ниже) для расчета температуры исходя из сопротивления терморезистора. Более подробно про использование данного уравнения вы можете прочитать в статье про измерение температуры с помощью терморезистора и Arduino.
1 |
1/T=A+B*ln(R)+C*(ln(R))^3 |
Но в данном проекте мы будем использовать более простое выражение для определения значения температуры (приведено ниже), которое называется уравнением на основе параметра Beta (или B). Оно не такое точное как уравнение Стейнхарта-Харта, но несмотря на это обеспечивает достаточную точность вычислений в необходимом нам узком температурном диапазоне.
1 |
1/T=1/T0+1/B*ln(R/R0) |
Переменная T в этом выражении – это значение температуры окружающей среды в Кельвинах. T0 – это обычная комнатная температура, также в Кельвинах (25°C = 298.15K), B – константа beta, R – сопротивление терморезистора при текущей температуре окружающей среды, R0 – сопротивление терморезистора при температуре T0. Значения T0, B и R0 можно найти в даташите на имеющийся у вас терморезистор.
Если напряжение на делителе напряжения и Vref (опорное напряжение) одинаковы, то в этом случае у вас нет необходимости знать значения R0 или R чтобы определить значение температуры. В этом случае вы можете записать уравнение для определение сопротивления терморезистора используя отношение значений на выходе АЦП.
1 |
R=R0*((adcMax/adcVal)-1) |
Тогда получаем:
1 2 |
1/T=1/T0+1/B*ln(R0*((adcMax/adcVal)-1)/R0), R0 сокращается и в результате остается: 1/T=1/T0+1/B*ln((adcMax/adcVal)–1) |
Рассчитав обратное значение полученного по этой формуле результата, мы получим значение температуры в Кельвинах. Допустим, что напряжение с выхода делителя напряжения (с терморезистором) у нас подается на 10-битный АЦП. Константа beta для терморезистора равна 3380, сопротивление R0 терморезистора при температуре 25°C равно 10 кОм, а значение на выходе АЦП равно 366. Тогда по выше приведенной формуле получим:
1 2 3 |
1/T=1/298.15+1/3380*ln((1023/366)-1) 1/T=0.003527 T = 283.52K – 273.15K = 10.37°C |
Этот алгоритм вычисления температуры отражен в функции temp() в нашей программе.
1 2 3 4 5 6 7 8 |
void temp() { Vo = analogRead(ThermistorPin); R2 = R1 * (1023.0 / (float)Vo - 1.0); logR2 = log(R2); T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); T = T - 273.15; } |
Далее в функции loop мы будем считывать состояния кнопок. При нажатии этих кнопок ток разряда будет увеличиваться или уменьшаться (в зависимости от нажатой кнопки). Если кнопка нажата на время более 1000ms, то включается таймер отсчета.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void loop() { UP_Button.read(); Down_Button.read(); if (UP_Button.wasReleased() && l < 11 && calc == false) { l=l+1; } if (Down_Button.wasReleased() && l > 0 && calc == false) { l=l-1; } if (UP_Button.pressedFor (1000) && calc == false) { analogWrite(PWM_Pin,PWM_RES[l]); digitalWrite(Buzzer, HIGH); delay(1500); digitalWrite(Buzzer, LOW); timerInterrupt(); } } |
Тестирование работы проекта
Когда аппаратная часть проекта будет готова и программа будет загружена в плату Arduino можно будет приступить к тестированию работы проекта. Для этого поставьте тестируемую батарею в крепление для нее на плате. После этого на экране OLED дисплея должны начать показываться результаты работы схемы: ток разряда, емкость батареи и т.д.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи. Для удобства вы можете смонтировать конструкцию проекта на печатной плате.
Исходный код программы (скетча)
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
#include<JC_Button.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); int ThermistorPin = A1; int Vo; float R1 = 10000; float logR2, R2, T; float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07; const int Current [] = {0,70,100,190,350,400,500,620,700,830,910,1000}; const int PWM_RES [] = {0, 1, 2, 4, 8, 9, 12, 15, 17, 20, 22, 24}; int l = 0; const float Low_BAT_level = 3.4; const byte PWM_Pin = 3; const byte Buzzer = 9; const int BAT_Pin = A0; int PWM_Value = 0; unsigned long Capacity = 0; int ADC_Value = 0; float Vcc = 5.04 ; // напряжение на контакте 5V платы Arduino (измеряется с помощью мультиметра после подачи на плату Arduino внешнего напряжения 9V) float BAT_Voltage = 0; float sample =0; byte Hour = 0, Minute = 0, Second = 0; bool calc = false, Done = false; Button UP_Button(11, 25, false, true); Button Down_Button(12, 25, false, true); // 'Circuit-Digest-Logo', 128x64px (лого 'Circuit-Digest') const unsigned char myBitmap [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0x39, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x06, 0xff, 0xf8, 0x1c, 0xff, 0xff, 0xff, 0xe7, 0xfe, 0x07, 0xef, 0xff, 0xff, 0xff, 0xff, 0xe4, 0x21, 0xff, 0xe0, 0x19, 0xff, 0xff, 0xff, 0xe7, 0x3e, 0xf3, 0xef, 0xff, 0xff, 0xff, 0xe7, 0xf1, 0x80, 0x7f, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc1, 0x00, 0x3f, 0x8f, 0xff, 0xff, 0xe7, 0xff, 0xff, 0x1e, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xe7, 0x82, 0x00, 0x7f, 0x9f, 0xf9, 0xc1, 0x81, 0x9e, 0x66, 0x06, 0xfe, 0xef, 0x03, 0xc1, 0xe0, 0xc1, 0xfe, 0x3f, 0xff, 0x9f, 0xf9, 0xc3, 0x1f, 0x9e, 0x66, 0x0e, 0xfe, 0xee, 0x7b, 0xbc, 0xdf, 0xe7, 0xc0, 0x00, 0x3f, 0x9f, 0xf9, 0xcf, 0x3f, 0x9e, 0x67, 0x3e, 0xfe, 0xee, 0xfb, 0xbe, 0xdf, 0xe7, 0x80, 0x8f, 0xff, 0x9f, 0xf9, 0xcf, 0x3f, 0x9e, 0x67, 0x3e, 0xfe, 0xec, 0xfb, 0x00, 0xe3, 0xe7, 0xc0, 0xd0, 0x7f, 0x8f, 0xf9, 0xcf, 0x3f, 0x9e, 0x67, 0x3e, 0xfe, 0xee, 0xfb, 0x3f, 0xfc, 0xe7, 0xfc, 0x60, 0x7f, 0xc7, 0xf9, 0xcf, 0x3f, 0x9e, 0x67, 0x3e, 0xfc, 0xee, 0xfb, 0xbf, 0xfe, 0xe7, 0xe3, 0x03, 0xff, 0xe0, 0x19, 0xcf, 0x01, 0x80, 0x67, 0x3e, 0xf1, 0xee, 0x7b, 0x9f, 0xfe, 0xe7, 0xe1, 0x09, 0xff, 0xf0, 0x19, 0xcf, 0xc1, 0xc0, 0xe7, 0x3e, 0x07, 0xef, 0x03, 0xc1, 0xc0, 0xf7, 0xf0, 0x31, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // массив побитового изображения (общее количество используемых байт для хранения изображения в PROGMEM = 1040) void setup () { Serial.begin(9600); pinMode(PWM_Pin, OUTPUT); pinMode(Buzzer, OUTPUT); analogWrite(PWM_Pin, PWM_RES[l]); UP_Button.begin(); Down_Button.begin(); display.begin(SSD1306_SWITCHCAPVCC, 0x3C); display.clearDisplay(); display.drawBitmap(0, 0, myBitmap, 128, 64, WHITE); display.display(); delay(3500); display.setTextColor(WHITE); display.clearDisplay(); display.setTextSize(2); display.setCursor(2,15); display.print("Adj Curr:"); display.setCursor(2,40); display.print("UP Down:"); display.print("0"); display.display(); } //************************* End of Setup function ******************************* void loop() { UP_Button.read(); Down_Button.read(); if (UP_Button.wasReleased() && l < 11 && calc == false) { l=l+1; display.clearDisplay(); display.setCursor(2,25); display.print("Curr:"); display.print(String(Current[l])+"mA"); display.display(); } if (Down_Button.wasReleased() && l > 0 && calc == false) { l=l-1; display.clearDisplay(); display.setCursor(2,25); display.print("Curr:"); display.print(String(Current[l])+"mA"); display.display(); } if (UP_Button.pressedFor (1000) && calc == false) { analogWrite(PWM_Pin,PWM_RES[l]); digitalWrite(Buzzer, HIGH); delay(1500); digitalWrite(Buzzer, LOW); display.clearDisplay(); timerInterrupt(); } } //************************* End of Loop function ******************************* void timerInterrupt(){ calc = true; while (Done == false) { Second ++; if (Second == 60) { Second = 0; Minute ++; } if (Minute == 60) { Minute = 0; Hour ++; } //************ Измерение напряжения батареи *********** for(int i=0;i< 100;i++) { sample=sample+analogRead(BAT_Pin); // считываем напряжение на батарее delay (2); } sample=sample/100; BAT_Voltage = sample * (Vcc/ 1024.0); temp(); //********************************************* display.clearDisplay(); display.setTextSize(2); display.setCursor(20,5); display.print(String(Hour) + ":" + String(Minute) + ":" + String(Second)); display.setTextSize(1); display.setCursor(0,25); display.print("Disch Curr: "); display.print(String(Current[l])+"mA"); display.setCursor(2,40); display.print("Bat:" + String(BAT_Voltage)+"V" ); display.setCursor(63,40); display.print("Temp:"+String(T,1)); display.setCursor(116,35); display.print("."); display.setCursor(122,40); display.print("C"); Capacity = (Hour * 3600) + (Minute * 60) + Second; Capacity = (Capacity * Current[l]) / 3600; display.setCursor(2, 55); display.print("Capacity:" + String(Capacity) + "mAh"); display.display(); if (BAT_Voltage < Low_BAT_level) { Capacity = (Hour * 3600) + (Minute * 60) + Second; Capacity = (Capacity * Current[l]) / 3600; display.clearDisplay(); display.setTextSize(2); display.setCursor(2,15); display.print("Capacity:"); display.setCursor(2,40); display.print(String(Capacity) + "mAh"); display.display(); Done = true; l = 0; analogWrite(PWM_Pin, PWM_RES[l]); digitalWrite(Buzzer, HIGH); delay(100); digitalWrite(Buzzer, LOW); delay(100); digitalWrite(Buzzer, HIGH); delay(100); digitalWrite(Buzzer, LOW); delay(100); } delay(1000); } } void temp() { Vo = analogRead(ThermistorPin); R2 = R1 * (1023.0 / (float)Vo - 1.0); logR2 = log(R2); T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); T = T - 273.15; } |