Полоумная зарядка для NI-MH аккумуляторов.

Joiner
Offline
Зарегистрирован: 04.09.2014

karl2233 пишет:

значит я не тот скетч смотрел =)

а нет желания сделать универсальную(Литий+Никель) и на 2-3 канала?

готов принять участие в части составления алгоритма,  схемы и тестирования в желез.

к сожалению, на большее у мну не хвататет знаний(вернее понимания).

про опорное.

но ведь 1,1  меньше 2,5 следовательно дискретность хужее.

кроме того, если делать, так делать нормально и поставить внешний(хотя бы на 431)?

Что такое внешний на 431, я не понял.

1.1, 2.5, 5.0 , как мне кажется, дискретность не меняется. Мне кажется, что все зависит от максимального предела измерения. Если максимальный предел 10 вольт, и измеряем напряжение максимумом 10 вольт, то дискретность максимальная, равная (для атмеги 328) 1024. 1.1 вольта подгоняем под максимум резистивным делителем.

Тоже появилась задумка сделать что-то универсальное...вроде литиевые, никелиевые..... Затея сомнительная. Может два отдельных устройства? Мне кажется, что так лучше....не утверждаю.

Очень рад единомышленнику, с удовольствием готов к сотрудничеству.

karl2233
karl2233 аватар
Offline
Зарегистрирован: 05.07.2015

431 - внешний опорник, стабильнее внутреннего Атмеги.

два устройства? не-не!

одно! Атмеги явно хватит на это.

кинь почту, зашлю наработки(без скетча, ибо нема такого у мну).

 

Joiner
Offline
Зарегистрирован: 04.09.2014

karl2233 пишет:

......., зашлю наработки.....

Дык выкладывай сюда, будем обсуждать

quartz70rus
Offline
Зарегистрирован: 12.02.2015

Думаю попробовать эту схему для зарядника, хотя я в этом совсем профан

http://arduino.ru/forum/apparatnye-voprosy/kak-sdelat-upravlenie-siloi-toka-cherez-shim#comment-147649

http://caxapa.ru/lib/charge_nimh.pdf теория

ну и хотелось бы увидеть ваш результат зарядки

Joiner
Offline
Зарегистрирован: 04.09.2014

quartz70rus пишет:

Думаю попробовать эту схему для зарядника, хотя я в этом совсем профан

http://arduino.ru/forum/apparatnye-voprosy/kak-sdelat-upravlenie-siloi-toka-cherez-shim#comment-147649

http://caxapa.ru/lib/charge_nimh.pdf теория

ну и хотелось бы увидеть ваш результат зарядки

Посмотрел, пока тоже не понял как работает эта схема. Я в своей зарядке применял ШИМ регулировку тока. Мосфет работает как ключ, и несмотря на то что микроскопический по размерам, абсолютно не греется. Аккумуляторы заряжались раза в три быстрее, чем на заводской простенькой зарядке. Это и понятно, на заводской нет регулировки тока, он там небольшой и одинаков не зависимо от емкости заряжаемого аккумулятора.

В планах на будущее изучить как влияет на состояние акумулятора зарядка импульсным током, не вредит ли ему. Если да, то придется как-то сглаживать ток.

Если мне память не изменяет, вроде как на самом аккумуляторе пульсация напряжения минимальная, а на резисторе, подключенном последовательно аккумулятору, пульсация очень заметна.

quartz70rus
Offline
Зарегистрирован: 12.02.2015

 

дайте пожалуйста ссылку на свои актуальные релизы схемы и скетча ? :)

посмотреть разобраться, а то может я решил городить не то 

 

Joiner
Offline
Зарегистрирован: 04.09.2014

quartz70rus пишет:

дайте пожалуйста ссылку на свои актуальные релизы схемы и скетча ? :)

посмотреть разобраться, а то может я решил городить не то 

Если это вопрос ко мне, то отвечу. Все что сделал описано здесь в этой теме...т.е. начал и забросил. Но отдельную разрядку для аккумуляторов с подсчетом емкости сделал(на макетке), есть здесь и фотка и скетч.

В ближайшее время постараюсь вернуться к теме. Все что нужно есть. Остается еще прикупить пару аккумуляторов новых для опытов, а то мои довольно древние.

karl2233
karl2233 аватар
Offline
Зарегистрирован: 05.07.2015

Joiner пишет:
Посмотрел, пока тоже не понял как работает эта схема. Я в своей зарядке применял ШИМ регулировку тока. Мосфет работает как ключ, и несмотря на то что микроскопический по размерам, абсолютно не греется. 

в этой схеме тоже самое!

про наработки.

у мну есть только алгоритм(хотя он какбэ известен и не секрет) и схема.

тут скорее вопрос в том, как написать программу - ибо я совершал 3 или 4 подхода к этому и сталкивался с непреодолимыми(для меня) проблемами.

я щас её перемалюю, ибо хочется сделать на 4 канала(хе-хе, "хочется" - это при том, что написать программу я не в силах) и тогда выложу.

Или давайте определимся какой вариант - на 2 или 4 банки, тогда это упростит задачу.

но суть такова(два варианта - на 2 или 4 банки): 

1. МК(Ардуино) управляет 2(4) ячейками.

2. измерение напряжения на банках происходит через мультиплексор(вариант на 4) или напрямую.

3. измерение тока - черз 2 или 4 ОУ.

4. нагрузка для разряда - ШИМ, через n-канальные мосфеты.

5. ток заряда - тоже ШИМ.

6. в самом алгоритме настройки таковы:

6.1. возможность выболра тока заряда(для никеля) - 50-100-150-200мА.

6.2. количество циклов (заряд-разряд) - думаю 5 хватит.

6.3. возможность установки напряжений "мин" и "макс"(для никеля) с шагом 50мВ(0,75-0,9 и 1,3-1,7).

6.4. зарядку лития можно сделать ШИМ или на ТР4056.

6.6. сам алгоритм зарядка для каждого типа прописатьв в программе.

6.6. измерение температуры на бнках с усьтановкой порога срабатывания(40-70С).

6.7. условия прекращения зарядки:

6.7.1. Никель - когда напряжение ерестало расти на банке в течении 20 минут или по температуре.

6.7.2 Литий - когда тока упадёт до 10% от тока заряда или по температуре. (в варианте с зарядкой на ТР4046 проще).

как-то так.

так что давайте определятся- всё зависит от автора программы - потому что это самое сложное в данном деле.

а плюшек можно накидать ещё, вопрос в том, как реализовать )))))

 

 

bachark
Offline
Зарегистрирован: 18.08.2014

Просьба не пинать за вопрос :) я не большой спец по разработке схем :)

А можно вашу ПЕРВОНАЧАЛЬНУЮ схему доработать чтобы получился автомат для подзарядки аккумуляторов когда аккумуляторы встроены в устройство ... те подключил источник питания на 7 вольт блочек автоматом начинает заряжать аккумуляторы ... отключил источник начинает работат от аккумуляторов  и плюс можно померит состояние аккумулятора ... само питаемое устройтсво основано на ардуино мега .. свободные порты есть чтобы подлкючить измерения ...

И еще в вашей схеме не указаны модели транзисторов рекомендуемые можно их указать...

И хотелось бы заряжать блок аккумуляторов у меня стоит два аккумулятора по 3.6 вольта(li ion кажется) в сумме соответсввенно 7.4в

Joiner
Offline
Зарегистрирован: 04.09.2014

bachark пишет:

................................

И хотелось бы заряжать блок аккумуляторов у меня стоит два аккумулятора по 3.6 вольта(li ion кажется) в сумме соответсввенно 7.4в

А может Вам лучше какое-нибудь готовое устройство купить ...вроде этого http://www.ebay.com/itm/New-3A-Battery-Protection-BMS-PCB-Board-for-2-Packs-3-7V-Li-ion-18650-Battery-/321811575655?hash=item4aed76f367:g:aJMAAOSwd0BVrGCu

По-моему выйдет гораздо дешевле и быстрее.

bachark
Offline
Зарегистрирован: 18.08.2014

Очень интересный вариант можно еще схемку приблизительную... непонятно где источник те БП подключать и нагрузку ... по фотографии понятно только где батарея подпаивается

bachark
Offline
Зарегистрирован: 18.08.2014

и там  так понимаю из расчета на один аккумулятор а мне нужно на 7.4 вольта батарею подключить и подзаряжать ее без переключений (переключается схема автоматом)

пардон не внемательно прочитал сначала блочек расчитан какраз на два аккумулятора те 7.4 вольта

bachark
Offline
Зарегистрирован: 18.08.2014

насчет быстрее не факт там в доставке написано с 18 августа по 14 сентября :)

bachark
Offline
Зарегистрирован: 18.08.2014

можете тогда подсказать как можно контролировать уровень заряда через подлючение вывода ардуино чтобы можно было на экране вывести или там звуком что аккумулятор уже разряжен ... вобщем простейшую схему подключения

Joiner
Offline
Зарегистрирован: 04.09.2014

bachark пишет:

.................. что аккумулятор уже разряжен ... вобщем простейшую схему подключения

Я так думаю.... землю ардуины подключить к минусу батареи, плюс первой банки соединить с аналоговым входом А0 (можно без делителя, если опорное будет 5в),...плюс второй банки (обязательно с делителем, чтобы предел измерения был не меньше 8.5 вольт)) подключить к выводу А1. Напряжение на первой банке измерится напрямую, напряжение на второй - Общее напряжение батареи минус напряжение первой банки.

Подробнее об измерении напряжения поищите в инете что-нибудь вроде "Вольтметр на ардуино", существует много подробных описаний.

Если получится измерять напряжение, то тогда запросто его контролировать, хоть звуком предупреждать, хоть светом.

P.S. У меня есть классная схемка (без ардуины). Она на двух транзисторах кт315 и светодиодике. Настраивается на какое-то минимальное напряжение (допустим 3.6 в), и соединяется с одной банкой батареи, вторая аналогичная соединяется со второй банкой. Пока напряжение на каждой из банок больше 3.6 в, диодики не светятся и платки тока практически не потребляют. Но как только напряжение какой-либо банки станет меньше 3.6 в, загорится один из светодиодов, ну а если на обеих напряжение будем меньше установленного предела, то загорятся оба :)

Если нужно, схемку могу выложить.

bachark
Offline
Зарегистрирован: 18.08.2014

выложите плиз схемку интересно даже очень ... чем задается пороговое напряжение ?

Joiner
Offline
Зарегистрирован: 04.09.2014

bachark пишет:

выложите плиз схемку интересно даже очень ... чем задается пороговое напряжение ?

Пока выкладываю видео о нем :) https://www.youtube.com/watch?v=3QyzZtBPyYY&feature=youtu.be

bachark
Offline
Зарегистрирован: 18.08.2014

а тут можно както пользователю написать типо лички или можно както емайл посмотреть ?

Русл@н
Offline
Зарегистрирован: 14.04.2016

Неможно. К сожалению. Вот тоже жду готовой схемы зарядки на дуинке. Прикинул микруха от Махх будет стоить 200р или дуинка за 120р, дуинка выходит дешевле)

marindima
Offline
Зарегистрирован: 03.05.2017

Прект затих? Хотелось бы продолжения...

MVN123P
Offline
Зарегистрирован: 29.07.2016

Пользуюсь зарядным устройством собранным 3 года назад на PIC (собрал в 3-х экземплярах для зарядки 6-ти аккумуляторов)

Ссылка: http://bezkz.su/publ/shemy/raznoe-na-mikrokontrollerah/300288-12-1-0-288.html

 

yucan
Offline
Зарегистрирован: 20.04.2015

А я такое собрал, тоже нормально работает

http://radiokot.ru/lab/controller/31/

Joiner
Offline
Зарегистрирован: 04.09.2014

У меня-то была мечта заряжать каждый аккумулятор индивидуально, каждый на своем канале, а не батарею из друх-четырех аккумуляторов. И хотелось поэксперементировать и узнать, как будут заряжаться импульсным напряжением и жить впоследствие аккумуляторы. Для этого купил 2 аккумулятора и хотел погонять их на заряд-разряд. Один заряжать нормальным способом, другой импульсным напряжением и посмотреть как со временем будет изменяться их емкость. Даже хотел собрать для этого установку, чтобы процесс шел в автомате....но хронически не хватает времени, пока это дело отложил в долгий ящик.

ЮриБас
Offline
Зарегистрирован: 13.01.2012

yucan пишет:
 А я такое собрал, тоже нормально работает http://radiokot.ru/lab/controller/31/ 

Очень примитивный и не эффективный алгоритм заряда - 15часов током 250мА.  Получается, что можно заряжать только АКБ емкостью = 2500мА, остальным этот ток не совсем будет подходить.  Кроме того разряд в 1А слишком большой.   Согласен с Joiner что нужно заряжать элементы по отдельности и импульсным током, а алгоритм заряда должен быть умным, - по дельте, по температуре и ток заряда по внутреннему сопротивлению.

 

Студент174
Offline
Зарегистрирован: 10.02.2016

Тема умерла?

Joiner
Offline
Зарегистрирован: 04.09.2014

Студент174 пишет:

Тема умерла?

В реанимации :)  Остановилась на пол пути из-за нехватки времени, и из-за обретения нового интереса к литиевым аккумуляторам. Но эксперериментальные платы лежать в целости сохранности. В планах поэксперементировать с зарядкой импульсным током, посмотреть как это отражается на скорости зарядки и долговечности аккумуляторов.

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

если кому интересно я сейчас занимаюсь этой темой. но в  качестве переключающих элементов решил использовать  ардуиновский модуль с 4 релюхами (чтобы начинающим  пришлось меньше паять), хотя народ здесь  собрался грамотный если потребуется переделают на мосфеты . уже сделано ручное управление зарядкой сами выбираете ток заряда 270 мА или 870 мА или заряд напряжением 2,45 , в этом режиме есть разрядка током 870 mA. заряд разряд останавливается при достижении напрядений 2,7 и 4,25.  работает измерение внутреннего сопротивления.  отработанна работа меню(очень просто  добавть требуемые вам новые функции).  работает автоматическая разрядка,но надо немного доработать (пока в процессе),  автоматической зарядкой не занимался, хотя часть кода написана. планирую логировать показания и затем выводить на диспелей и на комп.хочу сделать пресеты для разных аккумуляторов,   управление подсветкой , выбором скорости передачи на комп, да мало что еще придет в голову,  хотя память уже на исходе, 65% уже под кодом !!! может кто оптимизирует и поправит огрехи. все откоментированно ( для коллеги ) , все оформленно в функции. имеется модель для протеуса на ней и отрабатываю код, в железе тоже работает.   короче -  если интересно дайте знать.   

Joiner
Offline
Зарегистрирован: 04.09.2014

Если не трудно, то почему бы не выложить. Может кому-то окажется полезным.

P.S. Мне не очень понятно с напряжением 2,7 и 4,25 вольт. Не понятно, зачем релюхи. Мне кажется, что ключи или какие-то полупроводниковые элементы, регулирующие ток, гораздо лучше, удобней и универсальней. И еще...мне кажется, что каждая баночка должна жить своей жизнью, быть под собственным контролем.

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017
/*Тестер батареек v3
Скетч для подключения 3310 и 5110 84*48
Описание и схема здесь.
А также фото и видео работы.

Arduino 1.8.4   IDE для компиляции              08.01.2018
*/

#include <avr/delay.h>
#include <LCD5110_Graph.h>// библиотека дисплея
//#include <LCD5110_Basic.h>// библиотека дисплея
// -- описание  #define-----------------------------------------------------------------------------
#define buzzTONE  700                   // тональность буззера
#define buzzTIME  1                     // длительность сигнала (если нужно отключить ставим ноль)
#define buzzPIN   13                    // пин на котором буззер
#define Ch_Pin    12                    // пин на котором ключ зарядки
#define Ch_Pin_1  10                    // пин на котором дополнительный ключ зарядки
#define Ch_Pin_V  A4                    // пин который отключает постоянный ток и включает постоянное напряжение заряда (для окончания заряда)  
#define DCh_Pin   11                    // пин на котором ключ разрядки D11
#define key_up    4                     // пин кнопки вверх             D4
#define key_down  2                     // пин кнопки вниз              D2
#define key_ok    3                     // пин кнопки ок                D3
#define analogV0  A0                    // назначаем аналоговый вход    A0 (D14)
#define analogV1  A1                    // назначаем аналоговый вход    A1 (D15)
#define Litgh     A3                    // назначаем аналоговый вход    A3 (D17) подсветка

// -- описание констант ----------------------------------------------------------------------------

#define Time_UpCh    60000              // один цикл дозаряда  1 мин
#define Time_Arr     300000             // время записи в массивы 5 мин
#define anti_dr      200                // антидребезг (длительность delay(200))
#define Res_dat      0.1                // сопротивление датчика
#define Volt_min     2.7                // минимальное напряжение на батарее 
#define Volt_in_res  3.6                // напряжение для проверки внутреннего сопротивления
#define Volt_dop_res 3.6                // напряжение подключения доп.сопротивления (повышение тока)
#define Volt_min_sup 3.6                // минимальное напряжение на батарее c супервизором 
#define Volt_midl    4.15               // напряжение перехода на пониженный ток 
#define Volt_max     4.25               // напряжение для отключения заряда
#define time_koef    1.047              // коэффициент корекции внутреннего счетчика времени

float Res_DCh      = 4.9              ; // резистор нагрузки для зарядки и разрядки

// -- описание переменных ------------------------------------------------------------------------------

int knop=0                            ; // номер меню  
int t=0                               ; // адрес меню для графиков
int numGraf=0                         ; // номер графика   
int mode=1                            ; // ????

float Volt_A0 =0                      ; // напряжение на A0    
float Volt_A1 =0                      ; // напряжение на A1
float I_Ch = 0                        ; // расчетный ток заряда
float I_DCh = 0                       ; // расчетный ток заряда
float Capac_Ch = 0                    ; // расчетная емкость аккумулятора  при зарядке
float Capac_DCh = 0                   ; // расчетная емкость аккумулятора  при разрядке
float Vcc=5                           ; // величина опорного напряжения
float in_Resist =0                    ; // расчетное внутреннее сопротивление 
float in_Resist_G=0                   ; // расчетное внутреннее сопротивление для графика

unsigned long previousMillis = 0      ; // предыдущее время входа в цикл  
unsigned long startMillis = 0         ; // 
unsigned long deltaMillis= 0          ; // прошедшее время за цикл        
unsigned long Time_1 =0               ; // временная переменная 
unsigned long watch_millis =0         ; // требуется  для функции расчета времени 
unsigned long Time_Litgh =0           ; // используется для отключения подсветки
unsigned long Time_G=0                ; // используется для отсчета времени для графиков 

String Time_s                         ; // время для вывода на дисплей
String B_Ch=" OFF "                   ; //
String B_DCh=" OFF "                  ; //
                             
bool R_Ch = LOW                       ; // подключение основного тока заряда (240 mA)                     
int  R_dop = 0                        ; // подключение дополнительного  сопротивления при зарядке (830 mA) 
bool R_shunt = LOW                    ; // подключение сопротивления для разрядки (5 Om)
bool MeasRes=0                        ; // флаг измерения внутр.сопротивления
bool key=1                            ; // флаг нажатия любой клавиши (для включения подсветки)
bool End_Ch=0                         ; // флаг окончания зарядки

  int Arr_Volt[60]                    ; //  массив наряжений  для графиков
//int Arr_I_Ch[60]                    ; //  массив тока
  int Arr_I_DCh[60]                   ; //  массив тока
//int Arr_Resist[60]                  ; //  массив вн.сопротивления

extern uint8_t SmallFont[]            ; // размер шрифта
extern uint8_t MediumNumbers[]        ; // размер шрифта

String Menu_Arr[]      ={"1. Manual   ","2. Charging ","3. SisInfo  ","4. Res_in   ","5. Discharg ","6. SetUp    ","7. PrintGraf","8. Presets  "} ; //  массив пунктов меню 
//String MenuTool_Arr[]={"4.1. Manual  ","4.2.TestInRes","4.3.DisCharg ","4.4.         "} ; //  массив пунктов меню Tools

LCD5110 myGLCD(9,8,7,5,6)             ; // назначаем пины экрана (у вас свои пиы)

//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//#################################    ФУКЦИИ   ###################################################################################################################################

//**************************************************************************************************************************************************************************
// Функция отрисовки горизонтальной шкалы 
//***************************************************************************************************************************************************************************
// Start_col - начальная колонка
// Start_row - начальная строка
// Long_sh   - длина шкалы
// Max_vol   - максимальная величина
// Vol       - текущая величина
// Mode      - вид шкалы (0;1)                   : в разаработке  
// Direct    - направление (0-вправо ; 1- влево) : в разаработке  
// используется библиотека  #include <LCD5110_Graph.h>
//              функция     myGLCD.drawLine(колонка_н,строка_н,колонка_к,строка_к)
//*********************************************************************************************************************************************************************************
void Shkala_gor(float Start_col,float Start_row,float Long_sh,float Max_vol,float Vol,int Mode,int Direct){
  float y=0;    // положение метки на шкале 
     
      //if (Start_col <0){Start_col=0;}                                                 //  ограничение выхода
      if (Start_row <0){Start_row=0;}                                                   //  за пределы экрана
      if (Start_row >48){Start_row=48;}                                                 //
      //if (Start_col >84){Start_col=84;}                                               //
      if (Start_col+Long_sh >84){myGLCD.print("Veri long !!! ", 10, 20);}               // предупреждене для наладки
      if (Vol>Max_vol){int Vo1=Max_vol;}                             
    
  myGLCD.drawLine(Start_col        , Start_row, Start_col        , Start_row+4);        // рисуем ограничение оси
  myGLCD.drawLine(Start_col+Long_sh, Start_row, Start_col+Long_sh, Start_row+4);        // рисуем ограничение оси
 
  for (int i = Start_col+2 ; i < Long_sh+Start_col; i +=2) {                            // 
      myGLCD.drawLine(i, Start_row+1,i , Start_row+3)  ;  }                             // рисуем ось
      
      y= ( Long_sh * Vol )/ Max_vol ;                                                   // расчет положения метки текущего положения 
      
  for (int i = Start_col ; i < Start_col+y ; i++) {                                     // 
       myGLCD.drawLine(i, Start_row+1, i, Start_row+3)  ;  }                            // рисуем метку
  }
//*********************************************************************************************************************************************************************************
/*
//*********************************************************************************************************************************************************************************
//*
//*********************************************************************************************************************************************************************************
// возвращает время прошедшее от  "watch_time"   в секундах или минутах в зависимости от парамметра "mode"  
// unsigned long  watch_millis                                                    ; //значение millis() для текущего времени  добввить в GLOBAL переменные
// watch_t  - входной параметр функции - текущее время в минутах (00:00 - 23:59) 
// mode - режим  1- возвращаем  минуты  ; 2- возвращает секунды 
// пример :   int watch_time=0                                                    ; // текущее время в минутах(00:00 - 23:59)  добввить в GLOBAL переменные
//            watch_time=watch_min(watch_time,2)                                  ; //получаем новое значение времени
//
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
unsigned long watch_min(unsigned long watch_t, int mode) {     // отсчет  времени  от watch_t  в минутах  или секундах
   
   unsigned long time_                             ; // обьяаление локальных переменных
   unsigned long watch_delta=0                     ; // 
   unsigned long watch_millis=0                    ; //
   unsigned long del_x=0                           ; // внутренняя переменная   прошедшее вреля вминутах или секундах   
   unsigned long day_x=0                           ; // внутренняя переменная   минут или секунд в сутках
   time_ = millis()                                ; // взять время от начала работы процессора
 
 switch (mode){ 
    case 1:   del_x=60000 ;  day_x=1439  ; break   ; //  для вывода в минутах
    case 2:   del_x=1000  ;  day_x=86399 ; break   ; //  для вывода в секундах
 }
   
 watch_delta = (time_ - watch_millis)/del_x        ; // изменение в минутах или секундах
 if (watch_delta>0) {  watch_millis = time_; }       // если  время не изменялось  то заносится время прошедшее с включения процессора
 
 if ( watch_t + watch_delta > day_x){
    // watch_t=0;  return 0                          ; // если привышает 24 часа   возвращаем  ноль (1439 мин = 86399 сек = 23:59)
 }else{                                                // в противном случае
   unsigned long time_out =watch_t + watch_delta     ; // присваеваем расчетное время переменной 
   return time_out                                   ; // возвращает  время в количестве минут  или секунд
 }                                    
}
//**** конец функции  расчет текущего времени в минутах  watch_min   ****************************************************************************************************************

//*********  функция преобразования кол-ва секунд  в стринг  m:s или h:m в зависимости от их колличества    *************************************************************************
// int time_sec -   количество секунд 
// возвращает String в виде "00:00" (":"  мигает когда выводим часы и минуты)
// все переменные локальные !
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   String sec2hour (unsigned long time_sec ){
    String time_out=""                                                                              ; // обьявление переменных  возращаемый  стринг
    String time_m="";                                                                               ; // вычисленные минуты и преобразованные  в стринг 00 
    String time_h="";                                                                               ; // впереди стоящий "0" для часов  
    String ed_izm="m:s";                                                                            ; // ед. измерения если прошло больше 60 мин. (по умолчанию)
    String razdel=":"                                                                               ; // переменная  для разделителя 
    
    while (time_sec >86399){time_sec-=86399 ;}                                                        // если прошли сутки  (может и не одни, я их кол-во не считаю)
    if (time_sec > 3599){{if (time_sec%2>0){razdel=" ";}else{razdel=":";}};time_sec/=60;ed_izm="h:m";}// если больше  59мин 59сек вывдим "h:m"    выбираем разделитель при мигании если индицируем "h:m"
    if (time_sec%60<=9){ time_m="0"+String(time_sec%60);}else{time_m=String(time_sec%60);}            // формируем стринг с минутами 00
    if (time_sec/60<10) {time_h="0";}                                                                 // если кол-во минут < 10 дописываем впереди "0"

  // -------- формирование стринга для вывода  -------------------------------------------------------------------------------------------------------------------------------
  // time_out= time_h + String(time_sec/60)+razdel+time_m+" "+ed_izm                                ; // формируем стринг 00:00
     time_out= time_h + String(time_sec/60)+razdel+time_m                                           ; // формируем стринг 00:00
     return  time_out                                                                               ; // возвращаем сформированыый стринг 00:00
  }  
 //********* конец измерения времени *************************************************************************************************************************************************
*/
//===================================================================================================================================================================================
//*******************************************     Display Draw Function    **********************************************************************************************************
// выводит на экран полную информацию о конкретной батарее
// Head - заголовок экрана
// Volt - выодимое напряжение
// Curr - текущщий ток
// Capac-  расчтная емкость
// in_Resist - внутреннее сопротивлене
// Time -  время заряда
// mode - флаг для замены тока на внутреннее сопротивление при выводе   отчета (0-заряд / 1-отчет)  
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void draw_bat(String Head,float Volt, float Curr, float Capac, float in_Resist, String Time,int mode) {                                    // функция вывода информации на Дисплей
   
   myGLCD.clrScr()                                ;  // чистим экран
  //--------------  формируем заголовок -----------------------------------------------------------------------------------
   myGLCD.invertText(true)                        ;  // инверсный текст
   String ind= Ind_Klych();
   myGLCD.print(Head+ind, LEFT, 1)                ;  // вывод на экран
   myGLCD.invertText(false)                       ;  // нормальный текст
   myGLCD.drawLine(0, 9, 84, 9)                   ;  // линия  отделяет заголовок
  
  //---------формируем экран для вывода информации  ----------------------------------------------------------------------
                                                    // наименование  измеряемых величин
      myGLCD.print("Volt" ,0, 11)                 ; // напряжение на батарее       V
  //---------------------------------------------------------------------------------------------------------------------  
   if(mode==0){                                     // режим заряда
      myGLCD.print("Curr" ,0, 20)                 ; // ток  разряд/заряд           A 
   }else{                                           // заряд окончен 
      myGLCD.print("R_in" ,0, 20)                 ; // внутреннее сопротивление
   }
  //--------------------------------------------------------------------------------------------------------------------
   myGLCD.print("Capac",0, 29)                    ; // емкость заряда/разряда      mAh  
                                                          
   myGLCD.print(":",29, 11)                       ; //  разделители
   myGLCD.print(":",29, 20)                       ; // 
   myGLCD.print(":",29, 29)                       ; // 
  //----------- еденицы измерения ----------------------------------------------------------------------------------------
   myGLCD.print( "mV",66, 11)                     ; // напряжение на батарее       mV
  //----------------------------------------------------------------------------------------------------------------------
  if (mode==0){                                     // режим заряда
    myGLCD.print( "mA",66, 20)                    ; // ток  разряд/заряд           mA
  }else{                                            // заряд окончен 
    myGLCD.print( "mR",66, 20)                    ; // внутреннее сопротивление  mOm
  } 
    myGLCD.print("mAh",66, 29)                    ; // емкость заряда/разряда      mAh
  //--------- выводим значения ---------------------------------------------------------------------------------------------
     myGLCD.printNumF(Volt  , 3, 35, 11)          ; // вывети показания вльтметра с 3 знаками после 0   
  //------------------------------------------------------------------------------------------------------------------------
   if (mode==0){                                    // режим заряда
       myGLCD.printNumF(Curr  , 0, 35, 20)        ; // вывести текущий ток  в mA 
   }else{                                           // заряд окончен 
       myGLCD.printNumF( in_Resist , 0, 35, 20)   ; // внутренне сопротивление
   }
  //------------------------------------------------------------------------------------------------------------------------
   myGLCD.printNumF(Capac , 0, 35, 29)            ; // вывести заряд в mAh
   myGLCD.update()                                ; // обновление экрана 
}
//********* конец функции вывода на дисплей  DROW_BAT()  ***************************************************************************************************************************
//*******************************************     Display Draw Function    **********************************************************************************************************
// выводит на экран полную информацию о напряжениях и токах
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void SisInfo() {                                     // функция вывода информации на Дисплей
    //String Head = "SisInfo"                                                                       ;  // заголовок
    All2LOW()                                                                                       ;  // сбросить  все ключи
    do{
      myGLCD.clrScr()                                                                               ;  // чистим экран
        // --------------------------  ОБРАБОТКА КНОПОК  ------------------------------------------------------------------------------------------
        // -------  ручное переключение зарядного тока  кнопкой "UP"  -----------------------------------------------------------------------------             
            if (digitalRead(key_up)==LOW && R_shunt==LOW){
                                             delay(anti_dr)                                          ; // андидребезг
                                             R_dop++                                                 ; // инкремент 
                                             if (R_dop>3 ){R_dop=0 ;}                                ; // организуем выбор "по кругу" 
            }                                    
        // ---- обработка кнопки "UP" ------------------------------------------------------------------ 
          if (R_dop==3){                                                                             ; // заряд напряжением   
              B_Ch =" OFF "                                                                          ; // для BAR Menu
              digitalWrite(Ch_Pin  ,HIGH)                                                            ; // включаем 
              digitalWrite(Ch_Pin_1,LOW)                                                             ; // отключаем 
              digitalWrite(Ch_Pin_V,HIGH)                                                            ; // включаем заряд напряжением
          }else if (R_dop==2){                                                                       ; // заряд  полным током    ( 830мА )  
              B_Ch =" Vch "                                                                          ; // для BAR Menu
              digitalWrite(Ch_Pin  ,HIGH)                                                            ; // 
              digitalWrite(Ch_Pin_1,HIGH)                                                            ; // 
              digitalWrite(Ch_Pin_V,LOW)                                                             ; // 
          }else if (R_dop==1){                                                                       ; // заряд основным током( 240мА ) 
              B_Ch =" Ch+ "                                                                          ; // для BAR Menu
              digitalWrite(Ch_Pin  ,HIGH)                                                            ; //  
              digitalWrite(Ch_Pin_1,LOW )                                                            ; //                                           
              digitalWrite(Ch_Pin_V,LOW)                                                             ; // 
          }else if (R_dop==0){
              B_Ch =" Ch  "                                                                          ; // для BAR Menu         
              digitalWrite(Ch_Pin  ,LOW )                                                            ; // оключить заряд
              digitalWrite(Ch_Pin_1,LOW )                                                            ; // 
              digitalWrite(Ch_Pin_V,LOW)                                                             ; // 
          } 
        // -------  ручное  вкл/выкл  разрядного шункта кнопкой "DOWN"   --------------------------------------------------------------------------       
            if (digitalRead(key_down)==LOW){                                                           // подключение щунта и автом. отключение зарядки аккумулятора 
                                             delay(anti_dr)                                          ; // антидребезг
                                             R_shunt=!R_shunt                                        ; // инверсия уровня на выводе D11
                                             R_dop=0                                                 ; // отключаем заряд аккумулятора
            }
        // ---  управление разрядным шунтом  -------------------------------------------------------------------------------------------------------            
            if (R_shunt==HIGH){digitalWrite(DCh_Pin,HIGH);}else{digitalWrite(DCh_Pin,LOW); }           // вкл./выкл. шунта 
      //-------------------------------- конец  обработки кнопок ---------------------------------------------------------------------------------        
     
      //---------формируем экран для вывода информации  ----------------------------------------------------------------------
      myGLCD.print("V_AO" ,0, 1)                          ; // напряжение      V
      myGLCD.print("V_A1" ,0, 10)                         ; // напряжение      V 
      myGLCD.print("I_Ch" ,0, 19)                         ; // ток            mA
      myGLCD.print("I_DCh",0, 28)                         ; // ток            mA
      //--------------------------------------------------------------------------------------------------------------------
      myGLCD.print(":",30, 1)                             ; //  разделители
      myGLCD.print(":",30, 10)                            ; // 
      myGLCD.print(":",30, 19)                            ; // 
      myGLCD.print(":",30, 28)                            ; //
      //----------- еденицы измерения ----------------------------------------------------------------------------------------
      myGLCD.print( "mV",67, 1)                           ; // напряжение на батарее      mV
      myGLCD.print( "mV",67, 10)                          ; // напряжение на датчике тока mV
      myGLCD.print( "mA",67, 19)                          ; // ток  заряда                mA
      myGLCD.print( "mA",67, 28)                          ; // ток  разряда               mA
      //--------- выводим значения ---------------------------------------------------------------------------------------------
      Izmerenie()                                         ; // производим измерение и расчет
      myGLCD.printNumF(Volt_A0, 3, 36, 1)                 ; // вывети показания вльтметра с 3 знаками после 0   
      myGLCD.printNumF(Volt_A1, 3, 36, 10)                ; // вывети показания вльтметра с 3 знаками после 0   
      myGLCD.printNumF(I_Ch   , 0, 36, 19)                ; // вывести текущий ток  в mA 
      myGLCD.printNumF(I_DCh  , 0, 36, 28)                ; // вывести текущий ток  в mA 
     //--- формируем down BAR  на экране ---------------------------------------------------------------------------------------
     if (R_shunt==HIGH){B_DCh="OFF ";}else{B_DCh="DCh ";}   // формируем надписи для down BAR
     Bar_Menu( B_Ch ,"Menu" ,B_DCh )                      ; // выводим Bar_Menu
     //-------------------------------------------------------------------------------------------------------------------------
     myGLCD.update()                                      ; // обновление экрана 
  }while(digitalRead(key_ok)==HIGH)                       ; // выйти если нажата "ОК"
   delay(anti_dr)                                         ; // антидребезг
   buzz()                                                 ; // звуковой сигнал                            
}
//********* конец функции вывода на дисплей  SisInfo()  ***************************************************************************************************************************
//===================================================================================================================================================================================
//=================================================================================================================================================================================
//***********  функция расчета внутреннего сопротивления аккумулятора  ************************************************************************************************************
// numPIN    - номер PIN для управления подключением нагрузочного  сопротивления
// voltPIN   - номер пина на котором снимается напряжение 
// Res_DCh   - величина  сопротивления-нагрузки  обьявлена в начале программы как GLOBAL
// kol_izm   - колличество измерений 
// в процессе разработки
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
float in_resist_accum (int numPIN,float analogV0,float Res_DCh,int kol_izm){
                                                                                            
int res_accum =0.0                                                          ; //  внутренняя переменная  сопротивление аккумулятора 
float U1 = 0.0                                                              ; //                         напряжение с нагрузкой
float U2 = 0.0                                                              ; //                         напряжение без нагрузки  
float volt_A0 =0.0                                                          ; // внутренняя переменная
int   x=0                                                                   ; //                         для цикла  
String ST_1="*** ERROR ***"                                                 ; //
String Head="InternalResist"                                                ; //

  if(kol_izm>5){                                                            ; // если кол-во измерений > 5
  //--------------  формируем заголовок ---------------------------------------------------------------------------------------------------
     myGLCD.clrScr()                                                         ; // чистим экран
     myGLCD.invertText(true)                                                 ; // инверсный текст
     myGLCD.print(Head, LEFT, 1)                                             ; // вывод на экран
     myGLCD.invertText(false)                                                ; // нормальный текст
     myGLCD.drawLine(0, 9, 84, 9)                                            ; // линия  отделяет заголовок
     //-------- отображаем на дисплее напряжение на аккумуляторе  ------------------------------------------------------------------------
     volt_A0=adc(analogV0,Vcc)                                               ; // измеряем напряжение на A0
     myGLCD.print("Voltage",CENTER,13)                                       ; // выводим наименование действия
     myGLCD.setFont(MediumNumbers)                                           ; // установим ,большой шрифт
     myGLCD.printNumF(volt_A0,2,18,22)                                       ; // выводим значение напряжения
     myGLCD.setFont(SmallFont)                                               ; // установим маленький шрифт
     myGLCD.print(" V",65,31)                                                ; // выводим единицы измерения
  // ------ BAR_Menu ---------------------------------------------------------------                                                      
     myGLCD.invertText(true)                                                 ; // инверсный текст              
     myGLCD.print("     | ok |     ",CENTER, 40)                             ; // вывести заголовок 
     myGLCD.invertText(false)                                                ; // нормальный текст
  // -------------------------------------------------------------------------------
     myGLCD.update()                                                         ; // обновление экрана
     
     while(digitalRead(key_ok)==HIGH)                                        ; // ждем нажатия кл. "ок"
     delay(anti_dr);buzz()                                                   ; // антидребезг, звуковой сигнал 
   }
  //---  формируем  заголовок для измерения внутреннего сопротивления ------------------------------------------------------------------
     myGLCD.clrScr()                                                         ; // чистим экран
     myGLCD.invertText(true)                                                 ; // инверсный текст
     myGLCD.print(Head, LEFT, 1)                                             ; // вывод на экран
     myGLCD.invertText(false)                                                ; // нормальный текст
     myGLCD.drawLine(0, 9, 84, 9)                                            ; // линия  отделяет заголовок
     myGLCD.print("Measure",CENTER,13)                                       ; // выводим наименование действия   

  for (x=kol_izm; x>=1 ; x--){                                                 // измеряем   kol_izm  раз
    myGLCD.setFont(MediumNumbers)                                            ; // установим маленький шрифт
    myGLCD.print(String(x),CENTER,22)                                        ; // выводим оставшееся кол-во измерений
    //--- отрисовка ползунка заряда --------------------------------------------------------------------------------------------------------
    Shkala_gor(0,42,83,(kol_izm),(kol_izm-(x-1)),0,0)                        ; // отрисовка шкалы 
    myGLCD.update()                                                          ; // обновление экрана 
    //---- измерение внутреннего сопротивления----------------------------------------------------------------------------------------------------------------------------------------
    digitalWrite(numPIN, HIGH)                                               ; // 1. подключаем измерительное сопротивление (открываем транзистор)
    delay (500)                                                              ; // задержка 0.5 сек для измерения
    volt_A0=adc(analogV0,Vcc)*1000                                           ; // измеряем напряжение на A0
    U1+= volt_A0                                                             ; // 2. расчитываем напряжение на аккум.  с  сопротивлением и складываем для расчета среднего значения
     
    digitalWrite(numPIN, LOW)                                                ; // 3. отключаем  измерительное сопротивление (закрываем транзистор)
    delay (500)                                                              ; // задержка 0.5 сек
    volt_A0=adc(analogV0,Vcc)*1000                                           ; // измеряем напряжение на A0
    U2+=volt_A0                                                              ; // 4. расчитываем  напряжение на аккум. без сопротивления и складываем для расчета среднего значения
}
  myGLCD.setFont(SmallFont)                                                  ; // установим маленький шрифт
// ---- расчет внутреннего сопротивления  ----------------------------------------------------------------------------------------------------------------------------------------
    U1/=kol_izm ; U2/=kol_izm                                                ; // 5. вычисляем среднее напряжение
    res_accum = (U2-U1)*1000/U1*Res_DCh                                      ; // 6. расчитываем  внутреннее сопротивление аккумулятора  

  if(kol_izm>5){
// ---- описание качества аккумулятора  -----------------------------------------      
   if (res_accum>10 && res_accum<=150){ST_1="*Exellent*";}                     //
    else if (res_accum>150 && res_accum<=250){ST_1="* Good *";}                //
     else if (res_accum>250 && res_accum<=350){ST_1="*Marginal*";}             //
      else if (res_accum>350 && res_accum<500){ ST_1="- Poor -";}              //
       else if (res_accum>500){ST_1="- Fail -";}                               //
// ------------------------------------------------------------------------------
   
      myGLCD.print(ST_1,CENTER,12)                                            ; // 
      myGLCD.printNumF(U2/1000,3,0,22)                                        ; // выводим напряжение измерения 
      myGLCD.print("V",30,22)                                                 ; // 
      myGLCD.printNumF((U2/Res_DCh/1000),3,0,31)                              ; // выводим ток измерения
      myGLCD.print("A",30,31)                                                 ; // 
      myGLCD.setFont(MediumNumbers)                                           ; // установим ,большой шрифт
      myGLCD.print(String(res_accum),37,22)                                   ; // выводим внутреннее сопротивление аккумулятора
      myGLCD.setFont(SmallFont)                                               ; // установим маленький шрифт
      myGLCD.print("mR",72,31)                                                ; //
// ------ BAR_Menu ---------------------------------------------------------------    
      myGLCD.invertText(true)                                                 ; // инверсия текта
      myGLCD.print("     | ok |     ",CENTER, 40);                            ; // вывести заголовок 
      myGLCD.invertText(false)                                                ; // нормальный текст
// -------------------------------------------------------------------------------
      myGLCD.update()                                                         ; // обновление экрана
  } //-- конец if(kol_izm>5) -----------------------------------------------------
     return  res_accum                                                       ; //  возвращаем внутреннее сопротивление аккумулятора
}
//********** конец функции расчета внутреннего сопротивления  аккумулятора   ******************************************************************************************************
//============================================================================================================================================================================    
//***********************************************************************************************************************************************************************************
 void buzz(){
    for(int i=0;i<=buzzTIME;i++){       //сигнал буззера
        digitalWrite(buzzPIN,HIGH);
        delay(buzzTONE);
        digitalWrite(buzzPIN,LOW);
        delay(buzzTONE);
   }
 }
//***********************************************************************************************************************************************************************************
/*
//***********************************************************************************************************************************************************************************
// вывод окошка с сообщением
// St_1 - первая строка
// St_2 - вторая строка
// mode - признак вывода кнопки "ok" (1-"ok")
//****************************************************************************************************************************************************************************------
byte Msg_disp(String St_1,String St_2,int mode) {
     myGLCD.clrScr()                                         ; // чистим экран 
       myGLCD.invertText(false)                                ; // отключаем инверсию
       
       myGLCD.drawRect(5,10,79,35)                             ; // рисуем  окно для сообщения                         
       myGLCD.drawLine(8,36,81,36)                             ; // рисуем  тень  
       myGLCD.drawLine(8,37,81,37)                             ; // рисуем  тень  
       myGLCD.drawLine(80,12,80,37)                            ; // рисуем  тень  
       myGLCD.drawLine(81,12,81,38)                            ; // рисуем  тень  

       myGLCD.print(St_1,CENTER, 15)                           ; // вывести заголовок
       myGLCD.print(St_2,CENTER, 25)                           ; // вывести заголовок 
    //-----------------------------------------------------------------------------------------
      if (mode==1){                                              // выводим кнопку "ок" 
          myGLCD.invertText(true)                              ; // включаем инверсию
          myGLCD.print(" ok ",CENTER, 40)                      ; // вывести заголовок 
          myGLCD.invertText(false)                             ; // отключаем инверсию
      }
    //-----------------------------------------------------------------------------------------   
   myGLCD.update()                                             ; // обновление экрана 
   if (mode==1){while (digitalRead(key_ok)==HIGH);}              // ждем нажатия кл. "ок"
   }
//********************************************************************************************************************************************************************************
*/
//********************************************************************************************************************************************************************************
//*******************************************   Функция вывода сообщений   **************************************************************************************************
// Head - заголовок
// ST_1 - 1 строка
// ST_2 - 2 строка
// mode -  отображение кнопки "ок"
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void draw_Msg(String Head, String ST_1, String ST_2,int mode) {   // функция вывода информации на Дисплей
     if (Head==""){Head="    MESAGE     ";}
    
     myGLCD.setFont(SmallFont)                                              ;  // установим маленький шрифт
     myGLCD.clrScr()                                                        ;  // чистим экран
    //--------------  формируем заголовок ---------------------------------------------------------------------------------------------------------------------------------------
    
     myGLCD.invertText(true)                                                ;  // инверсный текст
     myGLCD.print(Head, LEFT, 1)                                            ;  // вывод на экран
     if (mode==1){myGLCD.print("     | ok |     ",CENTER, 40) ;}               // вывести заголовок 
     myGLCD.invertText(false)                                               ;  // нормальный текст
     myGLCD.drawLine(0, 9, 84, 9)                                           ;  // линия  отделяет заголовок
   
     myGLCD.print(ST_1, CENTER , 15)                                        ;  // вывод на экран
     myGLCD.print(ST_2, CENTER , 27)                                        ;  // вывод на экран
      
     myGLCD.update()                                                        ;  // обновление экрана 
     if (mode==1){ while(digitalRead(key_ok)==HIGH){}; }                       // ждем нажатия кл. "ок"
}
//********************************************************************************************************************************************************************************

//================================================================================================================================================================================
//********************************************************************************************************************************************************************************
//  функция производит измерения на аналоговых входах и расчитывает токи  и емкость на основании известных сопротивлений  
//********************************************************************************************************************************************************************************
 void Izmerenie(){
             previousMillis=previousMillis+deltaMillis                                         ; // подготовка данных для работы со временем
             deltaMillis=millis()-previousMillis;                                              ; //
           
           // ----  измеряем и расчитываем напряжение  ---------------------------------------------------------------------------------------------      
             Volt_A0 = adc(analogV0,Vcc)                                                       ; // измеряем напряжение на  аккумуляторе  +
             Volt_A1 = adc(analogV1,Vcc)                                                       ; // измеряем напряжение на Res_dat  
           
           // --- расчет токов и емкости заряда ----------------------------------------------------------------------------------------------------
             if(digitalRead(Ch_Pin) ==HIGH){                                                     // если режим разрядки или определения внутреннего соротиаления
                I_Ch  = ((Volt_A1-Volt_A0)*1000/ Res_dat*1000)/1000                            ; // расчет тока заряда  (абсолютное значение)
                Capac_Ch  = Capac_Ch + ((I_Ch* deltaMillis*1000)/3600000)/1000                 ; // расчет емкости при  заряде  mAh
                I_DCh=0;Capac_DCh =0                                                           ; //
             }
             else if(digitalRead(DCh_Pin) ==HIGH){                                               // если режим разрядки или определения внутреннего соротиаления
                I_DCh  =  abs(Volt_A0/Res_DCh)*1000                                            ; // расчет тока разряда  (абсолютное значение)
                Capac_DCh = Capac_DCh+((I_DCh* deltaMillis*1000)/3600000)/1000                 ; // расчет емкости при  заряде  mAh
                I_Ch=0;Capac_Ch =0                                                             ; //   
             }      
 }
//********************************************************************************************************************************************************************************
//*************************************************************************************************************************************************************************
// функция измерения напряженеия питания      (функция от Okmor)
//*************************************************************************************************************************************************************************
long readVcc() {    
  int Prior_ADMUX;
  Prior_ADMUX =ADMUX; 
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference
  #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)                              ;
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
    ADMUX = _BV(MUX5) | _BV(MUX0)                                                                   ;
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
    ADMUX = _BV(MUX3) | _BV(MUX2)                                                                   ;
  #else
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)                                          ;
  #endif  

  delay(75)                         ; // ожидаем для успоения Vref 
  ADCSRA |= _BV(ADSC)               ; // начало преобразования
  while (bit_is_set(ADCSRA,ADSC))   ; // измерение

  uint8_t low  = ADCL               ; // must read ADCL first - it then locks ADCH  
  uint8_t high = ADCH               ; // unlocks both
  
  long result = (high<<8) | low     ; // установка регистра в 0
  ADMUX = Prior_ADMUX               ; // 
  result = 1125300L / result  /1000    ; // расчитываем Vcc (in mV); 1125300 = 1.1*1023*1000
  return result                     ; // Vcc в милливольтах
}
//******  конец readVcc ()*************************************************************************************************************************************************
//*************************************************************************************************************************************************************************
// функция измерения напряжения на входе с ресемплингом 
// Analog_in  - обозначение аналогового входа
// Vcc        - напряжение питания
// пример float V_in=adc("A0", 4.99)           (функция от dimax) 
//*************************************************************************************************************************************************************************
float adc(int Analig_in, float Vcc){
  uint32_t adc_buff=0                           ; //  инициализируем внутреннюю переменную
  for (int n=0; n<=4095; n++ ) {                  // 
      adc_buff+= analogRead(Analig_in);                  // в цикле снимаем показание со входа А0 4096 раз      
    }
   adc_buff >>=6                                ; // 65472 full scale 16bit
  return (float)adc_buff/65472*Vcc              ; // расчитываем и выходм из функции возвращая расчитанное значение
}
//*******  конец adc()*****************************************************************************************************************************************************
//========================================================================================================================================================================
//**************************************************************************************************************************************************************************
//  функция сброса всех ключей в LOW
//**************************************************************************************************************************************************************************
void All2LOW(){
     digitalWrite(Ch_Pin  ,LOW)                                                                     ; // отключаем ключ зарядки аккумулятора
     digitalWrite(Ch_Pin_1,LOW)                                                                     ; // отключаем доп.ключ зарядки аккумулятора
     digitalWrite(Ch_Pin_V,LOW)                                                                     ; // отключаем ключ зарядки напряжением
     digitalWrite(DCh_Pin ,LOW)                                                                     ; // отключаем ключ нагрузки  
     digitalWrite(buzzPIN ,LOW)                                                                     ; // отключаем buzz
}
//*************************************************************************************************************************************************************************

//********************************************************************************************************************************************************************************
// функция ручного управления ключами для  заряда, разряда и контроля за напряжениями и токами  (рабочая !!!  но требует доработки)
// использует функцию adc(analogV0,Vcc) , Izmerenie() ,draw_bat("Header"+ind,Volt_A0,I_Ch,Capac_Ch,in_Resist,Time_s,1), Ind_Klych() 
//********************************************************************************************************************************************************************************
 void Manual(){    
  bool Return = 0                                                                                   ; // флаг выхода из функции (1- выход)
  bool Fin_Resist=0                                                                                 ; // флаг  проверки внутреннего сопротивления  батареи (0-не был проверен/ 1- был проверен)
  float I=0                                                                                         ; // переменная для вывода тока
  float Capac =0                                                                                    ; //                       емкости батареи 
  key=1                                                                                             ; //  вкл подсветки      
 
  // ---- сброс  ключей и переменных при входе в функцию ------------------------------------------------------------------------------------------
     All2LOW()                                                                                      ; // все ключи в 0 
    
     previousMillis = 0                                                                             ; // предыдущее время входа в цикл  
     deltaMillis= 0                                                                                 ; // прошедшее время за цикл      
     watch_millis =0                                                                                ; // требуется  для функции расчета времени
     startMillis =0                                                                                 ; //
     R_dop=0                                                                                        ; // отключить 
     R_shunt=0                                                                                      ; // отключить шунт 
     Volt_A0=0                                                                                      ; // обнуляем напряжение батареи   
     I_Ch = 0                                                                                       ; //          ток заряда батареи   
     I_DCh= 0                                                                                       ; //          ток разряда батареи   
     Capac_Ch=0                                                                                     ; //          емкость батареи   
     Capac_DCh=0                                                                                    ; //          емкость батареи   
     in_Resist=0                                                                                    ; //          внутреннее сопротивление  
  //----------------------------------------------------------------------------------------------------------------------------------------------- 
  do { // делать пока не нажата кнопка "OK" 
           
           Izmerenie()                                                                              ; // произвести измерения напряжений и расчет токов и емкости 
        // --------------------------  ОБРАБОТКА КНОПОК  -----------------------------------------------------------------------------------------
        // -------  ручное переключение зарядного тока  кнопкой "UP"  -----------------------------------------------------------------------------             
            if (digitalRead(key_up)==LOW && R_shunt==LOW){
                                             delay(anti_dr)                                          ; // андидребезг
                                             R_dop++                                                 ; // инкремент 
                                             if (R_dop>3 ){R_dop=0 ;}                                ; // организуем выбор "по кругу" 
            }                                    
        // ---- обработка кнопки "UP" ------------------------------------------------------------------ 
          if (R_dop==3){                                                                             ; // заряд напряжением   
              B_Ch =" OFF "                                                                          ; // для BAR Menu
              digitalWrite(Ch_Pin  ,HIGH)                                                            ; // включаем 
              digitalWrite(Ch_Pin_1,LOW)                                                             ; // отключаем 
              digitalWrite(Ch_Pin_V,HIGH)                                                            ; // включаем заряд напряжением
          }else if (R_dop==2){                                                                       ; // заряд  полным током    ( 830мА )  
              B_Ch =" Vch "                                                                          ; // для BAR Menu
              digitalWrite(Ch_Pin  ,HIGH)                                                            ; // 
              digitalWrite(Ch_Pin_1,HIGH)                                                            ; // 
              digitalWrite(Ch_Pin_V,LOW)                                                             ; // 
          }else if (R_dop==1){                                                                       ; // заряд основным током( 240мА ) 
              B_Ch =" Ch+ "                                                                          ; // для BAR Menu
              digitalWrite(Ch_Pin  ,HIGH)                                                            ; //  
              digitalWrite(Ch_Pin_1,LOW )                                                            ; //                                           
              digitalWrite(Ch_Pin_V,LOW)                                                             ; // 
          }else if (R_dop==0){
              B_Ch =" Ch  "                                                                          ; // для BAR Menu         
              digitalWrite(Ch_Pin  ,LOW )                                                            ; // оключить заряд
              digitalWrite(Ch_Pin_1,LOW )                                                            ; // 
              digitalWrite(Ch_Pin_V,LOW)                                                             ; // 
          } 
        // -------  ручное  вкл/выкл  разрядного шункта кнопкой "DOWN"   --------------------------------------------------------------------------       
            if (digitalRead(key_down)==LOW){                                                           // подключение щунта и автом. отключение зарядки аккумулятора 
                                             delay(anti_dr)                                          ; // антидребезг
                                             R_shunt=!R_shunt                                        ; // инверсия уровня на выводе D11
                                             R_dop=0                                                 ; // отключаем заряд аккумулятора
            }
        // ---  управление разрядным шунтом  --------------------------------------------------------------------------------------------------------            
            if (R_shunt==HIGH){digitalWrite(DCh_Pin,HIGH);}else{digitalWrite(DCh_Pin,LOW); }           // вкл./выкл. шунта 
        //-------------------------------- конец  обработки кнопок ----------------------------------------------------------------------------------                     
        // ------ если батарея отвутствует ----------------------------------------------------------------------------------------------------------
        if (Volt_A0<1){                                                                               //
              All2LOW()    ;
              draw_Msg(""," NO BATTERY " , String (Volt_A0)+" v",1)                                ; // вывести сообщение
        }
        // ---  если батарея разряжена  -----------------------------------------------------------------------------------------------------------------   
        else if (Volt_A0<Volt_min ){                                                                  //
              All2LOW()                                                                           ; // все ключи в 0 
              draw_Msg(""," BATTERY LOW ", String (Volt_A0)+" v",1 )                              ; // вывести сообщение
        }
        //----- если батарея  в процессе заряда/разряда ---------------------------------------------------------------------------------------------
        else  if (Volt_A0>=Volt_min && Volt_A0<=Volt_max){  
               // ---- измеряем внутреннее сопротивление аккумулятора----------------------------------------------------------------------------------     
               if ((Volt_A0 > Volt_in_res && Volt_A0 < (Volt_in_res+0.1)) && Fin_Resist == 0){         // измерение внутреннего сопротивления  при напряжении = 3.6v  
                  in_Resist=in_resist_accum (DCh_Pin , analogV0, Res_DCh,5 )                         ; // измерение внутреннего сопротивления аккумулятора    (5 раза) 
                  Fin_Resist=1                                                                       ; // флаг о проведенном измерении внутреннего сопротивления
               }  
         // --------------------------------------------------------------------------------------------------------------------------------------------
               if ( R_shunt==1){I=I_DCh;Capac=Capac_DCh;}else{I=I_Ch;Capac=Capac_Ch;}                  // если разряжаем выводим ток разряда , емкость  разряда  
               draw_bat("Manual    ",Volt_A0,I,Capac,in_Resist,Time_s,0)                             ; // выводим информацию 
               //--- отрисовка ползунка заряда ---------------------------------------------------------------------------------------------------------
               Shkala_gor(0,36,83,(Volt_max-Volt_min),(Volt_A0-Volt_min),0,0)                        ; //  работает
               //--- формируем down BAR  на экране -----------------------------------------------------------------------------------------------------
               if (R_shunt==HIGH){B_DCh="OFF ";}else{B_DCh="DCh ";}                                    // формируем надписи для down BAR
               Bar_Menu( B_Ch ,"Menu" ,B_DCh )                                                       ; // выводим Bar_Menu
               myGLCD.update()                                                                       ; // обновляем экран
        }
        
        //----- если батарея зарядилась ----------------------------------------------------------------------------------------------------------------
        else  if (Volt_A0>Volt_max){                                                                   // если все в  "OFF" сбрасываем все ключи в "0"
              All2LOW()                                                                              ; // все ключи в 0 
              if ( R_shunt==1){                                                                        // если флаг подключения шунта = 1 
                 digitalWrite(DCh_Pin ,HIGH)                                                         ; // включаем  ключ нагрузки(шунта)
              }else{digitalWrite(DCh_Pin ,LOW);}                                                       // в противном случае отключаем ключ нагрузки(шунта)          
              //  ---  выводим экран окончания зарядки  ------------------------------------------------------------------------------------------------
              do {                                                                                     // отображать пока не будет нажата кн.ok
                     Izmerenie()                                                                     ; // произвести измерения напряжений и расчет токов и емкости
                     draw_bat("Manual Ch ",Volt_A0,I_Ch,Capac_Ch,in_Resist,Time_s,1)                 ; // выводим информацию  после окончания заряда
                     Bar_Menu( "     ","Menu" ,"    ")                                               ; // 
                     myGLCD.update()                                                                 ; // обновить экран 
              }while (digitalRead(key_ok)==HIGH )                                                    ; //
              delay(anti_dr);buzz()                                                                  ; // антидребезг, звуковой сигнал 
        }

} while (digitalRead(key_ok)==HIGH); //-- конец  while() ---------------------------------------------------------------------------------------------    
    MeasRes=0                                                                                        ; // сбрасываем флаг измерения внут.сопротивления 
  return                                                                                             ; // выходим из функции
 } 
//************************************************************************************************************************************************************* 
//*************************************************************************************************************************************************************
//  Функция заряда аккумулятора 
//*************************************************************************************************************************************************************
 void Charge(){  
 bool UpCh=0                                                                                         ; // флаг дозарядки (0-заряд ,1- дозаряд,2-окончание заряда)
 bool Fin_Resist =0                                                                                  ; // флаг измерения внутреннего сопротивления 
  
//---- управление ключами ------------------------------------------------------------------------------------------------------------------
   All2LOW()                                                                                         ; // все ключи в 0 
//-----------------------------------------------------------------------------------------------------------------------------------------
  //R_dop=0                                                                                          ; // все ключи в 0 
  key=1                                                                                              ; // включить подсветку  
  Volt_A0 =0                                                                                         ; // обнуляем переменные
  Volt_A1 =0                                                                                         ; //
  R_shunt=0                                                                                          ; // отключить шунт 
  I_Ch  =0                                                                                           ; //
  Capac_Ch=0                                                                                         ; //    
  
  myGLCD.clrScr()                                                                                    ; // чистим экран
                                                        
  previousMillis=millis()                                                                            ; 
 
 do{//------------------- идет заряд   -------------------------------------------------------------------------------------------------------------------
  while (UpCh<4){
                        Izmerenie()                                                                  ; // произвести измерения напряжений и расчет токов и емкости
                      //------  автоматическое управление зарядным током в зависимости от напрядения на аккумуляторе -------------------------------------                                     
                          if (Volt_A0<Volt_min){
                             digitalWrite(Ch_Pin,LOW)                                                ; // если меньше 2.4  отключаем ключ зарядки аккумулятора ток 200 мА                          
                             digitalWrite(Ch_Pin_1,LOW)                                              ; // отключаем дополнительный ключ  зарядки аккумулятора 800 
                             UpCh=0 ;}                                                                 // режим зарядки
                          else if ((Volt_A0>Volt_min &&  Volt_A0<Volt_dop_res) || UpCh==1){            // 
                             digitalWrite(Ch_Pin,HIGH)                                               ; // если больше 2.4 но меньше 3.6  включаем ключ зарядки аккумулятора ток 200 мА                          
                             digitalWrite(Ch_Pin_1,LOW)                                              ; // отключаем дополнительный ключ  зарядки аккумулятора
                             UpCh=1 ;}                                                                 // режим зарядки
                          else if ((Volt_A0>Volt_dop_res && Volt_A0<Volt_midl) || UpCh==2){            // если больше 3.6 но меньше 4.0 ток 830 мА
                             digitalWrite(Ch_Pin,HIGH)                                               ; // включаем ключ зарядки аккумулятора
                             digitalWrite(Ch_Pin_1,HIGH)                                             ; // включаем доп. ключ зарядки аккумулятора
                             UpCh=2 ;}                                                                 // режим зарядки
                         else if ((Volt_A0>Volt_midl && Volt_A0<=Volt_max) || UpCh==3 ){                // если больше 4.0 но меньше 4.25 ток 250 мА
                             digitalWrite(Ch_Pin,HIGH)                                               ; // включаем ключ зарядки аккумулятор
                             digitalWrite(Ch_Pin_1,LOW)                                              ; // отключаем дополнительный ключ  зарядки аккумулятора
                             UpCh=3 ;}                                                                 // режим зарядки
                     // ---- дозарядка -------------------------------------------------------------------------------------------------------------------
                          else if( (Volt_A0>Volt_max && digitalRead(Ch_Pin==HIGH))||( UpCh==4 && (millis()-previousMillis)>Time_UpCh)){ // если напряжение на аккумуляторе под напряжением > 4.2  в режиме зарядки
                             previousMillis=millis()                                                 ;
                             All2LOW()                                                               ; // все ключи в 0 
                             UpCh=4                                                                  ;                
                             delay(10000)                                                            ; // даем "отдохнуть" батарее 1 сек
                          }// ------ конец  Volt_A0>Volt_max  -------------------------------------------------------------------------------------------- 
    
              // ---- измеряем внутреннее сопротивление аккумулятора--------------------------------------------------------------------------------------     
                     if ((Volt_A0 > Volt_in_res && Volt_A0 < (Volt_in_res+0.1)) && Fin_Resist == 0){   // если ранее не было измерено внутреннее сопротивление  или напряжение = 3.6v  
                          in_Resist=in_resist_accum (DCh_Pin , analogV0, Res_DCh,5)                  ; // измерение внутреннего сопротивления аккумулятора     
                          Fin_Resist =1                                                              ; // флаг измерения внутреннего соаротивления в  1 
                     }
              //------------------------------------------------------------------------------------------------------------------------------------------
             
              //--- выводим инфу о зарядке на экран ------------------------------------------------------------------------------------------------------    
                  
                   draw_bat("CHARG Auto ",Volt_A0,I_Ch,Capac_Ch,in_Resist,Time_s,0)                  ; // выводим информацию 
                   Shkala_gor(0,36,83,(Volt_max-Volt_min),(Volt_A0-Volt_min),0,0)                    ; // отрисовка ползунка заряда 
                   Bar_Menu( "     ", "Menu" ,"    " )                                               ; // выводим Bar_Menu
                   myGLCD.update()                                                                   ; // обновить экран  
                   
              //--- продолжим заряжать--------------------------------------------------------------------------------------------------------------------
                   digitalWrite(Ch_Pin,HIGH)                                                         ; // включаем ключ зарядки аккумулятора   240mA               
                
  }           //------ конец цикла заряда ----------------------------------------------------------------------------------------------------------------
                    All2LOW()                                                                        ; // все ключи в 0 
              
              // ---- выводим отчет об окончании зарядки   -----------------------------------------------------------------------------------------------
                  while (digitalRead(key_ok)==HIGH ){                                                  // отображать пока не будет нажата кн.ok
                          Izmerenie()                                                                ; // произвести измерения напряжений и расчет токов и емкости
                          draw_bat("CHARG OFF ",Volt_A0,I_Ch,Capac_Ch,in_Resist,Time_s,1)            ; // выводим информацию  после окончания заряда
                          Shkala_gor(0,36,83,(Volt_max-Volt_min),(Volt_A0-Volt_min),0,0)             ; // отрисовка ползунка заряда    
                          Bar_Menu( "     ", "Menu" ,"    " )                                        ; // выводим Bar_Menu
                          myGLCD.update()                                                            ; // обновить экран 
                  } 
       
                                                                                   
         //--- вызов отображения графиков напряжения ,тока зарядки ,тока разрядки, внутреннего сопротивления  --------------------------------------------
        
 }while(digitalRead(key_ok)==HIGH)                                                                  ; // если нажата кнопка "ОК"
  delay(anti_dr);buzz()                                                                             ; // антидребезг, звуковой сигнал 
  return                                                                                            ; // выходим в МЕНЮ 
}                                                  
//***************************************************************************************************************************************************************************************
//***************************************************************************************************************************************************************************
// Функция разряда батареи
//***************************************************************************************************************************************************************************
void   Discharg(){     
  // --  описываем локальные переменные ----------------------------------------------------------------------------------  
   bool stopDCh =0                                   ; // флаг конца разрядки     
   bool Fin_Resist =0                                ; // флаг измерения внутреннего сопротвления
   //-- обнуляем переменные  ----------------------------------------------------------------------------------------------
             previousMillis = 0                      ; // предыдущее время входа в цикл  
             deltaMillis= 0                          ; // прошедшее время за цикл      
             watch_millis =0                         ; // требуется  для функции расчета времени
             startMillis =0                          ; //
             Volt_A0=0                               ; // обнуляем напряжение батареи   
             I_Ch = 0                                ; //          ток заряда батареи   
             I_DCh= 0                                ; //          ток разряда батареи   
             Capac_Ch=0                              ; //          емкость батареи   
             Capac_DCh=0                             ; //          емкость батареи   
             in_Resist=0                             ; //          внутреннее сопротивление  
             mode=0                                  ; //          признак режима Info/Grf_V/Grf_I/Grf_C
             R_shunt=0                               ; //          отключить шунт 
             key=1                                   ; // включить подсветку
             
   //--- отключаем ключи заряда батареии  -------------------------------------------------------------------------------
     All2LOW()                                                                           ; // все ключи в 0 
  //----------------------------------------------------------------------------------------------------- ---------------
  do {                                                                                     // делать пока не нажата кнопка "OK"     
           Izmerenie()                                                                   ; // произвести измерения напряжений и расчет токов и емкости
           if (Volt_A0<1) {
               buzz()                                                                    ; // подать сигнал
               stopDCh ==1                                                               ; // установить флаг конца разрядки
               draw_Msg(""," NO BATTERY ", String (Volt_A0)+" v",1)                      ; // если напряжение меньше 1 вольта вывести сообщение             
           }else  if (Volt_A0>=1 && Volt_A0<=Volt_min ){                                   // если батарея разряжена
               buzz()                                                                    ; // подать сигнал
               stopDCh =1                                                                ; // установить флаг конца разрядки
               R_shunt=LOW                                                               ; // сбросить флаг  включения шунта 
               do{                                                                         //  
                  Izmerenie()                                                            ; // произвести измерение 
                  draw_Msg(""," BATTERY LOW ", String (Volt_A0)+" v",1)                  ; // вывести сообщение
               }while (digitalRead(key_ok)==HIGH)                                        ; // 
          }else if (Volt_A0>Volt_min && R_shunt==HIGH && stopDCh ==0){                     // если напряжение больше  минимального
               //---- управление ключами -------------------------------------------------------------------------------------           
               digitalWrite(DCh_Pin,HIGH)                                                ; // включаем ключ нагрузки 
               if ((Volt_A0>Volt_in_res&&Volt_A0<(Volt_in_res+0.1))&&Fin_Resist == 0){     // если ранее не было измерено внутреннее сопротивление  или напряжение = 3.6v  
                    in_Resist=in_resist_accum (DCh_Pin , analogV0, Res_DCh,5 )           ; // измерение внутреннего сопротивления аккумулятора     
                    Fin_Resist=1                                                         ; // флаг о проверке внутреннего сопротивления
               }
              //--- заносим показания в массивы ------------------------------------------------------------------------------------------------------
              if(millis()-Time_G>Time_Arr ){                                               // если прошло 5 минут  
                 Time_G=millis()                                                         ; // запоминаем новое значение начала отсчета
                 t++                                                                     ; // адрес для массивов
                 Arr_Volt[t]  = Volt_A0*1000                                             ; // заносим в массив наряжений  для графиков
                 Arr_I_DCh[t] = I_DCh*1000                                               ; // заносим в массив тока разряда
              } 
          } 
         //----- ОБРАБОТКА КНОПОК ---------------------------------------------------------------------------------------------------------------- 
         // if (digitalRead(key_ok)==LOW)   { delay(anti_dr);stopDCh =0;}                  // сбрасываем флаг конца разрядки
                                                                          
         //-------  ручное переключение режимов отбражения информации по нажатию  "UP"  ---------------------------------------------------------             
            if (digitalRead(key_up)==LOW ){
                                             delay(anti_dr)                             ; // андидребезг
                                             mode++                                     ; // инкремент 
                                             if (mode>3 ){mode=0;}                      ; // организуем выбор "по кругу" 
            }                                    
         //-------  ручное переключение разрядного шункта кнопкой "DOWN" --------------------------------------------------------------------------       
            if (digitalRead(key_down)==LOW){                                              // подключение щунта и автом. отключение зарядки аккумулятора 
                                             delay(anti_dr)                             ; // антидребезг
                                             R_shunt=!R_shunt                           ; // инверсия уровня на выводе D11                                             
           }            
         // -----------------------------------------------------------------------------------------------------------------------------------------
           if (R_shunt==HIGH && stopDCh==0){                                              // формируем надписи для down BAR и включаем / отключаем ключ нагрузки  
               B_DCh="OFF "                                                             ; //
               digitalWrite(DCh_Pin,HIGH)                                               ; // подключаем шунт разряда
               I_Ch = 0                                                                 ; // ток заряда батареи в 0 
           }else{
              B_DCh=" ON "                                                              ; // 
              digitalWrite(DCh_Pin,LOW)                                                  ; // отключаем шунт разряда
              I_DCh= 0                                                                   ; // ток разряда батареи в 0
           }
        // ---- формируем экран ---------------------------------------------------------------------------------------------------------------------          
        switch (mode){                                                                  ; // вывдим инфу в зависимости от выбранного режима
          case 0:{
                B_Ch ="Info "                                                           ; // 
                draw_bat("DISCHARG " ,Volt_A0,I_DCh,Capac_DCh,in_Resist,Time_s,0)       ; //  выводим информацию 
                //--- отрисовка ползунка заряда ---------------------------------------------------------------------------------------------------
                Shkala_gor(0,36,83,(Volt_max-Volt_min),(Volt_A0-Volt_min),0,0)          ; //  шкала уровня напряжения (разряда)  
                break;
          }
          case 1:{                                                                      ; // выводим график тока
                B_Ch ="  I  "                                                           ;
          break;
          }
          case 2:{                                                                      ; // выводим график напряжения
               B_Ch ="  V  " ;
          break;
          }
          case 3:{                                                                      ; // выводим график напряжения и тока
               B_Ch =" I+V " ;
          break;         
          }
        } //  ---- конец switch(mode)---------------------------------------------------------------------------------------------------------- 

      //--- формируем down BAR  на экране -----------------------------------------------------------------------------------------------------
        Bar_Menu( B_Ch,"Menu" ,B_DCh)                                                  ; //
        myGLCD.update()                                                                ; // обновить экран
      
     }while (digitalRead(key_ok)==HIGH); // --------- конец  do while (digitalRead(key_ok)==HIGH) --------------------------------------------
      stopDCh =0                                                                       ; // сбрасываем флаг конца разрядки
  }
//*****   конец  Discharg()  **************************************************************************************************************************************************

//***************************************************************************************************************************************************************************
// функция  редактирования установок ( подсветка, UART, )  (в работе) 
//***************************************************************************************************************************************************************************
 void SetUp(){
    
 }
//***************************************************************************************************************************************************************************

//********************************************************************************************************************************************************************************
// функция анализирует состояние цифровых выходов для управления ключами и возвращает  стринг для индикации  в строке заголовка
//********************************************************************************************************************************************************************************
String Ind_Klych(){
String S="    " ;
  if (digitalRead(Ch_Pin)  ==HIGH && digitalRead(Ch_Pin_V)==HIGH){S="ChV  ";}                                  // вкл. заряда постоянным напряжением
  else if (digitalRead(Ch_Pin_1)==HIGH){S="Ch+ ";}                                                             // вкл. доп. ключ заряда     (ток 830 mA)
  else if (digitalRead(Ch_Pin)  ==HIGH && digitalRead(Ch_Pin_V)==LOW) {S="Ch  ";}                              // вкл. основной ключ заряда (ток 240 mA)
  else if (digitalRead(DCh_Pin) ==HIGH){S="DCh  ";}                                                            // вкл щунт разряда          (ток 780 mA)     
  else if (digitalRead(DCh_Pin) ==HIGH && digitalRead(Ch_Pin)==HIGH){S="Err  ";}                               // одновременно включен заряд и разряда (сквозной ток)
  else if (digitalRead(Ch_Pin)  ==LOW  && digitalRead(Ch_Pin_1)==LOW && digitalRead(DCh_Pin) ==LOW && digitalRead(Ch_Pin_V)==LOW){S="OFF  ";}   // все ключи выключены
  return S                                                                                                   ; // возвращаем стринг
}
//********************************************************************************************************************************************************************************
//***************************************************************************************************************************************************************************
// функция выводит  описание функций кнопок в данный момент снизу экрана. длина обозначений не должна превышать 4 знаков 
// пример   Bar_Menu( " Ch+","Menu" ,"DCh ")                                                   ; //
//*************************************************************************************************************************************************************************** 
 void Bar_Menu(String Left,String Centr ,String Right){
       myGLCD.invertText(true)                                                                 ; // инвертровать текст 
       myGLCD.print( Left ,  0,40)                                                             ; //        
       myGLCD.print("|"+Centr+"|", 26,40)                                                      ; //                      
       myGLCD.print( Right, 61,40)                                                             ; //  
       myGLCD.invertText(false)                                                                ; // востановить текст
     //  myGLCD.update()                                ;  // обновление экрана 
}
//***************************************************************************************************************************************************************************
 //* функция  Menu_M()  *******************************************************************************************************************************************************
 // меню для  Nokia 5110
 //****************************************************************************************************************************************************************************
 // #include <LCD5110_Graph.h>                                                                       // подключаем графическую библиотеку  в заголовке программы
 // String Menu_Arr[]={" Пункт 1 "," Пункт 2 ", " Пункт 3 "," Пункт 4 "}                           ; // массив пунктов меню 
 // вызов фукции  int M = byte Menu_M (String Menu_Arr,byte kolvo,int punkt_disp,byte akt_punkt)   ; // вызов функции вывода меню. 
 // String Menu_Arr                                                                                ; // массив с пунктами меню 
 // int kolvo = 7                                                                                  ; // кол-во пунктов меню
 // int punkt_disp=4                                                                               ; // количество пунктов меню на экране
 // int akt_punkt1=2                                                                               ; // активный пункт меню 
 //***************************************************************************************************************************************************************************-
   int  Menu_M (String Menu_Arr[],byte kolvo,int punkt_disp,byte akt_punkt){
           //----- формируем  меню программы  ( надо-бы  выделить в функцию с возвратом выбранного пункта меню)  ---------------------------------------------         
             int punkt_menu=0                                                 ; // внутренние переменные  для отрисовки пунктов меню           
            // int knop=0                                                     ; // выбранный пункт меню             (для наладки)
            // int kolvo = 7                                                  ; // количество пунктов меню           (для наладки) 
            // int punkt_disp=4                                               ; // количество пунктов меню на экране (для наладки)
             int H=11                                                         ; // начальная строка вывода      (для подгонки вида меню)
             int h=9                                                          ; // смещение строк по вертикали  (для подгонки вида меню)      
             int x=0                                                          ; // 
          
    do{            
             myGLCD.clrScr()                                                  ; // чистим экран
             //--отрисовка ЗАГОЛОВКА МЕНЮ --------------------------------------------------------------------------------------------------------------------
              myGLCD.setFont(SmallFont)                                       ; // установим маленький шрифт
              myGLCD.invertText(true)                                         ; // инвертровать текст 
              myGLCD.print("   MAIN MENU ", CENTER, 0)                        ; // вывести заголовок меню 
              //myGLCD.print("   MAIN MENU  "+(String(akt_punkt+1)+"/"+String(kolvo)), CENTER, 0)  ; // вывести заголовок меню 
              myGLCD.invertText(false)                                        ; // востановить текст
            //------------------------------------------------------------------------------------------------------------------------------------------------
            // перемещаемся по меню  
             if (digitalRead(key_up)==LOW)   { akt_punkt--; delay(anti_dr); }   // если нажата кнопка вверх
             if (digitalRead(key_down)==LOW) { akt_punkt++; delay(anti_dr); }   //                    вниз 
            //--  расчет положения пункта меню  ------------------------------------------------------------------------------------------------------------- 
             if (akt_punkt > kolvo-1) { akt_punkt = 0 ; x=0 ;}                  //                               ( не трогать)        
             if (akt_punkt >= punkt_disp-1) { x = akt_punkt - punkt_disp+1;}    // если  активный пункт за пределами экрана ( не трогать)
             if (akt_punkt < 0)       { akt_punkt = kolvo-1 ;}                  // контролируем выход за пределы ( не трогать)
            //---- и его отрисовка ---------------------------------------------------------------------------------------------------------------------------
            for (punkt_menu=0+x; punkt_menu<=punkt_disp+x; punkt_menu++){       // 
                if    (punkt_menu==akt_punkt) myGLCD.invertText(true)         ; //
                else  myGLCD.invertText(false)                                ; // инвертировать если выбран пункт меню    
                      myGLCD.print(Menu_Arr[punkt_menu],3, H+h*(punkt_menu-x)); // вывести пункт меню                                                                                                                                                   
            } 
            myGLCD.drawLine(0, 47, 83, 47)                                    ; // линия снизу меню  
         
           //----  отрисовка метки положения в меню  -----------------------------------------------------------------------------------------------------
            if (kolvo>punkt_disp){                                              //  если кол-во пунктов меню превышает возможности для вывода               
               myGLCD.drawLine(78,10,83,10)                                   ; //  то рисуем  линию огр. сверху      -
               myGLCD.drawLine(80,10,80,45)                                   ; //  то рисуем  линию положения в меню | 
               myGLCD.drawLine(78,45,83,45)                                   ; //  то рисуем  линию огр. снизу       -
               byte point = 13 + ((akt_punkt)*34)/kolvo                       ; //  расчитываем положение круглой метки
               myGLCD.drawCircle(80,point,2)                                  ; //  и отображаем ее на линии         *  
               myGLCD.drawCircle(80,point,1)                                  ; //  и отображаем ее на линии         *
           }  
           myGLCD.update()                                                    ; // обновить экран 
       } while (digitalRead(key_ok)==HIGH)                                    ; //--- конец DO WHILE  ----------------------------------------------------    
        return  (akt_punkt+1)                                                 ; // возвращаем номер активного пункта меню  
}//---  конец MENU_M ------------------------------------------------------------------------------------------------------------------------------------- 
//***************************************************************************************************************************************************************************************  
//#################################  конец модуля функции   ФУКЦИИ   ####################################################################################################################
void setup(){

Serial.begin(115200)            ; // устанавливаем скорость передачи UART           
// -- установка пинов на вход и выход  --------------------------------------------
pinMode(buzzPIN, OUTPUT)        ; //
pinMode(analogV0, INPUT)        ; // определяем тип порта (вход) A0
pinMode(analogV1, INPUT)        ; // определяем тип порта (вход) A1
pinMode(Litgh, OUTPUT)          ; // определяем тип порта (вход) A3(D17) Подсветка
digitalWrite(Litgh, HIGH)       ; // включим  подсветку
//---------------------------------------------------------------------------------
pinMode(key_up,   INPUT)        ; // кнопка вверх
pinMode(key_down, INPUT)        ; // кнопка вниз
pinMode(key_ok  , INPUT)        ; // кнопка ok

digitalWrite(key_up,  HIGH)     ; //  подтянули к 1 
digitalWrite(key_down,HIGH)     ; //   
digitalWrite(key_ok,  HIGH)     ; //
//---------------------------------------------------------------------------------
pinMode(DCh_Pin, OUTPUT)        ; // разряд управление пин на выход
pinMode(Ch_Pin,  OUTPUT)        ; // заряд током Ch      
pinMode(Ch_Pin_1,OUTPUT)        ; // заряд током Ch+
pinMode(Ch_Pin_V,OUTPUT)        ; // заряд напряжением ChV
pinMode(buzzPIN, OUTPUT)        ; // бузер   

digitalWrite(DCh_Pin ,LOW)      ; //  подтянули к 0  все отключить !!!
digitalWrite(Ch_Pin  ,LOW)      ; // 
digitalWrite(Ch_Pin_1,LOW)      ; //   
digitalWrite(Ch_Pin_V,LOW)      ; // 
digitalWrite(buzzPIN ,LOW)      ; //
//----------------------------------------------------------------------------------
startMillis=millis()            ; // время входа в программу   ????
Time_Litgh =millis()            ; // для расчета времени подсветки  

myGLCD.InitLCD()                ; // инициализацие экрана
myGLCD.setContrast(70)          ; // контрастность
myGLCD.invertText(false)        ; // отключаем инверсию
myGLCD.setFont(SmallFont)       ; // маленький шрифт
myGLCD.clrScr()                 ; // чистим экран
myGLCD.update()                 ; // обновить экран  

buzz()                          ; // гудим 
Vcc=readVcc()                   ; // измеряем напряжения питания
}//---- конец  setup() -------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------------------------------------------------------
void loop(){  
 
    // --   измерение  и расчеты   ----------------------------------------------------------------------------------------------------------------------------  
     previousMillis=previousMillis+deltaMillis                            ; // подготовка данных для работы со временем
     deltaMillis=millis()-previousMillis;                                 ; //
     All2LOW()                                                            ; // все ключи в 0                                                        
     Izmerenie()                                                          ; // произвести измерения напряжений и расчет токов и емкости

 /*
   // if  (Volt_A0<1) { Msg_disp("No","battery",1) ;}                                         // если напряжение меньше 1 вольта
   //--------------------------------------------------------------------------------------------------------------------------------------
        if(millis()-Time_G>Time_Arr ){                                       // если прошло 5 минут  
           Time_G=millis()                                                 ; // запоминаем новое значение начала отсчета
           t++                                                             ; // адрес для массивов
           Arr_Volt[t]  = Volt_A0*1000                                     ; // заносим в массив наряжений  для графиков
           Arr_I_Ch[t]  = I_Ch *1000                                       ; // заносим в массив тока заряда
           Arr_I_DCh[t] = I_DCh*1000                                       ; // заносим в массив тока разряда
           Arr_Resist[t]= in_Resist_G *1000                                ; // заносим в массив вн.сопротивления
        }
/*
    //-- Проверка нажатия клавиши ------------------------------------------------------------------------------------------------------------
     if (digitalRead(key_up)==LOW||digitalRead(key_ok)==LOW||digitalRead(key_down)==LOW){
         delay(anti_dr)                                                    ; // антидребезг      
         digitalWrite(Litgh, HIGH)                                         ; // включим  подсветку
         key=1                                                             ; // была нажата одна из клавиш
     }
    //----- выкл подсветки -----------------------------------------------------------------------------------------------------------------
      if(millis()-Time_Litgh>60000 ){                                        // если прошла минута  
         key==0                                                            ; // сбрасываем флаг нажатия кнопок
         Time_Litgh =millis()                                              ; // перезаписывае значение  
         digitalWrite(Litgh, LOW)                                          ; // выключим  подсветку
     }      
    //--------------------------------------------------------------------------------------------------------------------------------------
    if ((millis()-startMillis  >=1000)){                                     // отсчет одной секунды  
         startMillis =millis()                                             ; //
         Time_1 = watch_min((previousMillis/(1000*time_koef)),2)           ; // время разряда батареи  в 1-минутах 2-секундах    ( 1.047- коэф. опережения времени внутреним счетчиком)  
    }
    Time_s = sec2hour ( Time_1 )                                           ; // преобразуем секунды в стринг для вывода времени
  
  // -- конец  измерение ------------------------------------------------------------------------------------------------------------------------------------
*/  
   //-------- обнуляем переменные ----------------------------------------------------------------------------------------------------------------------                   
             previousMillis = 0                          ; // предыдущее время входа в цикл  
             deltaMillis= 0                              ; // прошедшее время за цикл      
             watch_millis =0                             ; // требуется  для функции расчета времени
             startMillis =0                              ; //
             Volt_A0=0                                   ; // обнуляем напряжение батареи   
             Volt_A1=0                                   ; // обнуляем                      
             I_Ch = 0                                    ; //          ток заряда батареи   
             I_DCh= 0                                    ; //          ток разряда батареи   
             Capac_Ch=0                                  ; //          емкость батареи   
             Capac_DCh=0                                 ; //          емкость батареи   
             in_Resist=0                                 ; //          внутреннее сопротивление  
            
             knop= Menu_M (Menu_Arr,8,4, knop)           ; // вызываем функцию вывода главного меню
  // --------------------------------------------------------------------------------------------------------------------------------------------------------

switch (knop){// обработка пунктов МЕНЮ      

//=============================================================================================================================================================
    case 1:{ // " Manual "     работает на 90% !  для наладки и ручного управления ключами
             All2LOW()                                   ; // все ключи в 0 
             Manual()                                    ; // вызываем функцию
             knop-=1                                     ; // установка флага  возврата в меню
    break                                                ; // выходим из case  в МЕНЮ
    }       
//==============================================================================================================================================================
    case 2:{ // "CHARG" отработка сценария зарядки после подключения
             All2LOW()                                   ; // все ключи в 0 
             Charge()                                    ; // вызываем функцию       
             knop-=1                                     ; // установка флага  возврата в меню
    break                                                ; // выходим из case  в МЕНЮ
    }
//==============================================================================================================================================================
   case 3: { // "CHARG_SUP"отработка сценария зарядки  с контроллереми 
             All2LOW()                                   ; // все ключи в 0 
             SisInfo()                                   ; // вызываем функцию   
             knop-=1                                     ; // установка флага  возврата в меню
   break                                                 ; // выходим из case  в МЕНЮ
    }
   //===========================================================================================================================================================
    case 4:{ // "Res_in"     проверка внутреннего сопротивления аккумулятора
           //---- управление ключами -----------------------------------------                     
           All2LOW()                                                        ; // все ключи в 0 
           Izmerenie()                                                      ; // производим измереия 
           if (Volt_A0<1) {                                                 ; // если напряжение < 1v
               buzz()                                                       ; // подать сигнал
               draw_Msg("","  NO BATTERY  ", String (Volt_A0)+" v",1 )      ; // если напряжение меньше 1v  вывести сообщение             
           }else  if (Volt_A0>=1 && Volt_A0<=Volt_min ){                      // если батарея разряжена
               buzz()                                                       ; // подать сигнал
               draw_Msg(""," BATTERY LOW ", String (Volt_A0)+" v",1 )       ; // вывести сообщение
           }else if (Volt_A0>=Volt_min && Volt_A0<=Volt_max ){                // если напряжение в диаппазоне для измерений
            //---- измерение  и вывод сообщения  -----------------------------        
            in_Resist=in_resist_accum (DCh_Pin ,analogV0,Res_DCh,9)         ; // измерение внутреннего сопротивления аккумулятора     
            // ---- обработка нажатия клавиш ---------------------------------
            while (digitalRead(key_ok)==HIGH){ delay(anti_dr) ;All2LOW() ;}   // зациклить пока не нажата "ok"
           }
            buzz()                                                          ; // подать сигнал
            knop-=1                                                         ; // флаг отрисовки меню
            break                                                           ; // выходим из case  в МЕНЮ
   } 
   //===========================================================================================================================================================
    case 5:{ // "Discherg "   проверка сценария для разрядки
             Discharg()                                                     ; //   функция разряда батареи
             knop-=1                                                        ; //   флаг отрисовки меню
             break                                                          ; //   выходим из case  в МЕНЮ
    }  
 //===========================================================================================================================================================
   case 6:{ // "SetUp"       Установока для пресетов 
            SetUp()                                                         ; //  функция Установок для пресетов
            knop-=1                                                         ; //  флаг отрисовки меню
            break                                                           ; //  выходим из case  в МЕНЮ
   }

   case 7:{ // "PrintGraf"    вывод графиков в COM 
            // Prn2Com()                                                    ; //  функция вывода графиков в COM 
            knop-=1                                                         ; //  флаг отрисовки меню
            break                                                           ; //  выходим из case  в МЕНЮ
   }

  case 8:{ // "Presets  "    предустановки для заряда / разряда батарей
            // Presets()                                                    ; //  функция предустановки для заряда / разряда батарей
            knop-=1                                                         ; //  флаг отрисовки меню
            break                                                           ; //  выходим из case  в МЕНЮ
  }
}  //--конец switch (knop) --------------------------------------------------------------------------------------------------

}//-------- конец LOOP ------------------------------------------------------------------------------------------------------




 

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017
dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

Stashevskiy68, сверните свой код в #179, слишком большая портянка.

Под сообщениием нажать "Изменить" ,  встать мышкой на код,  нажать кнопку "code", нажать кнопку "дополнительно",
поставить галку "сворачивать код по-умолчанию".

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

спасибо. подправил.

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

фотки в железе

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

Joiner
Offline
Зарегистрирован: 04.09.2014

Stashevskiy68 пишет:

 

 

 

 

Не люблю кулеры....

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

Я использую lm317 как стабилизатор тока и питаю его от 12 в поэтому и охлаждение такое , запитай меньшим напряжением и будет тебе счастье. да собирал схему из того что было под рукой на работе. А делал под релейный модуль что-бы меньше пайки было для новичков да и модули есть в наличии . В программе главное логистику реализовать а управление выходами это уже вторично.

Joiner
Offline
Зарегистрирован: 04.09.2014

Совсем не хотел обидеть. Самодельное устройство тем и хорошо, что есть возможность воплотить все свои желания. И самое главное, как мне кажется, это довести до законченного устройства. Свою зарядку довести до ума пока не смог. В макетном исполнении иногда для профилактики разряжаю на ней NI-MH аккумуляторы и измеряю их емкость.  Заряжаю пока за заводской дешманской зарядке. А куллеры не люблю за их негромкий назойливый шум. Всегда стараюсь обойтись без них, где это возможно.

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

Для того и выкладываю свое произведение что-бы услышать критику и предложения по доработке. Новичкам в программировании рекомендую обратить внимание на реализацию меню я его оформил в отдельную функцию

Joiner
Offline
Зарегистрирован: 04.09.2014

За меню спасибо. Обязательно поизучаю. Удобное меню - достоинство любого проекта. Пару раз писал меню, испытывал серьезные затруднения.

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

там в заголовке функции все входные параметры описанны. обьявляем одномерный стринговый мвссив с пунктами меню , передаем его в функцию и возвращаем в переменную номер пункта . потом создаем switch  case   и запускаем функции в зависимости от выбранного пункта меню.  когда достигаем последнего пункта меню переходим на первый. а когда  достигаем первого то на первом пункте и остаемся. о положении в меню ориентируемся по индикатору с правой стороны.  в общем все просто. бери и пользуйся.

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

а у меня проблема ARDUINO IDE не хочет работать в WIN 10 , раньше  переустановка java помогало , а сейчас   почему-то не работает.  пока сделал виртуальную машину  с XP .  у кого какие предложения по решению проблемы?  

Joiner
Offline
Зарегистрирован: 04.09.2014

Stashevskiy68 пишет:

а у меня проблема ARDUINO IDE не хочет работать в WIN 10 , раньше  переустановка java помогало , а сейчас   почему-то не работает.  пока сделал виртуальную машину  с XP .  у кого какие предложения по решению проблемы?  

У меня ни каких проблем с Win10 и IDE не возникало почему-то.

Stashevskiy68
Offline
Зарегистрирован: 09.01.2017

у меня  с год то-же небыло.

 

Mactun
Offline
Зарегистрирован: 12.12.2018

Я так понимаю, уже с год как все затихло?) как думаете, каналов 14 реально сделать?))

Joiner
Offline
Зарегистрирован: 04.09.2014

Mactun пишет:
Я так понимаю, уже с год как все затихло?) как думаете, каналов 14 реально сделать?))

Все в наших руках :)

А зачем столько много?

Mactun
Offline
Зарегистрирован: 12.12.2018

Для работы надо((( года 2 мечтаю об этом, вот щас конкретно начал в это углубляться.

Joiner
Offline
Зарегистрирован: 04.09.2014

Самое нужное в зарядке NI-MH аккумуляторов, и самое сложное в осуществлении, это своевременное отключение аккумуляторов при окончании зарядки. Испытать алгоритм автоматического отключения мне так и не довелось. Аккумуляторов у меня не много, и после зарядки они довольно долго служат в моих устройствах. Поэтому интерес к этой теме пропал. Заряжать аккумуляторы приходится довольно редко. Заряжаю их самой примитивной заводской зарядкой на 4 аккумулятора. Просто по емкости и току вычисляю время, и по напоминальнику выключаю. Есть еще универсальная зарядка Литокала. Она тоже может заряжать NI-MH аккумуляторы, и даже автоматически отключать их после зарядки. Но она больше заточена под литиевые аккумуляторы... По NI-MH аккумуляторам результат не порадовал. При зарядке вручную на примитивной зарядке они при тестовой разрядке показывают лучший результат, чем при зарядке на автоматической зарядке.

Но ведь для нас главное автоотключение. Сунул, и забыл. А этого мы не достигли (

Mactun
Offline
Зарегистрирован: 12.12.2018

Ну у меня аккумуляторов много, по 7.2 вольта, для меня больше головной болью было своевременное отключение после заряда. Ну и за раз штук 14))) Придётся ехать на выходных в китай набрать 4х канальных аймаксов)