Открытый проект универсального зарядника

R2D2

Итак программист в разных местах программы обозначает какой шаблон он хочет видеть, подпрограмма рисования шаблонов нарисует шаблон в видеопамяти, прерывание выведет видеопамять на ЖКИ. Для того чтобы экономить время процессора и ЖКИ предусмотрены механизмы не полной прорисовки шаблона, а только изменяемой части и не всех строчек разом, а только указанных. Прерывание и подпрограмма рисования шаблонов один раз написаны и отлажены, далее программист творчески манипулирует простым вызовом шаблонов в нужных местах программы. На этом мы закончим описывать механизм вывода информации на ЖКИ. Более детально смотрите сам текст программы.

Урок №19 (структуры)

В нашем ЖКИ есть 2 канала зарядки. Так уж сложилось, что у процессора оказалось достаточно свободных ножек, чтобы подключить 2 канала, не привлекая дополнительной логики. И при выборе “2 канала” или “1 канал и балансир” выбор пал на первый вариант. Два абсолютно одинаковых канала управляются одной программой. Нужно написать подпрограмму работы с одним каналом и передавать ей номер канала. Одним выстрелом двух зайцев. Пишем одну подпрограмму, которую применим 2 раза. Разве это не халява.

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

// Вот таким образом мы упрощенно описываем структуру канала
// Слово struct - это служебное слово Си
// Слово CHANNEL - это произвольное слово, теперь его можно
// использовать как тип для описания представителей структуры
struct CHANNEL
  {
  float I;
  float V;
  float T;
  };

// А в этом месте мы описываем наши два канала и каждый имеет одинаковую
// структуру как указано выше
CHANNEL Ch1, Ch2;

// А вот так мы будем работать со свойствами канала
Ch1.I=5;
Ch2.V=Ch1.V;
Ch1.T=GetTemperatur();

А вот описание настоящего канала:

struct CHANNEL              // Структура, описывающая состояние канала в любой момент времени
{
BYTE A;                     // Номер подключенного аккумулятора из списка
long STime;                 // Время старта канала в десятых долях секунды (для вычисления полного времени работы канала)
long WTime;                 // Время работы канала в десятых долях секунды
long CTime;                 // Максимальное время выполнения одного цикла зарядки или разрядки в 1/10 сек.
long SecsT;                 // Для определения скорости роста температуры в каналах
BYTE Cycl;                  // Текущий цикл (загружается при пуске канала)
        // 0000 - зарядка
        // 0001 - разрядить и зарядить 1 раз
        // 0010 - разрядить и зарядить 2 раза
        // 0011 - разрядить и зарядить 3 раза
float k0, k1, k2;           // Коэффициенты для расчета тока зарядки
float kr0, kr1, kr2;        // Коэффициенты для расчета тока разрядки
float kv0, kv1, kv2;        // Коэффициенты подстройки напряжения
float Rch;                  // Сопротивление шунта зарядки
BYTE f1;                    // Флаги алгоритма зарядки 1 (10й байт типа аккума)
BYTE f2;                    // Флаги алгоритма зарядки 2 (11й байт типа аккума)
BYTE n;                     // Количество последовательных элементов в аккуме (Кол-во послед. банок)
WORD
ftPause:1,                  // Вторая попытка по перегреву
h:1,                        // Зарядка для хранения
Zaryd:1,                    // В настоящий момент вообщето вцелом идет заряд иначе разряд
LZaryd:1,                   // Локально сейчас идет заряд (true-заряд, false-разряд)
                            // Для отслеживания режимов декристаллизации
C:1,                        // 0-Стоп 1-Старт
dT:1,                       // 0-Скорость температуры < 2гр./мин. 1-больше (перегрев)
DP:1,                       // Динамический 0-Нет дельтапика 1-Есть дельта пик
DPs:1,                      // Статический 0-Нет дельтапика 1-Есть дельта пик
First:1,                    // 1-только что запустили 0-давно работаем
Stop:1;                     // 1-получен приказ на выключение 0-не получен
BYTE Speed;                 // 0-медленно 1-нормально 2-быстро
WORD Pause;                 // Необходима для стабилизации на тл494 заказанного тока в 1/10 сек.
BYTE Fasa;                  // Фаза заряда (0-нулевая, 1-основная, 2-капельный или струйный)
WORD WW;                    // Скорость роста и убывания тока изначально
WORD W;                     // Скорость роста и убывания тока может убывать при непревышении напряжения
WORD i;                     // Установленный ток (0-0xfffe) - величина ШИМ
WORD iDec;                  // Установленный ток (0-0xfffe) - величина ШИМ для локального процесса разрядки
BYTE sDec;                  // Стадия 0-Зарядка 1-Пауза 2-Разрядка 3-Пауза
BYTE pDec;                  // Переменная отсчета цикла декристаллизации от ch.PDes до нуля в 1/10 секундах
BYTE PDec;                  // Константа цикла декристаллизации из свойств типа аккума
BYTE TDec;                  // Константа цикла декристаллизации из свойств типа аккума
BYTE Imin, Imax;            // Плавное повышение тока в процессе зарядки
float I, V, T, Told;        // Реальные измеренные ток, напряжение и температура
float Tmax, TT;             // Абсолютная температура и скорость роста температуры перегрева
float Vst;                  // Напряжение статическое
float Vmax;                 // Используется при заряде для определения DP динамического
float Vmaxs;                // Используется при заряде для определения DP статического
float Vmin0;                // Минимальное напряжение для нулевой фазы
float Vmin1;                // Минимальное напряжение для первой фазы
float Vh;                   // Напряжение хранения
float dV;                   // Константа - величина дельтапика (во второй фазе используется для капильного заряда)
float II;                   // Принято решение установить такой ток
float IIDec;                // Принято решение установить такой ток для локального процесса разрядки
float VV;                   // Принято решение не превышать такое напряжение при заряде
float Z;                    // Емкость Ач
float InZ;                  // Полученный интегральный заряд Ач подсчитывается еже 1/10 секундно (при выводе надо поделить на 36000)
BYTE Msg;                   // Код остановки канала
          // 0 - Код не предусмотрен (канал не запускался)
          // 1 - Ток упал до нуля при заряде
          // 2 - Превышение лимита времени
          // 3 - Превышение температуры
          // 4 - Превышение скорости роста температуры
          // 5 - Превышение емкости заряда в 1.2 раза
          // 6 - Напряжение достигло минимума при разряде
          // 7 - Провисло питание до 11 вольт
          // 8 - Обнаружился дельтапик
          // 9 - На заряжаемом аккуме напряжение ниже минимального "это неправильно"
          // 10 - Зашкал тока
          // 11 - Зашкал напряжения
          // 12 - Остановлен пользователем
          // 13 - Напряжение ниже нулевой фазы
          // 14 - Напряжение достигло Vh хранения
          // 15 - Ошибки в настройках типов
          // 16 - Напряжение достигло нужного уровня при заряде
          // 17 - Перегрев схемы
}Ch1, Ch2;

А вот так в главном цикле вызывается обработка каждого канала.
Ищите Ch1 и Ch2.

// Главная программа запускается по ресету
int main(void)
{
fc=255;
#include "init.cpp"       // Инициализация всего
#include "zagruzka.cpp"   // Загрузка начальных переменных
while(true)
  {
  wdt_reset();            // Сброс собаки
  #include "sh.cpp"       // Прорисовка шаблонов
  #include "test.cpp"     // Рассчитываем все переменные по каналам
  if(iK1!=iK0)            // Если есть необработанные кнопки рисуем меню
    {
    #include "menu.cpp"   // Обработка кнопок
    }
  TestMainParam();        // Если какой нибудь канал работает или тестирование
  if(Ch1.C)Go(Ch1);       // Если запущен канал 1
  if(Ch2.C)Go(Ch2);       // Если запущен канал 2
  #include "uart_in.cpp"  // Если надо чтонибудь получить с COM-порта
  #include "uart_out.cpp" // Если надо чтонибудь послать на COM-порт
  }
}
R2D2

Как вы увидели в структуре канала есть переменные в которых отражен желаемый ток и желаемое напряжение. Канал не сразу реагирует и выставляет нужное напряжение и ток на аккумуляторе, а с определенной скоростью реакции. Кроме того в настройках канала отражены текущие фазы зарядки. А также отражены результаты, достигнутые каналом. Как это все учесть?

Основная процедура управлением зарядкой/разрядкой Go() действует следующим образом:

  1. Если это первый запуск Go, то загружаем в настройки канала все что мы знаем об этом аккуме и его химии, обнуляем все что надо и ставим по умолчанию все что надо. Играем музыку старта.
  2. Проверяем все экстренные проверки (зашкалы, проверка на вшивость и т.д.)
  3. Если проверки показали что надо остановиться, то останавливаемся и фиксируем причину. Играем музыку конца.
  4. Если необходима задержка выскакиваем из программы столько раз, пока не истечет задержка, а вызывается Go() более 100 раз в секунду.
  5. Обработка фазы декресталлизации, установка мелкопоместных задач по току, задержки опять ток разрядки или зарядки.
  6. Опять длинная пауза по времени, которая может завершить Go() в этот раз.
  7. Расчет всех токов и напряжений из данных АЦП. Проверка всех условий зарядки, разрядки, достижения требуемых напряжений и токов. Главная цель проверить не конец ли это.
  8. Если закончилась очередная фаза тренировки, то переинициализация для запуска нового цикла.
  9. А вот теперь в зависимости от того что есть в наличии и того чего хочется и от допустимой скорости реагирования, выставляем новый ток через процедуру выставления тока.
1 month later
R2D2

Вышла новая прошивка и макропрога к ней. avrcpp.narod.ru (Все заинтересованные дайте ваших глюков пжлста).
Статью про Си почистил и причесал кому надо там же.

E95

Очень порадовало что теперь можно заряжать автомобильные аккумуляторы ёмкостью до 100а/ч. Из глюков вижу что пока остались проблемы с установкой тока заряда и разряда.Где-то теряется один процент,например установлен ток заряда 10% от ёмкости,а реально заряжает током 9%
Программу на компьютере пока запустить не удалось,при нажатии кнопки старт выскакивает такая ошибка:

Если не сложно,хотелось бы видеть в будущих прошивках на дисплее ёмкость не только в процентах но и в ампер часах.

alecs2000
E95:

не только в процентах но и в ампер часах.

+1

и акб выставлять на “ходу” (не из заранее запрограммированных)

E95

и акб выставлять на “ходу” (не из заранее запрограммированных)

В новой прошивке это реализовано

R2D2

Исправил! Высылайте еще глюков.
Времени потестить не было.
Кстати теперь можно накапливать базу поведения различных акков (*.gra) и тем самым сравнивать их графики и оценивать свежесть акков и качество производителя.

7 days later
anton_z

Прошился новой прошивкой. Очень порадовала возможность задания в ручную кол-ва банок и емкости. Мелкий глюк, оставшийся еще со времен прошивки 1.5 - в режиме тренировки, когда происходит переход из режима разрядка в режим зарядка на экране вначале “Канал 1 Разрядка”, а потом “Канал 1 Зарядка а” т.е. последняя “а” от “Разрядка” не затирается.
Сейчас тренировкой пробую восстановить старые аккумуляторы от шуруповерта на 18 В, которые родной зарядкой уже не заряжались. После первого цикла показал 10%, после второго 20%, после третьего - 40%, сейчас уже около 80% от номинальной емкости показывает. В общем, посмотрим, что получится.
PS: Предложение. Раньше была емкость в процентах, не хватало Ач, а сейчас наоборот - в Ач, но не хватает процентов, поэтому хотелось бы видеть после зарядки емкость и в процентах и в Ач.

anton_z

Опять небольшой отчетец после тестов.

  1. Во время тренировки проявился глюк, заключающийся в том, что в момент переключения из режима “Разрядка” в режим “Зарядка” у бп, питающего зарядник срабатывала защита. Решил смоделировать эту ситуацию, подключив вместо акка другой бп и постепенно уменьшая его напряжение получил этот же глюк в момент переключения режимов. Прошился 1.5 прошивкой - тот же глюк, потом увидел, что уже выложена прошивка от 08.06.10, прошился ей, глюк исчез (хотя на жки выводится дата от 27.05.10). Отсюда предложение - создать whatsnew.txt и дописывать его с компиляцией новой прошивкой.
  2. Как я понимаю, режим десульфации так и не доделан. При запуске выдает “Ошибка настроек”
  3. Хорошо бы в макропрограмме сделать быстрое сохранение/восстановление калибровочных коэффициентов. А то после перепрошивки приходится в ручную перебивать все значения.

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

R2D2

Спасибо!

Режим десульфатации не продвигается из-за отсутствия информации. Если у кого есть ссылки на статьи про десульфатацию… ?

ВНИМАНИЕ! В схеме 1.7 на входе силовых надо ставить 2200мкф, а также на 78м05 на землю и 12в надо сверху напаять 100-200 мкф, а также L2 можно и даже может быть НУЖНО выкинуть и запаять туда перемычку.

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

anton_z

По поводу режима десульфации. Может быть тогда сделать, чтоб можно было задавать 4 параметра: ток заряда, ток разряда, период и скважность. Уже появится возможность что-то потестировать. Или меньше параметров (некоторые фиксированные), чтобы хоть как-нибудь работало. Есть несколько полумертвых акб от упс, скутера и фонаря. Хочется с ними поэксперементировать.

R2D2

ОК. В ближайшее время сделаю. Мой опытный образец после серии экспериментов немного рассыпался.

leowka

Тут есть инфа по десульфации. У меня акк как раз свинцовый мертвый есть. Пытался оживить его зарядником, но не смог. Хотел просто дать напругу небольшую на него, но т.к ток акк не брал совсем, то происходит срабатывание Vmax.

11 days later
R2D2

После упаковки ЗУ в дюралевый корпус avrcpp.narod.ru/zu17/zu.html обнаружились новые особенности:

  1. Наводки на контур стабилизации при мощности больше 50 Ватт.
  2. Наводки на шину ЖКИ, что приводит к появлению мусора на экране.

Как уберечся от такой напасти?

leowka
naumovich:

Уважаемый R2D2, пажалуйст посмотрите “mail.rambler.ru/session/…/redirect.cgi?url=http%3A…”, может каким образом приглянется.
Н.С.П.

А что в ней? Чисто для литий-ионных, думаю полимерные тоже можно заряжать, ну и свинец пойдет. И еще мега-мини корпус, не каждый сможет припаять. А еще она чисто для детекта протекающего тока, т.е управления процессом зарядки никакой, т.е просто цифровой шунт.

R2D2:

После упаковки ЗУ в дюралевый корпус avrcpp.narod.ru/zu17/zu.html обнаружились новые особенности:

  1. Наводки на контур стабилизации при мощности больше 50 Ватт.
  2. Наводки на шину ЖКИ, что приводит к появлению мусора на экране.

Как уберечся от такой напасти?

Может самый простой способ упаковать в пластиковый корпус?

R2D2

Богатая микросхема, но слишком поздно.
Посмотрел как решается проблема в B6.
Колечко задвинуто в угол питания.
ЖКИ сделано на коротких проводах.
Никаких экранов.
Вся измерительная часть в противоположном конце.
Короче чисто грамотная, умудренная опытом разводка.
Теперь и я умудрился. Это плюс.
Опять все переделывать. 😦 Это минус.
Но ведь если бы я послушался умных людей, я бы все равно не верил бы и не понимал бы.
Еще один плюс попробовать по экранировать помехи.
А если экранировать дроссель. Что-то мне говорит, что поле полезет во все щели и усилится или гденить чтонить нагреваться начнет с утечками.

leowka

Кстати такие ссылки как naumovich дает, ни в коем разе нельзя давать, в этой ссылке сессионый ключ от вашей почты, и соотв пока он активный можно спокойно вашу почту прочитать, да и ссылка умирает как сессионый ключ таймаутится.
2 R2D2 а я все пользуюсь старым варинатом зарядки(v1.5) и доволен 😃 Еще раз спасибо! Как видно выше у народа, да и по себе сужу, не так нужен этот КПД, как режимы зарядок дописанные. это я про десульфацию, струйный заряд. Жду не дождусь 😃

R2D2

Я полез править логику зарядки и увяз в инфе, наверное будет новая прошивка с сильно переработанной логикой зарядки и добавлением параметров настройки. Малыми улучшениями не получается написать прогу.

11 days later
Dimonira

Наверное уже поздно, но всё же…
У фирмы ST есть аппнота, где подробно описывается принцип действия, расчёт и выбор компонентов преобразователя напряжения, управляемого от микроконтроллера, такого же как в зарядных устройствах типа iMax B6 и т.п.
Аппноту с названием “An MCU-based low cost non-inverting buck-boost converter for battery chargers” можно взять тут: www.st.com/stonline/products/…/12476.pdf

Да, и кстати, проект зарядника с таким преобразователем у них тоже есть в другой аппноте тут:
www.st.com/stonline/products/…/12477.pdf