UPS для WiFi своими руками
Свет по-прежнему периодически пропадает. И хотя старый самодельный UPS на 9 вольт выходного напряжения и с питанием от БП ноутбука для WiFi ещё работает. Но вот аккумулятор на 12 вольт 7 ампер-часов уже подустал, а новый покупать неохота. Да и схема на операционнике не всем моим хотелкам уже отвечает.
Посмотрел описания и отзывы по китайским модулям для создания UPS для WiFi. Картина грустная. Настроить гистерезис включения – отключения зарядки аккумулятора нельзя. Настроить нижний порог, при котором батарея отключается от нагрузки, тоже нельзя. Индикация скромненькая. Нарастить ёмкость батареи – проблема.
Зато есть несколько банок 18650 после ремонта друзьям батареи самоката. И есть кучка ATtiny13.
Поэтому решил попробовать сделать новый UPS для своего WiFi под следующие требования:
— использование батареи 3S на 18650;
— возможность запрограммировать зарядный ток и перепрограммировать его при необходимости;
— использование схемы зарядки CC-CV;
— отключение от заряда полностью заряженного аккумулятора;
— возможность запрограммировать порог напряжения для аккумулятора, при снижении до которого, вновь включится зарядка;
— возможность задать минимальный ток, при снижении до которого при напряжении 12,6 вольт, будет отключаться заряд аккумулятора;
— контроль нижнего порога напряжения, считающегося нижним пределом для аккумулятора и при котором будет отключаться нагрузка и выдаваться сигнал аварии (красный светодиод);
— автоматически возвращаться из режима аварии и переход на зарядку, после появления сетевого питания;
— плавное нарастание тока при старте заряда аккумулятора для более бережного отношения к аккумулятору;
— возможность использования подуставших аккумуляторов, которые не способны зарядиться до 12,6 вольт (до 4,2 на элемент) и по которым нужно принимать решение о прекращении зарядки по другим критериям;
— возможность использования в качестве источника питания, блока питания от ноутбука, который использовался и в старом UPS;
— индикация режима зарядам (желтый светодиод);
— индикация питания от сети (синий светодиод);
— индикация уровня заряда аккумулятора;
— мгновенный переход на питание от батареи и обратно без задержки;
— защита от переполюсовки аккумулятора;
— возможность полностью отключить тумблером аккумулятор от схемы при разряде до аварийного уровня или при долгом отсутствии дома, чтобы не разряжался его даже малым током потребления контроллера.
Из-за выбранного варианта индикации, обнаружилась проблема нехватки выводов ATtiny13. Два вывода нужно для контроля напряжения и тока. Один для контроля напряжения питания. Один для управления выходным DC-DC преобразователем. И один для управления с помощью ШИМ сигнала DC-DC преобразователя, который и будет регулировать ток заряда аккумулятора от блока питания ноутбука.
И получилось, что индицировать включение заряда ещё одной ножки не хватает.
Пришлось добавить детектор на диоде конденсаторе и транзисторе, который включит светодиод при появлении на выходе PB0 ШИМ сигнала.
В результате получилась вот такая схема:

Прошивка создавалась на Arduino IDE 1.8.19. Уложилась в 820 байт. Частота контроллера 9,6 МГц. Опорное напряжение от внутреннего источника 1,1 вольт. По факту оказалось 1,071363 вольт.
Поэтому для точности измерений, желательно проверить уровень опорного в своём контроллере. Ну, или просто подстроить коэффициенты методом проб и ошибок.
Т.к. резисторы у меня не прецизионные, то добавлен подстроечник в делитель напряжения для измерения напряжения батареи. С его помощью при отсутствии сетевого питания были установлены одинаковые уровни напряжения на ножках контроллера PB2 и PB3.
У меня контроллер установлен в панельку, поэтому проблем с перепрошивкой при отладке не возникало.
При желании получить другое выходное напряжение, меняется выходной DC-DC преобразователь на другое напряжение.
Если есть желание получить другой ток заряда, то нужно пересчитать. Принцип расчёта описан в скетче.
В скетче приведено описание вообще всех параметров и расчётов для работы программы.
Сейчас UPS используется со сборкой 3S2P банок 18650 по 2000 миллиампер-часов каждая. Этого должно хватать часов на 10 работы WiFi. При необходимости увеличить время работы, просто добавляется число банок — 3S3P или 3S4P и/или ставятся более ёмкие аккумуляторы.
Код скетча:
Посмотрел описания и отзывы по китайским модулям для создания UPS для WiFi. Картина грустная. Настроить гистерезис включения – отключения зарядки аккумулятора нельзя. Настроить нижний порог, при котором батарея отключается от нагрузки, тоже нельзя. Индикация скромненькая. Нарастить ёмкость батареи – проблема.
Зато есть несколько банок 18650 после ремонта друзьям батареи самоката. И есть кучка ATtiny13.
Поэтому решил попробовать сделать новый UPS для своего WiFi под следующие требования:
— использование батареи 3S на 18650;
— возможность запрограммировать зарядный ток и перепрограммировать его при необходимости;
— использование схемы зарядки CC-CV;
— отключение от заряда полностью заряженного аккумулятора;
— возможность запрограммировать порог напряжения для аккумулятора, при снижении до которого, вновь включится зарядка;
— возможность задать минимальный ток, при снижении до которого при напряжении 12,6 вольт, будет отключаться заряд аккумулятора;
— контроль нижнего порога напряжения, считающегося нижним пределом для аккумулятора и при котором будет отключаться нагрузка и выдаваться сигнал аварии (красный светодиод);
— автоматически возвращаться из режима аварии и переход на зарядку, после появления сетевого питания;
— плавное нарастание тока при старте заряда аккумулятора для более бережного отношения к аккумулятору;
— возможность использования подуставших аккумуляторов, которые не способны зарядиться до 12,6 вольт (до 4,2 на элемент) и по которым нужно принимать решение о прекращении зарядки по другим критериям;
— возможность использования в качестве источника питания, блока питания от ноутбука, который использовался и в старом UPS;
— индикация режима зарядам (желтый светодиод);
— индикация питания от сети (синий светодиод);
— индикация уровня заряда аккумулятора;
— мгновенный переход на питание от батареи и обратно без задержки;
— защита от переполюсовки аккумулятора;
— возможность полностью отключить тумблером аккумулятор от схемы при разряде до аварийного уровня или при долгом отсутствии дома, чтобы не разряжался его даже малым током потребления контроллера.
Из-за выбранного варианта индикации, обнаружилась проблема нехватки выводов ATtiny13. Два вывода нужно для контроля напряжения и тока. Один для контроля напряжения питания. Один для управления выходным DC-DC преобразователем. И один для управления с помощью ШИМ сигнала DC-DC преобразователя, который и будет регулировать ток заряда аккумулятора от блока питания ноутбука.
И получилось, что индицировать включение заряда ещё одной ножки не хватает.
Пришлось добавить детектор на диоде конденсаторе и транзисторе, который включит светодиод при появлении на выходе PB0 ШИМ сигнала.
В результате получилась вот такая схема:

Прошивка создавалась на Arduino IDE 1.8.19. Уложилась в 820 байт. Частота контроллера 9,6 МГц. Опорное напряжение от внутреннего источника 1,1 вольт. По факту оказалось 1,071363 вольт.
Поэтому для точности измерений, желательно проверить уровень опорного в своём контроллере. Ну, или просто подстроить коэффициенты методом проб и ошибок.
Т.к. резисторы у меня не прецизионные, то добавлен подстроечник в делитель напряжения для измерения напряжения батареи. С его помощью при отсутствии сетевого питания были установлены одинаковые уровни напряжения на ножках контроллера PB2 и PB3.
У меня контроллер установлен в панельку, поэтому проблем с перепрошивкой при отладке не возникало.
При желании получить другое выходное напряжение, меняется выходной DC-DC преобразователь на другое напряжение.
Если есть желание получить другой ток заряда, то нужно пересчитать. Принцип расчёта описан в скетче.
В скетче приведено описание вообще всех параметров и расчётов для работы программы.
Сейчас UPS используется со сборкой 3S2P банок 18650 по 2000 миллиампер-часов каждая. Этого должно хватать часов на 10 работы WiFi. При необходимости увеличить время работы, просто добавляется число банок — 3S3P или 3S4P и/или ставятся более ёмкие аккумуляторы.
Код скетча:
/****************************************************************************************
* Программа для ATtiny13 для UPS на трёх последовательных 18650, питающего WiFi на 9 вольт
* Для вариантов на 6 или 5 вольт, достаточно поменять версию Mini560 на соответствующее напряжение
* Скетч использует 820 байт (80%) памяти устройства. Всего доступно 1024 байт.
* Глобальные переменные используют 15 байт (23%) динамической памяти, оставляя 49 байт для локальных переменных. Максимум: 64 байт.
*
*
* Принципы работы:
* - Контролируем напряжение на АКБ (из трёх 18650 с BMS платой) и ток через шунт 1 Ом (1 Ватт) включенный между выходом DC-DC и АКБ
* - Зарядный ток в программе ограничен на уровне 1,6 А. Если для вашей батареи этого мало, просто уменьшите шунт. При 0,5 Ом ток будет ограничен на уровне 3,2 А.
* - При достижении 12,6 В (4,2 на элемент 18650) и снижении тока до 0,16 А, ШИМ отключаем и устанавливается целевое напряжение 11,7 В (3,9 В на элемент 18650)
* - При снижении напряжения на аккумуляторе до уровня 11,7 В, снова включатся ШИМ для зарядки от БП
* - Если ток при 12,6 В не упадёт до 0,16 А, но ШИМ дойдёт до минимального значения, то также завершаем зарядку.
* - При снижении напряжения аккумулятора ниже 10,2 В (3,4 на элемент 18650) поднимается флаг аварии, зажигается светодиод аварии, отключается ШИМ и нагрузка.
* - При появлении внешнего питания запустится ШИМ в штатном режиме - плавный рост ШИМ, начиная с уровня 12 на выходе PB0.
* - Максимальный уровень ШИМ ограничен величиной 200. Это обеспечивает ток около 2 А при напряжении блока питания 19 вольт.
* - Также считаем заряд оконченным, если напряжение на аккумуляторе не растёт больше 30 минут хотя бы на 0,035 В.
* - Это бывает у приуставших аккумуляторах.
* - В этом случае, также отключается заряд и поднимается флаг "АКБ заряжен"
* - Желтый светодиод показывают когда батарея заряжается (ШИМ работает).
* - Он подключен не к отдельной ножке контроллера, а к детектору импульсов на выходе ШИМ (РВ1)
*
* = Частота контроллера 9,6 МГц.
* = Образцовое напряжение задано внутренним источником 1,1 В (реально на моём экземпляре ATtiny13 опорное 1,071363 В)
* = Частота ШИМ = 37,5 кГц
* = Цена одного разряда АЦП = 0,001074 В (это в идеале, а в моём контроллере 0,001046 - видимо вместо 1,1 В в моём ATTiny13 пороговое 1,071363 В).
* - Для точности - измеряем напряжение 16 раз и складываем значения.
* - После этого не делим сумму 16 замеров на 16, а используем как есть, сравнивая её с контрольными напряжениями на шунте и блоке питания умноженными на 16
* - Измерение напряжений на шунте производится через делитель напряжения 15 кОм и 1 кОм. (точнее 975 Ом - постоянный 910 Ом и подстроечник на 100 Ом).
* Подстроечником выравнивал напряжение на обоих делителях - до шунта и после. Разница на делителях 0,001 В.
* Контрольные напряжения:
* - контролируемое значение при полном заряде - 12,6 В -> 0,762 на делителе -> 0,762 / 0,001046 * 16 = 11656
* - контролируемое значение порога повторного включения - 11,7 В -> 0,708 на делителе -> 0,708 / 0,001046 * 16 = 10830
* - контролируемое значение порога отключения нагрузки - 10,2 В -> 0,617 на делителе -> 0,617 / 0,001046 * 16 = 9438
* - нижний порог включения при подключении аккумулятора - 7,5 В (три элемента 18650 по 2,5 В) -> 0,453 на делителе -> 0,453 / 0,001046 * 16 = 6929
* Ток рассчитываем по разнице напряжений до шунта и после.
* - для тока 1,6 А получим контрольное значение (разницу напряжений до и после шунта) -> 1,6 В / 16,53 = 0,09679 В / 0,001046 = 92,537 * 16 = 1480
* - для тока 0,16 А получим контрольное значение (разницу напряжений до и после шунта) -> 0,16 В / 16,53 = 0,009679 / 0,001046 = 9,2537 * 16 = 148
* - контроль прироста напряжение за 30 минут менее, чем на 0,035 В, при котором также считаем заряд оконченным -> 0,035 / 0,001046 * 16 = 32
* Максимально можно измерить с таким делителем до переполнения АЦП -> 17,7 В
* - Если не подключена батарея, то система отключает ШИМ и выходит в состояние "Зарядка завершена" по превышению напряжения 13,24 В на аккумуляторе.
* - При подключении аккумулятора снова, система переходит в режим заряда.
*
* Контроль напряжения питания (19 В) контролируем через делитель 20 кОм и 1 кОм.
* Если на входе нет напряжения выше 15 вольт, то отключаем заряд аккумулятора.
*
*******************************************************************************************/
#include <avr/io.h>
#include <util/delay.h>
// Номера каналов АЦП (соответствуют физической разводке пинов ATtiny13)
#define ADC_BEFORE_SHUNT 3 // PB3 (ADC3) - Напряжение до шунта
#define ADC_AFTER_SHUNT 1 // PB2 (ADC1) - Напряжение после шунта (АКБ)
#define ADC_19V 2 // PB4 (ADC2) - Контроль сети питания 19В (через делитель 20к/1к)
#define PB1_MINI560 1 // PB1 - Выход управления EN платы MINI560
#define PB0_PWM 0 // PB0 - ШИМ управления затвором мосфета
#define PWM_MAX 200 // Максимально допустимое значение ШИМ - около 2 А
#define PWM_MIN 20 // Минимально допустимое значение ШИМ - после которого принимаем решение об отключении ШИМ
#define PWM_START 160 // Начальное значение ШИМ при заряде - около 0,3 А
// Целевые константы для 16 накопленных замеров (опорное 1.1В)
const uint16_t VOLTAGE_LOW_15V = 10630; // Порог наличия сети (15 В при делителе 20к/1к)
const uint16_t CURRENT_1_6A = 1500; // Ток стабилизации (1.6 А) - чуть округлил от 1480 расчётных
const uint16_t CURRENT_0_16A = 150; // Ток окончания заряда (0.16 А) - чуть округлил от 148 расчётных
const uint16_t VOLTAGE_12_6V = 11656; // Порог ограничения напряжения (12.6 В)
const uint16_t VOLTAGE_11_7V = 10830; // Порог повторного включения (12.6 - 0.9 = 11.7 В => 3,9 В на элемент 18650)
const uint16_t VOLTAGE_10_2V = 9438; // Порог аварийного отключения MINI560 (10.2 В => 3,4 В на элемент 18650)
const uint16_t VOLTAGE_7_5V = 6929; // Нижний порог включения при возврате аккумулятора (7.5 В)
const uint16_t VOLTAGE_0_01V = 32; // Порог минимального прироста напряжения (0.035 В)
const uint16_t VOLTAGE_NO_BATT = 12250; // Порог повышенного напряжения (свыше 13,24 В на клеммах, АКБ отключен)
int16_t pwm_out = 0; // Текущая скважность ШИМ
// Логические флаги состояний системы
bool is_charging = true; // Идет процесс зарядки (CC или CV)
bool is_charged = false; // Батарея полностью заряжена, ШИМ выключен
bool was_power_lost = false; // Флаг: была потеряна сеть
bool no_battery_mode = false; // Флаг: аккумулятор физически отключен
uint16_t step_timer = 0; // Таймер для замедления шагов регулирования тока (до 100 мс)
uint32_t degradation_timer = 0; // Таймер для контроля «уставших» АКБ (30 минут)
uint16_t last_saved_voltage = 0; // Переменная хранения прошлого значения напряжения
// Сбор 16 замеров АЦП БЕЗ деления для повышения точности
uint16_t read_adc_16 (uint8_t channel)
{
uint16_t sum = 0;
ADMUX = (1 << REFS0) | (channel & 0x03); // Сохраняем внутреннее опорное 1.1В
_delay_us(20); // Пауза для стабилизации мультиплексора АЦП
for (uint8_t i = 0; i < 16; i++)
{
ADCSRA |= (1 << ADSC); // Запуск преобразования
while (ADCSRA & (1 << ADSC)); // Ожидание окончания замера
sum += ADC; // Накапливаем сумму 16 замеров
}
return sum; // Возврат полученной суммы
}
// Полное аппаратное отключение ШИМ (железобетонный стоп генерации)
void shutdown_pwm()
{
TCCR0B &= ~(1 << CS00); // СТОП ТАЙМЕР: убираем тактирование (No clock)
TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); // Отвязываем таймер от пина PB0
PORTB &= ~(1 << PB0_PWM); // Жестко прижимаем затвор к земле (0 Вольт)
OCR0A = 0; // Сбрасываем регистр сравнения
}
// Аппаратное включение ШИМ
void start_pwm()
{
TCCR0A |= (1 << COM0A1); // Подключаем ШИМ к пину PB0
TCCR0B |= (1 << CS00); // ЗАПУСК ТАЙМЕРА: тактирование напрямую (37.5 кГц при 9.6 МГц)
}
// ========================================================
// НАЧАЛЬНАЯ УСТАНОВКА
// ========================================================
void setup()
{
DDRB |= (1 << PB0_PWM); // Настраиваем PB0 на выход (ШИМ мосфета)
// Инициализация PB1 под активное управление MINI560 (резистор 1.5 кОм на землю)
DDRB |= (1 << PB1_MINI560); // Порт РВ1 переключить на выход
PORTB |= (1 << PB1_MINI560); // Выдаем логическую 1 (5 В) — принудительно ВКЛЮЧАЕМ MINI560
// Режим Fast PWM 8-bit (WGM01=1, WGM00=1), запуск тактирования таймера
TCCR0A |= (1 << WGM01) | (1 << WGM00);
TCCR0B |= (1 << CS00);
// Включение АЦП, выбор предделителя частоты 64 (частота АЦП 150 кГц при тактовой 9.6 МГц)
ADMUX = (1 << REFS0);
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1);
_delay_ms(50);
last_saved_voltage = read_adc_16(ADC_AFTER_SHUNT); // Базовая точка отсчета напряжения
pwm_out = PWM_MIN; // Стартовое значение для мягкого пуска ШИМ
}
void loop()
{
// === МОНИТОРИНГ СЕТИ (каждые 10 мс)
uint16_t val_net = read_adc_16(ADC_19V);
bool power_present = (val_net >= VOLTAGE_LOW_15V);
// ================================================================================================
// РЕЖИМ А: СЕТИ НЕТ (РАБОТА НАГРУЗКИ ОТ АККУМУЛЯТОРА) - крутимся в этом цикле до появления питания
// ================================================================================================
if (!power_present) // Если нет питания
{
shutdown_pwm(); // Мгновенно тушим ШИМ зарядки (стоп таймера)
was_power_lost = true; // Взводим флаг: сеть пропадала
uint16_t adc_after = read_adc_16(ADC_AFTER_SHUNT); // Измеряем батарею в разряде
// Защита лития от глубокого разряда: если напряжение упало ниже 10.2 В
if (adc_after <= VOLTAGE_10_2V)
{
PORTB &= ~(1 << PB1_MINI560); // Выводим 0 В на вывод EN MINI560 - отключаем от аккумулятора нагрузку
// Резистор 1.5к досадит MINI560 до нуля и погасит MINI560
}
_delay_ms(10);
return; // Прерываем loop(), возвращаемся в начало на проверку сети
}
// ========================================================
// РЕЖИМ Б: СЕТЬ ЕСТЬ (АКТИВНАЯ РАБОТА И ЗАРЯДКА)
// ========================================================
// Сценарий восстановления: если сеть ТОЛЬКО ЧТО вернулась после аварии
if (was_power_lost) // Если было пропадание сети
{
PORTB |= (1 << PB1_MINI560); // Гарантированно включаем MINI560 (5 В на выходе РВ1)
// Ждем 300 мс, чтобы MINI560 запустился, а переходные напряжения на входе выровнялись
_delay_ms(300);
was_power_lost = false; // Сбрасываем флаг Сеть пропадала
no_battery_mode = false; // Сбрасываем флаг отсутствия батареи
is_charging = true; // Сбрасываем автоматику в режим новой плавной зарядки
is_charged = false;
pwm_out = PWM_START; // Откатываем ШИМ на безопасный минимум
step_timer = 0; // Сбрасываем таймер шагов (каждый шаг - 10 мс - продолжительность цикла)
degradation_timer = 0; // Сбрасываем таймер 30 минут ожидания роста напряжения
uint16_t temp_after = read_adc_16(ADC_AFTER_SHUNT);
last_saved_voltage = temp_after;
return;
}
// Считываем датчик на клеммах аккумулятора
uint16_t adc_after = read_adc_16(ADC_AFTER_SHUNT);
// --- ПРОВЕРКА ЗАЩИТЫ: ОПРЕДЕЛЕНИЕ ОТСУТСТВИЯ АККУМУЛЯТОРА ---
if (adc_after >= VOLTAGE_NO_BATT) // Если напряжение на батарее больше 12,9 В (батареи нет - напряжение подскочило)
{
shutdown_pwm(); // Мгновенно выключаем ШИМ
no_battery_mode = true; // Переходим в специальный защитный режим
is_charging = false; // Отключаем разрешение зарядки
is_charged = false; // Опускаем флаг Батарея заряжена
}
// ========================================================
// ОБРАБОТКА ВЕТОК СОСТОЯНИЙ (ПРИ НАЛИЧИИ СЕТИ)
// ========================================================
// --- ПОДРЕЖИМ Б.0: ОЖИДАНИЕ ПОДКЛЮЧЕНИЯ АККУМУЛЯТОРА ---
if (no_battery_mode) // Если нет батареи
{
shutdown_pwm(); // ШИМ выключен
PORTB |= (1 << PB1_MINI560); // MINI560 включен и работает напрямую от сети 19 В
// Выходим из защиты, только если на клеммах появилось адекватное напряжение батареи
// (меньше порога перезапуска 12.6В, но выше 7,5 В - три батареи по 2,5 В - меньше нет смысла ставить - это мёртвые батареи)
if (adc_after < VOLTAGE_12_6V && adc_after > VOLTAGE_7_5V)
{
no_battery_mode = false; // Сбросить флаг отсутствия батареи
is_charging = true; // Разрешаем зарядку подключенного АКБ
pwm_out = PWM_START; // Плавный пуск с минимального значения ШИМ
step_timer = 0; // Сброс счётчика шагов
degradation_timer = 0; // Сброс таймера 30 минут
last_saved_voltage = adc_after; // Пересохранить свежее значение напряжение на батарее
}
_delay_ms(10);
return; // Пропускаем остальной код зарядки, пока АКБ не подключен
}
// Считываем напряжение до и после шунта
uint16_t adc_before = read_adc_16(ADC_BEFORE_SHUNT);
//uint16_t adc_after = read_adc_16(ADC_AFTER_SHUNT);
// Вычисляем ток как знаковую разность (убирает ловушку нулевого тока)
int16_t current_current = (int16_t)adc_before - (int16_t)adc_after; // Вычисляем падение напряжения на шунте
if (current_current < 0) current_current = 0; // Отрезаем отрицательные шумы
// --- ПОДРЕЖИМ Б.1: ИДЕТ АКТИВНАЯ ЗАРЯДКА АКБ ---
if (is_charging) // Если есть разрешение на заряд батареи
{
PORTB |= (1 << PB1_MINI560); // Включаем МИНИ560 (1 на порт РВ1)
OCR0A = (uint8_t)pwm_out; // Выдаём pwm_out в ШИМ порт
start_pwm(); // Включить ШИМ
step_timer++; // Увеличиваем счётчик шагов
if (step_timer >= 10) // Если прошло 10 шагов - заходим сюда через каждые 0,1 сек.
{
step_timer = 0; // Сбрасываем в ноль счётчик шагов
// Приоритет 1: Защита от перезаряда 12.6В (CV)
if (adc_after >= VOLTAGE_12_6V) // Если напряжение на аккумуляторе больше или равно 12,6 В
{
if (pwm_out > PWM_MIN) // ... и ШИМ больше минимально допустимого значения, то ...
pwm_out--; // ... уменьшить переменную ШИМ
}
// Приоритет 2: Стабилизация тока на уровне 1.0 А (CC)
else // Если ещё не достигли 12,6 В
{
// Если реальный ток меньше целевого 1А (931 единица)
if ((uint16_t)current_current < CURRENT_1_6A) // Если падение напряжения на шунте меньше 1 А
{
if (pwm_out < PWM_MAX) // Если не превышен максимально разрешенный уровень ШИМ
pwm_out++; // Увеличиваем ШИМ
}
// Если ток превысил целевой 1А
else if ((uint16_t)current_current > (CURRENT_1_6A + 30))
{
if (pwm_out > PWM_MIN) // Если не достигли минимально разрешенного уровня ШИМ
pwm_out--; // Уменьшаем ШИМ
}
}
}
// Критерий окончания №1: Ток упал до 0.12 А при зафиксированном CV напряжении 12.6 В
// ИЛИ скважность ШИМ опустилась до самого минимума (качать больше некуда) — переходим в отключение
if (adc_after >= VOLTAGE_12_6V && ((uint16_t)current_current <= (CURRENT_0_16A) || pwm_out <= PWM_MIN))
//if (adc_after >= VOLTAGE_12_6V && current_current <= CURRENT_0_16A)
{
shutdown_pwm(); // Отключаем ШИМ
is_charging = false; // Сбрасываем флаг разрешения заряда
is_charged = true; // Поднимаем флаг окончания заряда
degradation_timer = 0; // Сбрасываем таймер 30 минут без роста напряжения
pwm_out = 0; // Сбрасываем память ШИМ
}
// Критерий окончания №2: Контроль стареющих аккумуляторов (+0.01 В за 30 минут)
degradation_timer++; // Увеличиваем таймер 30 минут без роста напряжения
if (degradation_timer >= 180000) // Если прошло 180000 шагов по 10 мс = ровно 30 минут
{
degradation_timer = 0; // Сбрасываем таймер 30 минут без роста напряжения
// Если дельта роста напряжения меньше 9 единиц виртуального АЦП (0.01 В)
if (last_saved_voltage > 0 && (adc_after - last_saved_voltage) < VOLTAGE_0_01V)
{
shutdown_pwm(); // Отключаем ШИМ
is_charging = false; // Сбрасываем флаг разрешения заряда
is_charged = true; // Отсекаем заряд по деградации
pwm_out = 0; // Сбрасываем память ШИМ
}
last_saved_voltage = adc_after; // Обновляем контрольную точку
}
}
// --- ПОДРЕЖИМ Б.2: БАТАРЕЯ ЗАРЯЖЕНА (РЕЖИМ ОЖИДАНИЯ СЕТИ) ---
else if (is_charged) // Если есть флаг Батарея заряжена
{
shutdown_pwm(); // Выключаем ШИМ (0 В на РВ0)
PORTB |= (1 << PB1_MINI560); // На РВ1 выдать 1 - MINI560 работает штатно, питая потребителей напрямую от сети 19 В
// Критерий возобновления заряда: естественный саморазряд батареи на 0.9 В (до 11.7 В)
if (adc_after <= VOLTAGE_11_7V) // Если напряжение на аккумуляторе меньше 11,7 В, то ...
{
pwm_out = PWM_START; // Включаем ШИМ со стартовым значением - перезапуск заряда
is_charging = true; // Поднимаем флаг разрешения заряда
is_charged = false; // Сбрасываем флаг окончания заряда
}
}
// ПРИМЕЧАНИЕ: Для тестов в Proteus оставьте задержку 10 мс. Для готового физического железа
// её можно увеличить до 50-100 мс, чтобы дополнительно снизить энергопотребление АЦП.
_delay_ms(10);
}
свернутьразвернуть
Комментарии (1)
RSS
0
- 21 октября 2026, 01:36
Если подразумевается сборка из различных/старых элементов, то я бы добавил контроль напряжения в каждом блоке 3S и возможно, балансировку.
Самые обсуждаемые обзоры