Spaces:
Running
Running
// Класс для работы с SD картой | |
class SDCardManager { | |
public: | |
bool init() { | |
if (!SD.begin(SD_CS_PIN, SPI, SD_SPI_SPEED)) { | |
Serial.println("Ошибка инициализации SD карты"); | |
return false; | |
} | |
return true; | |
} | |
bool saveData(const char* filename, const void* data, size_t size) { | |
File file = SD.open(filename, FILE_WRITE); | |
if (!file) { | |
Serial.println("Ошибка открытия файла для записи"); | |
return false; | |
} | |
size_t written = file.write((const uint8_t*)data, size); | |
file.close(); | |
return written == size; | |
} | |
bool loadData(const char* filename, void* data, size_t size) { | |
File file = SD.open(filename, FILE_READ); | |
if (!file) { | |
Serial.println("Ошибка открытия файла для чтения"); | |
return false; | |
} | |
size_t read = file.read((uint8_t*)data, size); | |
file.close(); | |
return read == size; | |
} | |
}; | |
// Класс для работы с PSRAM | |
class PSRAMManager { | |
private: | |
void* psramData; | |
size_t dataSize; | |
bool initialized; | |
public: | |
PSRAMManager() : psramData(nullptr), dataSize(0), initialized(false) {} | |
bool init() { | |
if (!psramInit()) { | |
Serial.println("Ошибка инициализации PSRAM"); | |
return false; | |
} | |
// Выделяем память для всех данных | |
dataSize = sizeof(ConfigData) + sizeof(LearningData) + sizeof(RXXLearningData); | |
psramData = ps_malloc(dataSize); | |
if (!psramData) { | |
Serial.println("Ошибка выделения памяти в PSRAM"); | |
return false; | |
} | |
initialized = true; | |
Serial.println("PSRAM инициализирован"); | |
return true; | |
} | |
bool saveData(const void* data, size_t size, size_t offset) { | |
if (!initialized) return false; | |
if (offset + size > dataSize) { | |
Serial.println("Ошибка: превышение размера PSRAM"); | |
return false; | |
} | |
memcpy((uint8_t*)psramData + offset, data, size); | |
return true; | |
} | |
bool loadData(void* data, size_t size, size_t offset) { | |
if (!initialized) return false; | |
if (offset + size > dataSize) { | |
Serial.println("Ошибка: превышение размера PSRAM"); | |
return false; | |
} | |
memcpy(data, (uint8_t*)psramData + offset, size); | |
return true; | |
} | |
size_t getFreeMemory() { | |
return ESP.getFreePsram(); | |
} | |
size_t getTotalMemory() { | |
return ESP.getPsramSize(); | |
} | |
}; | |
// Класс для работы с веб-сервером | |
class WebServerManager { | |
private: | |
WebServer server; | |
PSRAMManager psramManager; | |
public: | |
void init() { | |
// Инициализация WiFi | |
WiFi.mode(WIFI_AP_STA); | |
WiFi.softAP(WEB_SSID, WEB_PASSWORD); | |
// Настройка маршрутов | |
server.on("/", HTTP_GET, [this]() { | |
server.send(200, "text/html", htmlPage); | |
}); | |
server.on("/config", HTTP_GET, [this]() { | |
StaticJsonDocument<1024> doc; | |
ConfigData config; | |
if (psramManager.loadData(&config, sizeof(ConfigData), 0)) { | |
doc["injectionTimeMin"] = config.injectionTimeMin; | |
doc["injectionTimeMax"] = config.injectionTimeMax; | |
// ... добавьте остальные поля конфигурации | |
} | |
String response; | |
serializeJson(doc, response); | |
server.send(200, "application/json", response); | |
}); | |
server.on("/config", HTTP_POST, [this]() { | |
StaticJsonDocument<1024> doc; | |
DeserializationError error = deserializeJson(doc, server.arg("plain")); | |
if (error) { | |
server.send(400, "text/plain", "Ошибка разбора JSON"); | |
return; | |
} | |
ConfigData config; | |
// Обновление конфигурации | |
config.injectionTimeMin = doc["injectionTimeMin"]; | |
config.injectionTimeMax = doc["injectionTimeMax"]; | |
// ... обновите остальные поля конфигурации | |
if (psramManager.saveData(&config, sizeof(ConfigData), 0)) { | |
server.send(200, "text/plain", "Конфигурация сохранена"); | |
} else { | |
server.send(500, "text/plain", "Ошибка сохранения конфигурации"); | |
} | |
}); | |
server.begin(); | |
} | |
void handleClient() { | |
server.handleClient(); | |
} | |
}; | |
// Класс для управления двигателем | |
class EngineManager { | |
private: | |
float currentRPM; | |
float currentThrottle; | |
float currentTemp; | |
float currentLambda; | |
public: | |
void updateSensors(float rpm, float throttle, float temp, float lambda) { | |
currentRPM = rpm; | |
currentThrottle = throttle; | |
currentTemp = temp; | |
currentLambda = lambda; | |
} | |
float calculateInjectionTime() { | |
// Базовая логика расчета времени впрыска | |
float baseTime = map(currentRPM, 0, MAX_RPM, | |
configData.injectionTimeMin, | |
configData.injectionTimeMax); | |
// Коррекция по температуре | |
if (configData.tempCorrectionEnabled) { | |
baseTime *= getTempCorrection(currentTemp); | |
} | |
// Коррекция по лямбде | |
if (configData.lambdaCorrectionEnabled) { | |
baseTime *= getLambdaCorrection(currentLambda); | |
} | |
return baseTime; | |
} | |
float calculateAdvance() { | |
// Базовая логика расчета УОЗ | |
float baseAdvance = map(currentRPM, 0, MAX_RPM, | |
configData.minAdvance, | |
configData.maxAdvance); | |
// Коррекция для холостого хода | |
if (isIdle()) { | |
return getIdleAdvance(); | |
} | |
return baseAdvance; | |
} | |
private: | |
bool isIdle() { | |
return currentRPM >= configData.idleRpmMin && | |
currentRPM <= configData.idleRpmMax && | |
currentThrottle < THROTTLE_IDLE_THRESHOLD; | |
} | |
float getTempCorrection(float temp) { | |
// Логика коррекции по температуре | |
return 1.0; // Заглушка | |
} | |
float getLambdaCorrection(float lambda) { | |
// Логика коррекции по лямбде | |
return 1.0; // Заглушка | |
} | |
float getIdleAdvance() { | |
// Логика расчета УОЗ на холостом ходу | |
return map(currentRPM, configData.idleRpmMin, configData.idleRpmMax, | |
configData.idleAdvanceMin, configData.idleAdvanceMax); | |
} | |
}; | |