Аппаратная конфигурация VGA Вывод: Красный: GPIO14 Зеленый: GPIO19 Синий: GPIO27 H-Sync: GPIO32 V-Sync: GPIO33 Клавиатура 4x4: text Строки: GPIO16, GPIO17, GPIO18, GPIO19 Столбцы: GPIO21, GPIO22, GPIO23, GPIO25 Расположение клавиш: 1 2 3 A 4 5 6 B 7 8 9 C * 0 # D Датчики DS18B20: Шина 1-Wire: GPIO5 Питание: 3.3V с управлением через MOSFET (опционально) Назначение клавиш Основной режим мониторинга: A: Открыть меню настроек B: Прокрутка вниз C: Прокрутка вверх D: Сброс нумерации датчиков Главное меню: 1: Выбор датчика 2: Установка верхнего порога (TH) 3: Установка нижнего порога (TL) 4: Установка разрешения 5: Установка комбинированного значения (номер косы) *: Возврат в режим мониторинга Режимы ввода: Цифры 0-9: Ввод числовых значений #: Подтверждение ввода *: Отмена операции Особенности работы системы Ввод "номера косы": Комбинированное значение до 65535 Старший байт > верхний порог (TH) Младший байт > нижний порог (TL) Подтверждение в два этапа для предотвращения ошибок Визуализация: Цветовая дифференциация значений Подсветка выбранных опций Индикатор прокрутки Форматированный ввод с разделителями Работа с датчиками: Автоматическое определение датчика 3F Сброс нумерации по нажатию кнопки Поддержка до 60 датчиков Настройки сохраняются в EEPROM датчиков Обратная связь: Отображение текущих значений перед изменением Визуализация промежуточных вычислений Сообщения об ошибках Рекомендации по использованию Для ввода комбинированного значения: Выберите датчик через меню (пункт 1) Выберите "5. Set Combined Threshold" Введите число от 0 до 65535 Подтвердите ввод кнопкой # Проверьте рассчитанные значения порогов Примените изменения кнопкой # или отмените * Для оптимальной работы: Используйте стабилизированный источник питания Добавьте подтягивающий резистор 4.7K на линию 1-Wire Для длинных линий используйте экранированный кабель Особенности интерфейса: Температуры окрашиваются в зависимости от значения Текущий выбранный датчик выделяется в меню Все изменения подтверждаются двухэтапно Система показывает текущие значения перед изменением Данная реализация предоставляет полный контроль над датчиками через клавиатуру с визуализацией на VGA-мониторе, с поддержкой ввода комбинированных значений порогов ("номера косы"). #include #include #include #include #include // VGA const int redPin = 14; const int greenPin = 19; const int bluePin = 27; const int hsyncPin = 32; const int vsyncPin = 33; VGA3Bit videodisplay; // 1-Wire const int oneWirePin = 5; OneWire oneWire(oneWirePin); DallasTemperature sensors(&oneWire); // 4x4 const byte ROWS = 4; const byte COLS = 4; char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; byte rowPins[ROWS] = {16, 17, 18, 19}; byte colPins[COLS] = {21, 22, 23, 25}; Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS); // enum SystemState { MAIN_MONITORING, MENU_SELECTION, SENSOR_SELECT, SET_HIGH_TEMP, SET_LOW_TEMP, SET_RESOLUTION, SET_COMBINED_THRESHOLD, CONFIRM_COMBINED_THRESHOLD }; SystemState currentState = MAIN_MONITORING; // int deviceCount = 0; int device3F = -1; int numberedDevices = 0; int scrollOffset = 0; int selectedSensor = -1; int tempInputValue = 0; byte resolutionInput = 0x7F; unsigned int combinedThreshold = 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; }; SensorInfo sensorList[60]; // 60 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); // sensors.begin(); deviceCount = sensors.getDeviceCount(); if (deviceCount > 60) deviceCount = 60; // for (int i = 0; i < deviceCount; i++) { if (sensors.getAddress(sensorList[i].address, i)) { byte scratchPad[9]; readSensorScratchpad(sensorList[i].address, scratchPad); sensorList[i].number = scratchPad[2]; sensorList[i].alarmHigh = scratchPad[2]; sensorList[i].alarmLow = scratchPad[3]; sensorList[i].config = scratchPad[4]; if (sensorList[i].number > 0 && sensorList[i].number <= deviceCount) { deviceNumbered[i] = true; if (sensorList[i].number > numberedDevices) numberedDevices = sensorList[i].number; } } } // 3F checkFor3FSensor(); // showSplashScreen(); } void loop() { char key = keypad.getKey(); switch(currentState) { case MAIN_MONITORING: handleMainMonitoring(key); break; case MENU_SELECTION: handleMenuSelection(key); break; case SENSOR_SELECT: handleSensorSelect(key); break; case SET_HIGH_TEMP: handleSetHighTemp(key); break; case SET_LOW_TEMP: handleSetLowTemp(key); break; case SET_RESOLUTION: handleSetResolution(key); break; case SET_COMBINED_THRESHOLD: handleSetCombinedThreshold(key); break; case CONFIRM_COMBINED_THRESHOLD: handleConfirmCombinedThreshold(key); break; } // 2 static unsigned long lastUpdate = 0; if (millis() - lastUpdate > 2000) { lastUpdate = millis(); sensors.requestTemperatures(); updateSensorData(); checkFor3FSensor(); } } // ===== ===== void updateSensorData() { for (int i = 0; i < deviceCount; i++) { sensorList[i].temperature = sensors.getTempC(sensorList[i].address); // byte scratchPad[9]; if (readSensorScratchpad(sensorList[i].address, scratchPad)) { sensorList[i].alarmHigh = scratchPad[2]; sensorList[i].alarmLow = scratchPad[3]; sensorList[i].config = scratchPad[4]; } } } // ===== ===== void handleMainMonitoring(char key) { if (key == 'A') { currentState = MENU_SELECTION; showMenuScreen(); return; } showMonitoringScreen(); // if (key == 'B' && millis() - lastScrollTime > scrollDelay) { scrollOffset++; if (scrollOffset > deviceCount - 8) scrollOffset = deviceCount - 8; if (scrollOffset < 0) scrollOffset = 0; lastScrollTime = millis(); } if (key == 'C' && scrollOffset > 0 && millis() - lastScrollTime > scrollDelay) { scrollOffset--; lastScrollTime = millis(); } // if (key == 'D') { resetNumbering(); } } void handleMenuSelection(char key) { switch(key) { case '1': currentState = SENSOR_SELECT; selectedSensor = -1; tempInputValue = 0; showSensorSelectScreen(); break; case '2': if (selectedSensor >= 0) { currentState = SET_HIGH_TEMP; tempInputValue = sensorList[selectedSensor].alarmHigh; showSetHighTempScreen(); } break; case '3': if (selectedSensor >= 0) { currentState = SET_LOW_TEMP; tempInputValue = sensorList[selectedSensor].alarmLow; showSetLowTempScreen(); } break; case '4': if (selectedSensor >= 0) { currentState = SET_RESOLUTION; resolutionInput = sensorList[selectedSensor].config; showSetResolutionScreen(); } break; case '5': if (selectedSensor >= 0) { currentState = SET_COMBINED_THRESHOLD; combinedThreshold = (sensorList[selectedSensor].alarmHigh << 8) | sensorList[selectedSensor].alarmLow; showSetCombinedScreen(); } break; case '*': currentState = MAIN_MONITORING; break; } } void handleSensorSelect(char key) { if (key >= '0' && key <= '9') { tempInputValue = tempInputValue * 10 + (key - '0'); if (tempInputValue > 99) tempInputValue = 0; } if (key == '#') { if (tempInputValue >= 0 && tempInputValue < deviceCount) { selectedSensor = tempInputValue; currentState = MENU_SELECTION; showMenuScreen(); return; } else { tempInputValue = 0; } } if (key == '*') { currentState = MENU_SELECTION; showMenuScreen(); return; } showSensorSelectScreen(); } void handleSetHighTemp(char key) { if (key >= '0' && key <= '9') { tempInputValue = tempInputValue * 10 + (key - '0'); if (tempInputValue > 125) tempInputValue = 125; } if (key == '#') { if (tempInputValue >= -55 && tempInputValue <= 125) { setSensorHighTemp(selectedSensor, tempInputValue); currentState = MENU_SELECTION; showMenuScreen(); return; } } if (key == '*') { currentState = MENU_SELECTION; showMenuScreen(); return; } showSetHighTempScreen(); } void handleSetLowTemp(char key) { if (key >= '0' && key <= '9') { tempInputValue = tempInputValue * 10 + (key - '0'); if (tempInputValue > 125) tempInputValue = 125; } if (key == '#') { if (tempInputValue >= -55 && tempInputValue <= 125) { setSensorLowTemp(selectedSensor, tempInputValue); currentState = MENU_SELECTION; showMenuScreen(); return; } } if (key == '*') { currentState = MENU_SELECTION; showMenuScreen(); return; } showSetLowTempScreen(); } void handleSetResolution(char key) { switch(key) { case '1': resolutionInput = 0x1F; break; // 9-bit case '2': resolutionInput = 0x3F; break; // 10-bit case '3': resolutionInput = 0x5F; break; // 11-bit case '4': resolutionInput = 0x7F; break; // 12-bit } if (key == '#') { setSensorResolution(selectedSensor, resolutionInput); currentState = MENU_SELECTION; showMenuScreen(); return; } if (key == '*') { currentState = MENU_SELECTION; showMenuScreen(); return; } showSetResolutionScreen(); } void handleSetCombinedThreshold(char key) { if (key >= '0' && key <= '9') { if (combinedThreshold < 10000) { combinedThreshold = combinedThreshold * 10 + (key - '0'); } } if (key == '#') { if (combinedThreshold <= 65535) { currentState = CONFIRM_COMBINED_THRESHOLD; showConfirmCombinedScreen(); return; } else { showErrorScreen("Value too big! Max 65535"); delay(2000); showSetCombinedScreen(); } } if (key == '*') { currentState = MENU_SELECTION; showMenuScreen(); return; } showSetCombinedScreen(); } void handleConfirmCombinedThreshold(char key) { switch(key) { case '#': // setSensorCombinedThreshold(selectedSensor, combinedThreshold); currentState = MENU_SELECTION; showMenuScreen(); break; case '*': // currentState = SET_COMBINED_THRESHOLD; showSetCombinedScreen(); break; } } // ===== ===== bool readSensorScratchpad(DeviceAddress addr, byte* scratchpad) { if (oneWire.reset() == 0) return false; oneWire.select(addr); oneWire.write(0xBE); for (int i = 0; i < 9; i++) { scratchpad[i] = oneWire.read(); } return true; } bool writeSensorScratchpad(DeviceAddress addr, byte alarmHigh, byte alarmLow, byte config) { if (oneWire.reset() == 0) return false; oneWire.select(addr); oneWire.write(0x4E); // Write Scratchpad oneWire.write(alarmHigh); oneWire.write(alarmLow); oneWire.write(config); if (oneWire.reset() == 0) return false; oneWire.select(addr); oneWire.write(0x48); // Copy Scratchpad to EEPROM delay(20); return true; } void resetNumbering() { numberedDevices = 0; for (int i = 0; i < deviceCount; i++) { deviceNumbered[i] = false; if (sensors.getAddress(tempDeviceAddress, i)) { writeSensorScratchpad(tempDeviceAddress, 0, 0x46, 0x7F); sensorList[i].number = 0; sensorList[i].alarmHigh = 0; } } } void checkFor3FSensor() { device3F = -1; for (int i = 0; i < deviceCount; i++) { if (sensorList[i].config == 0x3F) { device3F = (sensorList[i].alarmLow << 8) | sensorList[i].alarmHigh; break; } } } void setSensorHighTemp(int index, int temp) { if (index < 0 || index >= deviceCount) return; if (writeSensorScratchpad( sensorList[index].address, (byte)temp, sensorList[index].alarmLow, sensorList[index].config )) { sensorList[index].alarmHigh = (byte)temp; } } void setSensorLowTemp(int index, int temp) { if (index < 0 || index >= deviceCount) return; if (writeSensorScratchpad( sensorList[index].address, sensorList[index].alarmHigh, (byte)temp, sensorList[index].config )) { sensorList[index].alarmLow = (byte)temp; } } void setSensorResolution(int index, byte config) { if (index < 0 || index >= deviceCount) return; if (writeSensorScratchpad( sensorList[index].address, sensorList[index].alarmHigh, sensorList[index].alarmLow, config )) { sensorList[index].config = config; } } void setSensorCombinedThreshold(int index, unsigned int value) { if (index < 0 || index >= deviceCount) return; byte highByte = (value >> 8) & 0xFF; byte lowByte = value & 0xFF; if (writeSensorScratchpad( sensorList[index].address, highByte, lowByte, sensorList[index].config )) { sensorList[index].alarmHigh = highByte; sensorList[index].alarmLow = lowByte; } } // ===== ===== void showSplashScreen() { videodisplay.clear(); videodisplay.setCursor(20, 30); videodisplay.setTextColor(videodisplay.RGB(0, 255, 255)); videodisplay.println("DS18B20 CONTROLLER"); videodisplay.setCursor(40, 50); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print("Sensors: "); videodisplay.println(deviceCount); videodisplay.setCursor(30, 70); videodisplay.setTextColor(videodisplay.RGB(150, 255, 150)); videodisplay.println("Initializing..."); videodisplay.show(); delay(2000); } void showMonitoringScreen() { videodisplay.clear(); // videodisplay.setCursor(1, 1); videodisplay.println("***"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print("Sensors: "); videodisplay.setTextColor(videodisplay.RGB(255, 0, 255)); videodisplay.print(deviceCount); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); 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(0, 255, 255)); videodisplay.print(" MODE: "); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print("MONITORING"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); // int maxVisibleLines = 8; int yStart = 25; for (int i = 0; i < maxVisibleLines; i++) { int sensorIndex = i + scrollOffset; if (sensorIndex >= deviceCount) break; if (sensorList[sensorIndex].temperature != DEVICE_DISCONNECTED_C) { int yPos = yStart + i * 8; // if (sensorList[sensorIndex].temperature < 0) { videodisplay.setTextColor(videodisplay.RGB(0, 150, 255)); // } else if (sensorList[sensorIndex].temperature > 50) { videodisplay.setTextColor(videodisplay.RGB(255, 50, 0)); // } else { videodisplay.setTextColor(videodisplay.RGB(150, 255, 150)); // } char buffer[50]; snprintf(buffer, sizeof(buffer), "#%02d: %3dC TH:%02d TL:%02d CF:%02X", sensorList[sensorIndex].number, (int)sensorList[sensorIndex].temperature, sensorList[sensorIndex].alarmHigh, sensorList[sensorIndex].alarmLow, sensorList[sensorIndex].config); videodisplay.setCursor(1, yPos); videodisplay.print(buffer); } } // videodisplay.setTextColor(videodisplay.RGB(200, 200, 200)); videodisplay.setCursor(1, videodisplay.yres - 15); videodisplay.print("A:Menu B:Down C:Up D:Reset"); // if (deviceCount > maxVisibleLines) { int scrollPos = map(scrollOffset, 0, deviceCount - maxVisibleLines, 0, videodisplay.yres - 40); videodisplay.fillRect(videodisplay.xres - 5, 20, 3, videodisplay.yres - 40, videodisplay.RGB(80, 80, 80)); videodisplay.fillRect(videodisplay.xres - 5, 20 + scrollPos, 3, 10, videodisplay.RGB(0, 200, 255)); } videodisplay.show(); } void showMenuScreen() { videodisplay.clear(); videodisplay.setCursor(30, 10); videodisplay.setTextColor(videodisplay.RGB(0, 255, 255)); videodisplay.println("MAIN MENU"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.setCursor(10, 30); videodisplay.print("1. Select Sensor: "); if (selectedSensor >= 0) { videodisplay.print(selectedSensor); } else { videodisplay.print("N/A"); } videodisplay.setCursor(10, 45); videodisplay.print("2. Set High Temp (TH)"); videodisplay.setCursor(10, 60); videodisplay.print("3. Set Low Temp (TL)"); videodisplay.setCursor(10, 75); videodisplay.print("4. Set Resolution"); videodisplay.setCursor(10, 90); videodisplay.print("5. Set Combined Threshold"); videodisplay.setCursor(10, 105); videodisplay.print("*. Back to Monitoring"); videodisplay.show(); } void showSensorSelectScreen() { videodisplay.clear(); videodisplay.setCursor(30, 10); videodisplay.setTextColor(videodisplay.RGB(0, 255, 255)); videodisplay.println("SELECT SENSOR"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.setCursor(10, 30); videodisplay.print("Enter sensor number (0-"); videodisplay.print(deviceCount - 1); videodisplay.println("):"); videodisplay.setCursor(50, 50); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print(tempInputValue); videodisplay.setTextColor(videodisplay.RGB(150, 255, 150)); videodisplay.setCursor(10, 70); videodisplay.print("Current: "); if (tempInputValue >= 0 && tempInputValue < deviceCount) { videodisplay.print(sensorList[tempInputValue].temperature); videodisplay.print("C"); } videodisplay.setTextColor(videodisplay.RGB(200, 200, 200)); videodisplay.setCursor(10, 90); videodisplay.print("#: Confirm *: Cancel"); videodisplay.show(); } void showSetHighTempScreen() { videodisplay.clear(); videodisplay.setCursor(30, 10); videodisplay.setTextColor(videodisplay.RGB(255, 150, 0)); videodisplay.println("SET HIGH TEMP"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.setCursor(10, 30); videodisplay.print("Sensor: "); videodisplay.println(selectedSensor); videodisplay.setCursor(10, 50); videodisplay.print("Current TH: "); videodisplay.print(sensorList[selectedSensor].alarmHigh); videodisplay.println("C"); videodisplay.setCursor(10, 70); videodisplay.print("Enter value (-55 to 125):"); videodisplay.setCursor(50, 90); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print(tempInputValue); videodisplay.setTextColor(videodisplay.RGB(200, 200, 200)); videodisplay.setCursor(10, 110); videodisplay.print("#: Confirm *: Cancel"); videodisplay.show(); } void showSetLowTempScreen() { videodisplay.clear(); videodisplay.setCursor(30, 10); videodisplay.setTextColor(videodisplay.RGB(0, 150, 255)); videodisplay.println("SET LOW TEMP"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.setCursor(10, 30); videodisplay.print("Sensor: "); videodisplay.println(selectedSensor); videodisplay.setCursor(10, 50); videodisplay.print("Current TL: "); videodisplay.print(sensorList[selectedSensor].alarmLow); videodisplay.println("C"); videodisplay.setCursor(10, 70); videodisplay.print("Enter value (-55 to 125):"); videodisplay.setCursor(50, 90); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print(tempInputValue); videodisplay.setTextColor(videodisplay.RGB(200, 200, 200)); videodisplay.setCursor(10, 110); videodisplay.print("#: Confirm *: Cancel"); videodisplay.show(); } void showSetResolutionScreen() { videodisplay.clear(); videodisplay.setCursor(30, 10); videodisplay.setTextColor(videodisplay.RGB(0, 255, 200)); videodisplay.println("SET RESOLUTION"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.setCursor(10, 30); videodisplay.print("Sensor: "); videodisplay.println(selectedSensor); videodisplay.setCursor(10, 50); videodisplay.print("Current: "); videodisplay.print(getResolutionBits(sensorList[selectedSensor].config)); videodisplay.println(" bits"); // videodisplay.setCursor(30, 70); if (resolutionInput == 0x1F) { videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); } else { videodisplay.setTextColor(videodisplay.RGB(150, 150, 150)); } videodisplay.print("1. 9-bit (0x1F)"); videodisplay.setCursor(30, 85); if (resolutionInput == 0x3F) { videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); } else { videodisplay.setTextColor(videodisplay.RGB(150, 150, 150)); } videodisplay.print("2. 10-bit (0x3F)"); videodisplay.setCursor(30, 100); if (resolutionInput == 0x5F) { videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); } else { videodisplay.setTextColor(videodisplay.RGB(150, 150, 150)); } videodisplay.print("3. 11-bit (0x5F)"); videodisplay.setCursor(30, 115); if (resolutionInput == 0x7F) { videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); } else { videodisplay.setTextColor(videodisplay.RGB(150, 150, 150)); } videodisplay.print("4. 12-bit (0x7F)"); videodisplay.setTextColor(videodisplay.RGB(200, 200, 200)); videodisplay.setCursor(10, 130); videodisplay.print("#: Confirm *: Cancel"); videodisplay.show(); } void showSetCombinedScreen() { videodisplay.clear(); videodisplay.setCursor(20, 10); videodisplay.setTextColor(videodisplay.RGB(0, 200, 255)); videodisplay.println("SET COMBINED THRESHOLD"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.setCursor(10, 30); videodisplay.print("Sensor: "); videodisplay.println(selectedSensor); videodisplay.setCursor(10, 50); videodisplay.print("Enter value (0-65535):"); // char formatted[10]; sprintf(formatted, "%05u", combinedThreshold); videodisplay.setCursor(40, 70); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print(" "); for (int i = 0; i < 5; i++) { videodisplay.print(formatted[i]); if (i == 1) videodisplay.print(" "); // 2 } videodisplay.setTextColor(videodisplay.RGB(100, 255, 100)); videodisplay.setCursor(10, 90); videodisplay.print("MSB:TH="); videodisplay.print((combinedThreshold >> 8) & 0xFF); videodisplay.print(" LSB:TL="); videodisplay.print(combinedThreshold & 0xFF); videodisplay.setCursor(10, 105); videodisplay.setTextColor(videodisplay.RGB(200, 200, 200)); videodisplay.print("#:Confirm *:Cancel"); videodisplay.show(); } void showConfirmCombinedScreen() { videodisplay.clear(); videodisplay.setCursor(25, 10); videodisplay.setTextColor(videodisplay.RGB(0, 255, 150)); videodisplay.println("CONFIRM SETTINGS"); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.setCursor(10, 30); videodisplay.print("Sensor: "); videodisplay.println(selectedSensor); videodisplay.setCursor(10, 50); videodisplay.print("Value: "); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print(combinedThreshold); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.print(" ("); videodisplay.print(combinedThreshold, HEX); videodisplay.println(" hex)"); videodisplay.setCursor(10, 70); videodisplay.print("Upper Threshold (TH): "); videodisplay.setTextColor(videodisplay.RGB(255, 150, 150)); videodisplay.print((combinedThreshold >> 8) & 0xFF); videodisplay.println("C"); videodisplay.setCursor(10, 85); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.print("Lower Threshold (TL): "); videodisplay.setTextColor(videodisplay.RGB(150, 255, 150)); videodisplay.print(combinedThreshold & 0xFF); videodisplay.println("C"); videodisplay.setCursor(10, 105); videodisplay.setTextColor(videodisplay.RGB(255, 255, 0)); videodisplay.print("#: APPLY *: CANCEL"); videodisplay.show(); } void showErrorScreen(const char* message) { videodisplay.clear(); videodisplay.setCursor(40, 30); videodisplay.setTextColor(videodisplay.RGB(255, 0, 0)); videodisplay.println("ERROR!"); videodisplay.setCursor(10, 50); videodisplay.setTextColor(videodisplay.RGB(255, 255, 255)); videodisplay.print(message); videodisplay.show(); } // int getResolutionBits(byte config) { switch (config) { case 0x1F: return 9; case 0x3F: return 10; case 0x5F: return 11; case 0x7F: return 12; default: return 0; } }