#include #include #include #include #include #include // Pin configuration const int redPin = 14; const int greenPin = 19; const int bluePin = 27; const int hsyncPin = 32; const int vsyncPin = 33; const int oneWirePin = 5; const int resetPin = 21; const int monitorPin = 34; const int modeSwitchPin = 15; // Переключение режимов const int powerPin = 4; // Управление питанием датчиков // Режимы работы enum AppState { NUMERATION_MONITORING, CONFIG_SERVER }; AppState currentState = NUMERATION_MONITORING; bool monitoringMode = false; bool webServerInitialized = false; // Глобальные переменные VGA3Bit videodisplay; OneWire oneWire(oneWirePin); DallasTemperature sensors(&oneWire); WebServer server(80); int deviceCount = 0; int device3F = -1; int numberedDevices = 0; int scrollOffset = 0; unsigned long lastScrollTime = 0; const int scrollDelay = 500; DeviceAddress tempDeviceAddress; bool deviceNumbered[60] = {false}; // Структуры данных struct SensorInfo { DeviceAddress address; float temperature; byte number; byte alarmHigh; byte alarmLow; byte config; }; struct TempSensor { DeviceAddress address; int8_t lowTemp; int8_t highTemp; float currentTemp; byte resolution; }; // Константы const byte RES_9BIT = 0x1F; const byte RES_10BIT = 0x3F; const byte RES_11BIT = 0x5F; const byte RES_12BIT = 0x7F; const char* ssid = "ControllerTHTL#1"; const char* password = "12345678"; TempSensor* sensorList = nullptr; int sensorCountWeb = 0; int selectedSensorIndex = -1; // ===== Вспомогательные функции ===== void printAddress(DeviceAddress addr) { for (uint8_t i = 0; i < 8; i++) { if (addr[i] < 16) Serial.print("0"); Serial.print(addr[i], HEX); } } String addressToString(DeviceAddress addr) { String result = ""; for (uint8_t i = 0; i < 8; i++) { if (addr[i] < 16) result += "0"; result += String(addr[i], HEX); } return result; } void writeNumberToSensor(DeviceAddress addr, byte number) { oneWire.reset(); oneWire.select(addr); oneWire.write(0x4E); oneWire.write(number); oneWire.write(0x46); oneWire.write(0x7F); oneWire.reset(); oneWire.select(addr); oneWire.write(0x48); delay(75); } byte readNumberFromSensor(DeviceAddress addr) { byte scratchpad[9]; oneWire.reset(); oneWire.select(addr); oneWire.write(0xBE); for (int i = 0; i < 9; i++) { scratchpad[i] = oneWire.read(); } return scratchpad[2]; } void readSensorScratchpad(DeviceAddress addr, byte* scratchpad) { oneWire.reset(); oneWire.select(addr); oneWire.write(0xBE); for (int i = 0; i < 9; i++) { scratchpad[i] = oneWire.read(); } } // ===== Функции нумерации ===== void resetNumbering() { numberedDevices = 0; for (int i = 0; i < deviceCount; i++) { deviceNumbered[i] = false; } for (int i = 0; i < deviceCount; i++) { if (sensors.getAddress(tempDeviceAddress, i)) { writeNumberToSensor(tempDeviceAddress, 0); Serial.print("Reset numbering for device "); printAddress(tempDeviceAddress); Serial.println(); } } Serial.println("Numbering reset for all devices!"); } SensorInfo getSensorInfo(int index) { SensorInfo info; if (sensors.getAddress(info.address, index)) { info.temperature = sensors.getTempC(info.address); byte scratchpad[9]; readSensorScratchpad(info.address, scratchpad); info.number = scratchpad[2]; info.alarmHigh = scratchpad[2]; info.alarmLow = scratchpad[3]; info.config = scratchpad[4]; } else { memset(&info, 0, sizeof(info)); } return info; } void checkFor3FSensor() { device3F = -1; for (int i = 0; i < deviceCount; i++) { SensorInfo info = getSensorInfo(i); if (info.config == 0x3F) { char hexStr[5]; sprintf(hexStr, "%02X%02X", info.alarmLow, info.alarmHigh); device3F = (int)strtol(hexStr, NULL, 16); break; } } } // ===== VGA Функции ===== void showMonitoringMode() { videodisplay.clear(); // Заголовок videodisplay.setCursor(1, 1); videodisplay.println("***"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print("All sens: "); videodisplay.setTextColor(videodisplay.RGB(255, 0, 255)); videodisplay.print(deviceCount); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print(" Sens3F:"); if (device3F != -1) { videodisplay.setTextColor(videodisplay.RGB(0, 255, 0)); videodisplay.println(device3F); } else { videodisplay.setTextColor(videodisplay.RGB(255, 0, 0)); videodisplay.println("X"); } videodisplay.setTextColor(videodisplay.RGB(0, 255, 255)); videodisplay.print("SENSOR MONITORING MODE"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); // Прокрутка int maxVisibleLines = (videodisplay.yres - 20) / 7; bool needScroll = deviceCount > maxVisibleLines; if (needScroll && millis() - lastScrollTime > scrollDelay) { scrollOffset++; if (scrollOffset > deviceCount - maxVisibleLines) { scrollOffset = 0; } lastScrollTime = millis(); } // Сбор и сортировка данных SensorInfo sensorInfos[deviceCount]; for (int i = 0; i < deviceCount; i++) { sensorInfos[i] = getSensorInfo(i); } for (int i = 0; i < deviceCount - 1; i++) { for (int j = i + 1; j < deviceCount; j++) { if (sensorInfos[i].alarmHigh > sensorInfos[j].alarmHigh) { SensorInfo temp = sensorInfos[i]; sensorInfos[i] = sensorInfos[j]; sensorInfos[j] = temp; } } } // Отображение int yStart = 25; int lineHeight = 7; for (int i = 0; i < maxVisibleLines; i++) { int sensorIndex = i + scrollOffset; if (sensorIndex >= deviceCount) break; if (sensorInfos[sensorIndex].temperature != DEVICE_DISCONNECTED_C) { int xPos = 1; int yPos = yStart + i * lineHeight; char buffer[60]; snprintf(buffer, sizeof(buffer), "#%02d: %3dC H:%02d L:%02d Cf:%02X", sensorInfos[sensorIndex].number, (int)sensorInfos[sensorIndex].temperature, sensorInfos[sensorIndex].alarmHigh, sensorInfos[sensorIndex].alarmLow, sensorInfos[sensorIndex].config); videodisplay.setCursor(xPos, yPos); videodisplay.print(buffer); } } if (needScroll) { int indicatorX = videodisplay.xres - 10; int indicatorY = videodisplay.yres - 10; videodisplay.setCursor(indicatorX, indicatorY); videodisplay.print(">"); } videodisplay.show(); } void showConfigScreen() { videodisplay.clear(); videodisplay.setCursor(10, 10); videodisplay.setTextColor(videodisplay.RGB(0, 255, 255)); videodisplay.println("CONFIGURATION MODE"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print("AP IP: "); videodisplay.println(WiFi.softAPIP()); videodisplay.setTextColor(videodisplay.RGB(0, 255, 0)); videodisplay.println("Connect to WiFi:"); videodisplay.setTextColor(videodisplay.RGB(255, 100, 255)); videodisplay.println(ssid); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.println("Password: " + String(password)); videodisplay.show(); } // ===== WiFi Функции ===== void powerCycleSensors() { digitalWrite(powerPin, LOW); delay(500); digitalWrite(powerPin, HIGH); delay(100); sensors.begin(); } int getResolutionBits(byte config) { switch (config) { case RES_9BIT: return 9; case RES_10BIT: return 10; case RES_11BIT: return 11; case RES_12BIT: return 12; default: return 12; } } void setSensorResolution(int index, byte res) { if (index < 0 || index >= sensorCountWeb) return; sensors.setResolution(sensorList[index].address, getResolutionBits(res)); oneWire.reset(); oneWire.select(sensorList[index].address); oneWire.write(0x4E); oneWire.write(sensorList[index].highTemp); oneWire.write(sensorList[index].lowTemp); oneWire.write(res); oneWire.write(0x48); delay(20); sensorList[index].resolution = res; } void updateTemperatures() { sensors.requestTemperatures(); for (int i = 0; i < sensorCountWeb; i++) { sensorList[i].currentTemp = sensors.getTempC(sensorList[i].address); } } void discoverSensors() { TempSensor* oldSensorList = sensorList; int oldSensorCount = sensorCountWeb; DeviceAddress addr; int foundCount = 0; oneWire.reset_search(); while (oneWire.search(addr) && foundCount < MAX_DEVICES) { if (sensors.validAddress(addr)) { foundCount++; } } if (foundCount == 0) { if (oldSensorList != nullptr) { delete[] oldSensorList; } sensorCountWeb = 0; sensorList = nullptr; return; } sensorList = new TempSensor[foundCount]; sensorCountWeb = foundCount; oneWire.reset_search(); foundCount = 0; while (oneWire.search(addr) && foundCount < sensorCountWeb) { if (sensors.validAddress(addr)) { memcpy(sensorList[foundCount].address, addr, 8); byte scratchPad[9]; oneWire.reset(); oneWire.select(addr); oneWire.write(0xBE); for (byte i = 0; i < 9; i++) { scratchPad[i] = oneWire.read(); } sensorList[foundCount].lowTemp = (int8_t)scratchPad[2]; sensorList[foundCount].highTemp = (int8_t)scratchPad[3]; sensorList[foundCount].resolution = scratchPad[4]; sensorList[foundCount].currentTemp = -127.0f; foundCount++; } } if (oldSensorList != nullptr) { delete[] oldSensorList; } updateTemperatures(); } // ===== Веб-интерфейс ===== void handleRoot() { String html = ""; html += "Контроллер порогов датчиков"; // ... (весь HTML код из второго скетча) server.send(200, "text/html", html); } void handleSelect() { if (server.hasArg("th")) { String thParam = server.arg("th"); for (int i = 0; i < sensorCountWeb; i++) { String sensorAddr = addressToString(sensorList[i].address); if (thParam == sensorAddr) { selectedSensorIndex = i; break; } } } server.sendHeader("Location", "/", true); server.send(302, "text/plain", ""); } void handleSet() { // ... (аналогично второму скетчу) } void handleStatus() { powerCycleSensors(); discoverSensors(); String status = "Датчиков: " + String(sensorCountWeb) + "\n\n"; updateTemperatures(); for (int i = 0; i < sensorCountWeb; i++) { status += "Датчик TH=" + String(sensorList[i].highTemp) + "C:\n"; status += " Темп: " + String(sensorList[i].currentTemp) + "C\n"; status += " Пороги: " + String(sensorList[i].lowTemp) + "C - " + String(sensorList[i].highTemp) + "C\n"; status += " Разрешение: " + String(getResolutionBits(sensorList[i].resolution)) + " бит\n"; status += " Адрес: " + addressToString(sensorList[i].address) + "\n\n"; } server.send(200, "text/plain; charset=UTF-8", status); } void handleRescan() { discoverSensors(); selectedSensorIndex = -1; server.sendHeader("Location", "/", true); server.send(302, "text/plain", ""); } void handleSetSensorResolution() { // ... (аналогично второму скетчу) } void handleSetHighTemp() { // ... (аналогично второму скетчу) } void initWebServer() { WiFi.softAP(ssid, password); server.on("/", handleRoot); server.on("/set", handleSet); server.on("/select", handleSelect); server.on("/status", handleStatus); server.on("/rescan", handleRescan); server.on("/setsensorresolution", handleSetSensorResolution); server.on("/sethightemp", handleSetHighTemp); server.begin(); discoverSensors(); } // ===== Основные функции ===== void setup() { Serial.begin(115200); // Инициализация VGA videodisplay.setFrameBufferCount(2); Mode myMode = VGAMode::MODE320x240.custom(170, 110); videodisplay.init(myMode, redPin, greenPin, bluePin, hsyncPin, vsyncPin); videodisplay.setFont(Font6x8); // Настройка пинов pinMode(resetPin, INPUT_PULLDOWN); pinMode(monitorPin, INPUT_PULLDOWN); pinMode(modeSwitchPin, INPUT_PULLUP); pinMode(powerPin, OUTPUT); digitalWrite(powerPin, HIGH); // Инициализация датчиков sensors.begin(); deviceCount = sensors.getDeviceCount(); if (deviceCount > 60) deviceCount = 60; // Инициализация нумерации for (int i = 0; i < deviceCount; i++) { if (sensors.getAddress(tempDeviceAddress, i)) { byte num = readNumberFromSensor(tempDeviceAddress); if (num > 0 && num <= deviceCount) { deviceNumbered[i] = true; if (num > numberedDevices) numberedDevices = num; } } } checkFor3FSensor(); // Начальный экран videodisplay.clear(); videodisplay.setCursor(10, 10); videodisplay.println("Starting System..."); videodisplay.show(); } void runNumerationMode() { static unsigned long lastUpdate = 0; // Обработка кнопки мониторинга monitoringMode = (digitalRead(monitorPin) == HIGH); if (monitoringMode) { sensors.requestTemperatures(); checkFor3FSensor(); showMonitoringMode(); } else { if (millis() - lastUpdate >= 1000) { lastUpdate = millis(); // Обработка сброса if (digitalRead(resetPin) == HIGH) { resetNumbering(); while (digitalRead(resetPin) == HIGH) delay(10); } sensors.requestTemperatures(); videodisplay.fillRect(0, 0, videodisplay.xres, videodisplay.yres, videodisplay.RGB(0, 0, 0)); // Прогресс-бар int fillPercent = (deviceCount > 0) ? (numberedDevices * 100 / deviceCount) : 0; int barWidth = map(fillPercent, 0, 100, 0, videodisplay.xres); videodisplay.fillRect(0, 19, barWidth, 30, (fillPercent == 100) ? videodisplay.RGB(0, 255, 0) : videodisplay.RGB(255, 0, 0)); // Текст videodisplay.setCursor(10, 10); videodisplay.print(fillPercent); videodisplay.print("%"); // Нумерация for (int i = 0; i < deviceCount; i++) { if (sensors.getAddress(tempDeviceAddress, i) && !deviceNumbered[i]) { float tempC = sensors.getTempC(tempDeviceAddress); if (tempC > 37.0) { numberedDevices++; deviceNumbered[i] = true; writeNumberToSensor(tempDeviceAddress, numberedDevices); } } } // Инфопанель videodisplay.setCursor(2, videodisplay.yres - 20); videodisplay.print("Found: "); videodisplay.print(deviceCount); videodisplay.print(" sensors"); videodisplay.setCursor(2, videodisplay.yres - 10); videodisplay.print("Numbered: "); videodisplay.print(numberedDevices); videodisplay.print(" sensors"); // Датчик 3F videodisplay.setCursor(videodisplay.xres - 75, 10); videodisplay.print("3F: "); if (device3F != -1) { videodisplay.setTextColor(videodisplay.RGB(0, 255, 0)); videodisplay.print(device3F); } else { videodisplay.setTextColor(videodisplay.RGB(255, 0, 0)); videodisplay.print("X"); } videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.show(); } } } void runConfigMode() { if (!webServerInitialized) { initWebServer(); showConfigScreen(); webServerInitialized = true; } server.handleClient(); static unsigned long lastTempUpdate = 0; if (millis() - lastTempUpdate >= 5000) { lastTempUpdate = millis(); updateTemperatures(); } } void loop() { static AppState prevState = currentState; static unsigned long lastModeSwitch = 0; // Переключение режимов if (digitalRead(modeSwitchPin) == LOW && millis() - lastModeSwitch > 1000) { lastModeSwitch = millis(); if (currentState == NUMERATION_MONITORING) { currentState = CONFIG_SERVER; } else { currentState = NUMERATION_MONITORING; if (webServerInitialized) { server.stop(); WiFi.softAPdisconnect(true); webServerInitialized = false; } } } // Смена экрана при переключении if (prevState != currentState) { videodisplay.clear(); if (currentState == NUMERATION_MONITORING) { videodisplay.setCursor(10, 10); videodisplay.println("Switched to Monitoring"); } else { videodisplay.setCursor(10, 10); videodisplay.println("Switched to Config Mode"); } videodisplay.show(); delay(1000); prevState = currentState; } // Выполнение текущего режима if (currentState == NUMERATION_MONITORING) { runNumerationMode(); } else { runConfigMode(); } }