// ============================================================ // ИНТЕРАКТИВНЫЙ ТЕСТОВЫЙ СКЕТЧ ДЛЯ XL4015 + ESP32 DAC // ============================================================ // Управление через Serial Monitor (115200 baud) // ============================================================ #define DAC_PIN 25 // GPIO25 = DAC1 // Текущие значения uint8_t current_dac = 0; float current_voltage = 0.0; // Калибровочные значения (будут обновляться) uint8_t cal_1s = 246; // Для 4.2V uint8_t cal_2s = 195; // Для 8.4V uint8_t cal_3s = 145; // Для 12.6V uint8_t cal_4s = 0; // Для 16.8V // Настройка времени калибровки (в секундах) int calibration_delay = 10; // По умолчанию 10 секунд void setup() { Serial.begin(115200); delay(1000); // Устанавливаем начальное значение DAC dacWrite(DAC_PIN, 0); current_dac = 0; printWelcome(); printMenu(); } void loop() { // Проверяем, есть ли данные в Serial if (Serial.available() > 0) { String command = Serial.readStringUntil('\n'); command.trim(); // Убираем пробелы processCommand(command); } } // ============================================================ // ОБРАБОТКА КОМАНД // ============================================================ void processCommand(String cmd) { cmd.toLowerCase(); // Приводим к нижнему регистру Serial.println(); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); Serial.print("📨 Команда: "); Serial.println(cmd); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); // ========== ПРЯМОЕ УПРАВЛЕНИЕ DAC ========== if (cmd.startsWith("d") || cmd.startsWith("dac")) { // Команды: d100, dac100, d 100, dac 100 int value = extractNumber(cmd); if (value >= 0 && value <= 255) { setDAC(value); } else { Serial.println("❌ Ошибка: значение должно быть 0-255"); Serial.println(" Пример: d100 или dac150"); } } // ========== УПРАВЛЕНИЕ ПО БАНКАМ ========== else if (cmd == "1s") { setVoltageForCells(1); } else if (cmd == "2s") { setVoltageForCells(2); } else if (cmd == "3s") { setVoltageForCells(3); } else if (cmd == "4s") { setVoltageForCells(4); } // ========== КАЛИБРОВКА ========== else if (cmd == "cal" || cmd == "calibrate") { runCalibration(); } else if (cmd == "quickcal") { runQuickCalibration(); } // ========== НАСТРОЙКА ВРЕМЕНИ КАЛИБРОВКИ ========== else if (cmd.startsWith("delay")) { int value = extractNumber(cmd); if (value >= 1 && value <= 30) { calibration_delay = value; Serial.print("✅ Задержка калибровки установлена: "); Serial.print(value); Serial.println(" секунд"); } else { Serial.println("❌ Ошибка: значение должно быть 1-30 секунд"); Serial.println(" Пример: delay5 или delay10"); } } // ========== СОХРАНЕНИЕ КАЛИБРОВКИ ========== else if (cmd.startsWith("save1s")) { int value = extractNumber(cmd); if (value >= 0 && value <= 255) { cal_1s = value; Serial.print("✅ Сохранено: 1S = DAC "); Serial.println(value); } } else if (cmd.startsWith("save2s")) { int value = extractNumber(cmd); if (value >= 0 && value <= 255) { cal_2s = value; Serial.print("✅ Сохранено: 2S = DAC "); Serial.println(value); } } else if (cmd.startsWith("save3s")) { int value = extractNumber(cmd); if (value >= 0 && value <= 255) { cal_3s = value; Serial.print("✅ Сохранено: 3S = DAC "); Serial.println(value); } } else if (cmd.startsWith("save4s")) { int value = extractNumber(cmd); if (value >= 0 && value <= 255) { cal_4s = value; Serial.print("✅ Сохранено: 4S = DAC "); Serial.println(value); } } // ========== ИНФОРМАЦИЯ ========== else if (cmd == "info" || cmd == "status") { printStatus(); } else if (cmd == "cal_values" || cmd == "cv") { printCalibrationValues(); } // ========== БЫСТРЫЕ КОМАНДЫ ========== else if (cmd == "min") { setDAC(255); Serial.println("⬇️ Установлено минимальное напряжение (DAC=255)"); } else if (cmd == "max") { setDAC(0); Serial.println("⬆️ Установлено максимальное напряжение (DAC=0)"); } else if (cmd == "mid") { setDAC(128); Serial.println("➡️ Установлено среднее значение (DAC=128)"); } // ========== ПОШАГОВОЕ ИЗМЕНЕНИЕ ========== else if (cmd == "+" || cmd == "up") { if (current_dac < 255) { setDAC(current_dac + 1); Serial.println("⬆️ DAC +1"); } } else if (cmd == "-" || cmd == "down") { if (current_dac > 0) { setDAC(current_dac - 1); Serial.println("⬇️ DAC -1"); } } else if (cmd == "++" || cmd == "up10") { if (current_dac <= 245) { setDAC(current_dac + 10); Serial.println("⬆️ DAC +10"); } } else if (cmd == "--" || cmd == "down10") { if (current_dac >= 10) { setDAC(current_dac - 10); Serial.println("⬇️ DAC -10"); } } // ========== ПОМОЩЬ ========== else if (cmd == "help" || cmd == "?" || cmd == "menu") { printMenu(); } // ========== НЕИЗВЕСТНАЯ КОМАНДА ========== else { Serial.println("❌ Неизвестная команда!"); Serial.println(" Введи 'help' для списка команд"); } Serial.println(); } // ============================================================ // ФУНКЦИИ УПРАВЛЕНИЯ // ============================================================ void setDAC(uint8_t value) { dacWrite(DAC_PIN, value); current_dac = value; Serial.println(); Serial.println("╔═══════════════════════════════════╗"); Serial.print ("║ DAC установлен: "); Serial.print(value); Serial.print(" ("); Serial.print((value * 100.0) / 255.0, 1); Serial.println("%) ║"); Serial.println("╚═══════════════════════════════════╝"); Serial.println(); Serial.println("📊 СЕЙЧАС ИЗМЕРЬ НАПРЯЖЕНИЕ НА VOUT-1!"); Serial.println(" И запиши результат."); } void setVoltageForCells(uint8_t cells) { uint8_t dac_value; float target_voltage; switch(cells) { case 1: dac_value = cal_1s; target_voltage = 4.2; break; case 2: dac_value = cal_2s; target_voltage = 8.4; break; case 3: dac_value = cal_3s; target_voltage = 12.6; break; case 4: dac_value = cal_4s; target_voltage = 16.8; break; default: Serial.println("❌ Ошибка: недопустимое количество банок!"); return; } dacWrite(DAC_PIN, dac_value); current_dac = dac_value; Serial.println(); Serial.println("╔═══════════════════════════════════╗"); Serial.print ("║ Установлено для "); Serial.print(cells); Serial.println("S батареи ║"); Serial.print ("║ Целевое: "); Serial.print(target_voltage, 1); Serial.println("V ║"); Serial.print ("║ DAC: "); Serial.print(dac_value); Serial.println(" ║"); Serial.println("╚═══════════════════════════════════╝"); Serial.println(); Serial.println("📊 Проверь напряжение вольтметром!"); Serial.print(" Должно быть около "); Serial.print(target_voltage); Serial.println("V"); } // ============================================================ // КАЛИБРОВКА // ============================================================ void runCalibration() { Serial.println(); Serial.println("╔═══════════════════════════════════════════╗"); Serial.println("║ РЕЖИМ ПОЛНОЙ КАЛИБРОВКИ ║"); Serial.println("╚═══════════════════════════════════════════╝"); Serial.println(); Serial.println("⚠️ ПОДГОТОВКА:"); Serial.println(" 1. Подключи вольтметр к VOUT-1"); Serial.println(" 2. НЕ подключай нагрузку!"); Serial.println(" 3. Приготовь ручку и бумагу"); Serial.println(); Serial.print("⏱️ Задержка на измерение: "); Serial.print(calibration_delay); Serial.println(" секунд"); Serial.println(" (Изменить: delay5, delay10, delay15 и т.д.)"); Serial.println(); Serial.println("📋 Для каждого значения DAC:"); Serial.print(" - Жди "); Serial.print(calibration_delay); Serial.println(" секунд стабилизации"); Serial.println(" - Измерь напряжение"); Serial.println(" - Запиши в таблицу"); Serial.println(); Serial.println("Нажми ENTER для начала..."); // Ждём нажатия Enter while(Serial.available() == 0) { delay(100); } Serial.readString(); // Очищаем буфер Serial.println(); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); Serial.println(" НАЧАЛО КАЛИБРОВКИ"); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); // Проходим по значениям DAC с шагом 25 for (int dac_value = 0; dac_value <= 255; dac_value += 25) { dacWrite(DAC_PIN, dac_value); Serial.println(); Serial.print("┌─ DAC = "); Serial.print(dac_value); Serial.println(" ─────────────────────"); Serial.println("│"); Serial.print("│ Ожидание "); Serial.print(calibration_delay); Serial.print(" сек"); // Ждём стабилизации с анимацией int steps = calibration_delay * 2; // Каждые 0.5 секунды точка for (int i = 0; i < steps; i++) { delay(500); Serial.print("."); } Serial.println(); Serial.println("│"); Serial.println("│ 🔔 ЗВУКОВОЙ СИГНАЛ - ИЗМЕРЯЙ СЕЙЧАС!"); Serial.println("│"); Serial.println("│ 📊 ИЗМЕРЬ НАПРЯЖЕНИЕ НА VOUT-1!"); Serial.print("│ Запиши: DAC "); Serial.print(dac_value); Serial.println(" = _____ V"); Serial.println("│"); // Дополнительная пауза для записи (3 секунды) Serial.println("│ (3 сек на запись"); for (int i = 0; i < 6; i++) { delay(500); Serial.print("."); } Serial.println(")"); Serial.println("└─────────────────────────────────"); } Serial.println(); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); Serial.println("✅ КАЛИБРОВКА ЗАВЕРШЕНА!"); Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); Serial.println(); Serial.println("📋 Теперь найди в таблице значения DAC для:"); Serial.println(" - 4.2V (1S) → введи: save1s [значение]"); Serial.println(" - 8.4V (2S) → введи: save2s [значение]"); Serial.println(" - 12.6V (3S) → введи: save3s [значение]"); Serial.println(" - 16.8V (4S) → введи: save4s [значение]"); Serial.println(); Serial.println("Пример: save1s 150"); // Возвращаемся к DAC=0 dacWrite(DAC_PIN, 0); } void runQuickCalibration() { Serial.println(); Serial.println("╔═══════════════════════════════════════════╗"); Serial.println("║ РЕЖИМ БЫСТРОЙ КАЛИБРОВКИ ║"); Serial.println("╚═══════════════════════════════════════════╝"); Serial.println(); Serial.println("Проверяются только ключевые точки:"); Serial.println(); int key_values[] = {0, 50, 100, 150, 200, 255}; for (int i = 0; i < 6; i++) { int dac_value = key_values[i]; dacWrite(DAC_PIN, dac_value); Serial.print("DAC = "); Serial.print(dac_value); Serial.print(" → Измерь напряжение"); for (int j = 0; j < 4; j++) { delay(500); Serial.print("."); } Serial.println(" СЕЙЧАС!"); delay(2000); } Serial.println(); Serial.println("✅ Быстрая калибровка завершена!"); dacWrite(DAC_PIN, 0); } // ============================================================ // ИНФОРМАЦИЯ И МЕНЮ // ============================================================ void printWelcome() { Serial.println(); Serial.println("╔═════════════════════════════════════════════════╗"); Serial.println("║ ║"); Serial.println("║ XL4015 + ESP32 DAC ТЕСТОВЫЙ СКЕТЧ ║"); Serial.println("║ Управление зарядным устройством ║"); Serial.println("║ ║"); Serial.println("╚═════════════════════════════════════════════════╝"); Serial.println(); Serial.println("✅ Система готова к работе!"); Serial.println("📌 GPIO25 (DAC1) подключен к FB через 470Ω"); Serial.println("⚡ Напряжение DAC: 0-3.3V (0-255 в коде)"); Serial.println(); } void printMenu() { Serial.println(); Serial.println("╔═══════════════════════════════════════════════════╗"); Serial.println("║ СПИСОК КОМАНД ║"); Serial.println("╠═══════════════════════════════════════════════════╣"); Serial.println("║ ПРЯМОЕ УПРАВЛЕНИЕ DAC: ║"); Serial.println("║ d[число] Установить DAC (0-255) ║"); Serial.println("║ Примеры: d100, dac150, d 200 ║"); Serial.println("║ min DAC = 255 (минимум VOUT) ║"); Serial.println("║ max DAC = 0 (максимум VOUT) ║"); Serial.println("║ mid DAC = 128 (среднее) ║"); Serial.println("║ + / up DAC +1 ║"); Serial.println("║ - / down DAC -1 ║"); Serial.println("║ ++ / up10 DAC +10 ║"); Serial.println("║ -- / down10 DAC -10 ║"); Serial.println("╠═══════════════════════════════════════════════════╣"); Serial.println("║ УПРАВЛЕНИЕ ПО БАНКАМ: ║"); Serial.println("║ 1s 4.2V (1S батарея) ║"); Serial.println("║ 2s 8.4V (2S батарея) ║"); Serial.println("║ 3s 12.6V (3S батарея) ║"); Serial.println("║ 4s 16.8V (4S батарея) ║"); Serial.println("╠═══════════════════════════════════════════════════╣"); Serial.println("║ КАЛИБРОВКА: ║"); Serial.println("║ cal Полная калибровка (0-255, шаг 25)║"); Serial.println("║ quickcal Быстрая калибровка (6 точек) ║"); Serial.println("║ save1s [N] Сохранить DAC для 1S (4.2V) ║"); Serial.println("║ save2s [N] Сохранить DAC для 2S (8.4V) ║"); Serial.println("║ save3s [N] Сохранить DAC для 3S (12.6V) ║"); Serial.println("║ save4s [N] Сохранить DAC для 4S (16.8V) ║"); Serial.println("║ Пример: save1s 150 ║"); Serial.println("╠═══════════════════════════════════════════════════╣"); Serial.println("║ ИНФОРМАЦИЯ: ║"); Serial.println("║ info Текущий статус ║"); Serial.println("║ cv Значения калибровки ║"); Serial.println("║ help Показать это меню ║"); Serial.println("╚═══════════════════════════════════════════════════╝"); Serial.println(); Serial.println("💡 Начни с команды 'cal' для калибровки!"); Serial.println(); } void printStatus() { Serial.println(); Serial.println("╔═══════════════════════════════════╗"); Serial.println("║ ТЕКУЩИЙ СТАТУС ║"); Serial.println("╠═══════════════════════════════════╣"); Serial.print ("║ DAC значение: "); Serial.print(current_dac); Serial.print(" ("); Serial.print((current_dac * 100.0) / 255.0, 1); Serial.println("%) ║"); Serial.print ("║ DAC напряжение: "); Serial.print((current_dac * 3.3) / 255.0, 2); Serial.println("V ║"); Serial.println("╚═══════════════════════════════════╝"); Serial.println(); } void printCalibrationValues() { Serial.println(); Serial.println("╔═══════════════════════════════════════╗"); Serial.println("║ КАЛИБРОВОЧНЫЕ ЗНАЧЕНИЯ ║"); Serial.println("╠═══════════════════════════════════════╣"); Serial.print ("║ 1S (4.2V): DAC = "); Serial.print(cal_1s); Serial.println(" ║"); Serial.print ("║ 2S (8.4V): DAC = "); Serial.print(cal_2s); Serial.println(" ║"); Serial.print ("║ 3S (12.6V): DAC = "); Serial.print(cal_3s); Serial.println(" ║"); Serial.print ("║ 4S (16.8V): DAC = "); Serial.print(cal_4s); Serial.println(" ║"); Serial.println("╚═══════════════════════════════════════╝"); Serial.println(); Serial.println("Для изменения используй команды:"); Serial.println(" save1s [число], save2s [число], и т.д."); Serial.println(); } // ============================================================ // ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ // ============================================================ int extractNumber(String str) { // Убираем все не-цифры в начале int startIndex = 0; while (startIndex < str.length() && !isDigit(str[startIndex])) { startIndex++; } // Извлекаем число String numberStr = str.substring(startIndex); numberStr.trim(); if (numberStr.length() > 0) { return numberStr.toInt(); } return -1; // Ошибка }