Инструменты пользователя

Инструменты сайта


banddecoder_code

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
banddecoder_code [2026/01/16 20:37] eu8tbanddecoder_code [2026/01/23 08:04] (текущий) eu8t
Строка 1: Строка 1:
-IP 192.168.0.240+IP 192.168.0.240 (можно сменить через настройки)
  
-v0.44+v0.81 (примерно) 
 + 
 +{{:clip2net_menu_260117214628.jpeg?800|}} 
 + 
 +{{:clip2net_menu_260117214613.jpeg?800|}}
  
-{{:clip2net_menu_260110231520.jpeg|}} 
  
  
Строка 12: Строка 15:
 #include <Wire.h> #include <Wire.h>
 #include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
 +#include <EEPROM.h>
  
-const float VERSION 0.50; +// ====================================================
-LiquidCrystal_I2C lcd(0x27, 16, 2);+// === CONFIG: все константы устройства в одном месте === 
 +// =====================================================
  
-byte mac[] { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }+// --- EEPROM --- 
-IPAddress ip(192, 168, 0, 240)+const byte EEPROM_MAGIC      0x42
-unsigned int localPort 12060;+const int  EEPROM_ADDR_MAGIC = 0; 
 +const int  EEPROM_ADDR_IP    1  // 1..4
  
-EthernetUDP Udp;+// --- Версия прошивки --- 
 +const float VERSION = 0.81;
  
 +// --- CAT / сеть ---
 const unsigned long CAT_TIMEOUT = 7000; const unsigned long CAT_TIMEOUT = 7000;
 const unsigned long NET_TIMEOUT = 5000; const unsigned long NET_TIMEOUT = 5000;
  
 +// --- Пины энкодера ---
 const int ENC_A   = 8; const int ENC_A   = 8;
 const int ENC_B   = A1; const int ENC_B   = A1;
 const int ENC_BTN = 3; const int ENC_BTN = 3;
  
 +// --- Пины реле ---
 const int RELAYS[] = {4, 5, 6, 7}; const int RELAYS[] = {4, 5, 6, 7};
 const int RELAY_COUNT = 4; const int RELAY_COUNT = 4;
  
-enum Mode { AUTO, MANUAL }+// --- Кнопка --- 
-Mode mode AUTO;+const unsigned long SHORT_PRESS = 100; 
 +const unsigned long LONG_PRESS  = 3000
 +const unsigned long HOLD_TIME   700;
  
-bool manualForced = false; +// --- Редактор IP --- 
-bool autoFallback false;+const unsigned long EDITOR_CLICK_GUARD 200;
  
 +// --- Анимация CAT ---
 +const int CAT_ANIM_STEPS = 5;
 +
 +
 +// =====================================================
 +// === ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ (состояние устройства) ===
 +// =====================================================
 +
 +// --- IP редактор ---
 +bool ipEditMode = false;
 +byte ipEdit[4];
 +int ipOctetIndex = 0;
 +
 +// --- LCD ---
 +LiquidCrystal_I2C lcd(0x27, 16, 2);
 +
 +// --- Ethernet ---
 +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
 +IPAddress ip(192, 168, 0, 240);
 +unsigned int localPort = 12060;
 +IPAddress effectiveIP = ip;
 +EthernetUDP Udp;
 +
 +// --- CAT состояние ---
 unsigned long lastCatTime = 0; unsigned long lastCatTime = 0;
 bool catActive = false; bool catActive = false;
- 
 unsigned long lastPacketTime = 0; unsigned long lastPacketTime = 0;
- 
 long lastFreq = 0; long lastFreq = 0;
-int currentBand -1+bool freqReceived false; 
-int manualBandIndex = 0;+byte catAnimPos = 0
 +int catPacketCounter = 0
 + 
 +byte catDot[8] = { 
 +  0b00000, 
 +  0b00100, 
 +  0b01110, 
 +  0b01110, 
 +  0b01110, 
 +  0b00100, 
 +  0b00000, 
 +  0b00000 
 +}; 
 + 
 +// --- Режимы --- 
 +enum Mode { AUTO, MANUAL }; 
 +Mode mode = AUTO; 
 +bool manualForced = false;
  
 +// --- Диапазоны ---
 struct Band { struct Band {
   const char* name;   const char* name;
Строка 64: Строка 116:
  
 const int BAND_COUNT = sizeof(bands) / sizeof(Band); const int BAND_COUNT = sizeof(bands) / sizeof(Band);
 +
 +// --- Текущее состояние диапазонов ---
 +int currentBand = -1;
 +int manualBandIndex = 0;
 +
 +// --- Энкодер ---
 +int lastA = HIGH;
 +
 +// --- Кнопка ---
 +bool buttonHeld = false;
 +bool pressed = false;
 +unsigned long pressStart = 0;
 +bool ignoreNextEditorClick = false;
 +
 +// --- LCD обновление ---
 +Mode lastMode = AUTO;
 +int lastBandIndex = -1;
 +long lastDisplayedFreq = 0;
 +bool forceDisplayUpdate = false;
  
 int detectBand(long freq) { int detectBand(long freq) {
Строка 90: Строка 161:
   setRelaysByABCD(0);   setRelaysByABCD(0);
 } }
 +
 +void saveIPToEEPROM(IPAddress ipToSave) {
 +  EEPROM.update(EEPROM_ADDR_MAGIC, EEPROM_MAGIC);
 +  for (int i = 0; i < 4; i++)
 +    EEPROM.update(EEPROM_ADDR_IP + i, ipToSave[i]);
 +}
 +
 +bool loadIPFromEEPROM(IPAddress &out) {
 +  if (EEPROM.read(EEPROM_ADDR_MAGIC) != EEPROM_MAGIC) return false;
 +  byte b[4];
 +  for (int i = 0; i < 4; i++)
 +    b[i] = EEPROM.read(EEPROM_ADDR_IP + i);
 +  out = IPAddress(b[0], b[1], b[2], b[3]);
 +  return true;
 +}
 +
 +void enterIpEditMode() {
 +  ipEditMode = true;
 +
 +  for (int i = 0; i < 4; i++)
 +    ipEdit[i] = effectiveIP[i];
 +
 +  ipOctetIndex = 0;
 +  drawIpEditor();
 +  ignoreNextEditorClick = true;
 +}
 +
 +void drawIpEditor() {
 +  lcd.clear();
 +  lcd.setCursor(0,0);
 +  lcd.print("SET IP:");
 +
 +  lcd.setCursor(0,1);
 +
 +  for (int i = 0; i < 4; i++) {
 +
 +    // подчёркивание перед редактируемым октетом
 +    if (i == ipOctetIndex)
 +      lcd.print("_");
 +    else
 +      lcd.print("");   // ← НИЧЕГО НЕ ПЕЧАТАЕМ
 +
 +    // вывод октета с ведущими нулями
 +    int val = ipEdit[i];
 +    if (val < 100) lcd.print("0");
 +    if (val < 10)  lcd.print("0");
 +    lcd.print(val);
 +
 +    if (i < 3) lcd.print(".");
 +  }
 +}
 +
 +
  
 void printFreqCompact(long f) { void printFreqCompact(long f) {
Строка 107: Строка 231:
 } }
  
-Mode lastMode = AUTO+ 
-int lastBandIndex -1; +void runRelayTest() { 
-long lastDisplayedFreq = 0; +  lcd.clear()
-bool forceDisplayUpdate = false;+  lcd.setCursor(0,0); 
 +  lcd.print("TEST RELAYS"); 
 + 
 +  for (int 0; i < BAND_COUNT; i++) { 
 + 
 +    // включаем реле 
 +    setRelaysByBand(i); 
 + 
 +    // выводим комбинацию ABCD 
 +    lcd.setCursor(0,1)
 +    for (int b = 3; b >= 0; b--) 
 +      lcd.print((bands[i].abcdCode >> b) & 1); 
 + 
 +    delay(600); 
 +  } 
 + 
 +  disableAllRelays(); 
 +  delay(300); 
 + 
 +  forceDisplayUpdate = true; 
 +  updateLCDIfNeeded(); 
 +}
  
 void updateLCDIfNeeded() { void updateLCDIfNeeded() {
 +  if (ipEditMode) return;
   bool changed = false;   bool changed = false;
  
Строка 123: Строка 269:
   if (!changed) return;   if (!changed) return;
  
-  lcd.setCursor(0,0); +  updateTopLine(); 
-  lcd.print("IP:"); +  
-  lcd.print(ip); +
   lcd.setCursor(0,1);   lcd.setCursor(0,1);
   lcd.print("                ");   lcd.print("                ");
Строка 138: Строка 282:
     lcd.print(" ");     lcd.print(" ");
     if (catActive) printFreqCompact(lastFreq);     if (catActive) printFreqCompact(lastFreq);
-    else lcd.print("NO CAT        ");+    else lcd.print("NO DATA       ");
  
     lastBandIndex = currentBand;     lastBandIndex = currentBand;
Строка 154: Строка 298:
   lastMode = mode;   lastMode = mode;
 } }
 +
 +void updateTopLine() {
 +  if (ipEditMode) return;
 +  lcd.setCursor(0,0);
 +  lcd.print("                ");  
 +  lcd.setCursor(0,0);
 +
 +  // === AUTO режим ===
 +  if (mode == AUTO) {
 +    lcd.print("CAT ");
 +
 +    if (catActive) {
 +      // 5-позиционная анимация
 +      for (int i = 0; i < 5; i++) {
 +        if (i == catAnimPos)
 +          lcd.write(byte(0));   // кастомная точка
 +        else
 +          lcd.print(".");
 +      }
 +
 +      lcd.print("   ");
 +
 +      // Показ реле
 +      if (currentBand >= 0) {
 +        for (int i = 3; i >= 0; i--)
 +          lcd.print((bands[currentBand].abcdCode >> i) & 1);
 +      } else {
 +        lcd.print("----");
 +      }
 +
 +    } else {
 +      // CAT пропал
 +      lcd.print(".....   ");
 +      if (currentBand >= 0) {
 +        for (int i = 3; i >= 0; i--)
 +          lcd.print((bands[currentBand].abcdCode >> i) & 1);
 +      } else {
 +        lcd.print("----");
 +      }
 +    }
 +
 +    return;
 +  }
 +
 +  // === MANUAL режим ===
 +  lcd.print("CAT ");
 +  if (catActive) lcd.print("OK");
 +  else lcd.print("--");
 +}
 +
 +
  
 void splashScreen() { void splashScreen() {
Строка 161: Строка 356:
   lcd.print(VERSION, 2);   lcd.print(VERSION, 2);
   lcd.setCursor(0,1);   lcd.setCursor(0,1);
-  lcd.print("ABCD Dec");+  lcd.print("ABCD Decoder");
   delay(2000);   delay(2000);
 } }
 +
  
 void readUDP() { void readUDP() {
Строка 174: Строка 370:
   buf[len] = 0;   buf[len] = 0;
  
 +  // Любой пакет = связь жива
   lastPacketTime = millis();   lastPacketTime = millis();
 +  lastCatTime = millis();
 +  catActive = true;
  
-  char* f = strstr(buf"<Freq>"); +  // Если MANUAL был включён автоматически (fallback)а CAT снова появился — возвращаемся в AUTO 
-  if (!freturn;+  if (mode == MANUAL && !manualForced
 +      mode = AUTO; 
 +       
 +   
 +      // Восстанавливаем реле по текущему диапазону 
 +      if (currentBand >= 0) 
 +          setRelaysByBand(currentBand); 
 +   
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded(); 
 +  }
  
-  += 6+   
-  lastFreq atol(f* 10;+  // Двигаем CAT-анимацию каждые 2 пакета   
 +  catPacketCounter++; 
 +  if (catPacketCounter >= 2) {   // ← каждые 2 пакета 
 +      catPacketCounter = 0; 
 +      catAnimPos = (catAnimPos + 1% 5; 
 +      updateTopLine(); 
 +  }
  
-  int b = detectBand(lastFreq); 
-  if (b >= 0) currentBand = b; 
  
-  catActive true+  // Ищем <Freq> 
-  lastCatTime = millis();+  char* f strstr(buf, "<Freq>")
 +  if (f
 +    f += 6;
  
-  if (mode == MANUAL && autoFallback+    lastFreq = atol(f* 10
-    mode = AUTO+    freqReceived true  // ← ВОТ ЭТОТ if ТЕБЕ НУЖЕН
-    autoFallback false; +
-    manualForced = false; +
-    setRelaysByBand(currentBand); +
-  }+
  
-  if (mode == AUTO+    int b detectBand(lastFreq); 
-    setRelaysByBand(currentBand);+    if (b >= 0) 
 +      currentBand = b;
  
 +    // В AUTO обновляем реле
 +    if (mode == AUTO && currentBand >= 0)
 +      setRelaysByBand(currentBand);
 +  }
 +
 +  // Если <Freq> нет — это heartbeat, ничего не трогаем
   updateLCDIfNeeded();   updateLCDIfNeeded();
 } }
  
-// 
-// === КНОПКА С АНТИДРЕБЕЗГОМ И ЗАЩИТОЙ ОТ ЛОЖНЫХ СРАБАТЫВАНИЙ === 
-// 
-void handleButton() { 
-  static bool pressed = false; 
-  static unsigned long pressStart = 0; 
-  static unsigned long lastCheck = 0; 
  
-  const unsigned long SHORT_PRESS = 100; 
-  const unsigned long LONG_PRESS  = 3000; 
  
-  if (millis() - lastCheck < 30) return; +void handleButtonPress() {
-  lastCheck = millis(); +
- +
-  bool btn = !digitalRead(ENC_BTN); +
- +
-  if (btn && !pressed) {+
     pressed = true;     pressed = true;
     pressStart = millis();     pressStart = millis();
-  }+    buttonHeld = false; 
 +}
  
-  if (!btn && pressed) { +void handleButtonHold(unsigned long held{
-    unsigned long pressTime = millis(- pressStart; +
-    pressed = false;+
  
 +    // длинное → вход в редактор
 +    if (!ipEditMode && held >= LONG_PRESS) {
 +        enterIpEditMode();
 +        pressed = false;
 +        buttonHeld = false;
 +        return;
 +    }
 +
 +    // жест удержания
 +    if (!ipEditMode && !buttonHeld && held >= HOLD_TIME) {
 +        buttonHeld = true;
 +    }
 +}
 +
 +void handleIpEditorClick(unsigned long pressTime) {
 +    static unsigned long lastEditorClick = 0;
 +
 +    // игнорируем первый клик после входа в редактор
 +    if (ignoreNextEditorClick) {
 +        ignoreNextEditorClick = false;
 +        return;
 +    }
 +
 +    // длинное → выход без сохранения
     if (pressTime >= LONG_PRESS) {     if (pressTime >= LONG_PRESS) {
-      lcd.clear()+        ipEditMode = false
-      lcd.setCursor(0,0)+        forceDisplayUpdate = true
-      lcd.print("TEST RELAYS");+        updateLCDIfNeeded(); 
 +        return; 
 +    }
  
-      for (int i = 0; i BAND_COUNT; i++) { +    // защита от двойного клика 
-        setRelaysByBand(i); +    if (millis() - lastEditorClick 200return
-        delay(500); +    lastEditorClick = millis();
-      }+
  
-      disableAllRelays(); +    // короткое → следующий октет 
-      delay(500);+    if (pressTime >= 50{ 
 +        ipOctetIndex++;
  
-      lcd.clear(); +        if (ipOctetIndex > 3{ 
-      lcd.setCursor(0,0); +            effectiveIP = IPAddress(ipEdit[0]ipEdit[1]ipEdit[2], ipEdit[3]); 
-      lcd.print("ABCD:"); +            saveIPToEEPROM(effectiveIP);
-      lcd.setCursor(0,1); +
-      for (int i = 0; i < BAND_COUNT; i++) { +
-        for (int b = 3; b >= 0; b--) +
-          lcd.print((bands[i].abcdCode >> b) & 1); +
-        lcd.print(" "); +
-      } +
-      delay(1500);+
  
-      // ВОССТАНАВЛИВАЕМ РЕЛЕ       +            lcd.clear(); 
-      if (mode == MANUAL)  +            lcd.setCursor(0,0); 
-        setRelaysByBand(manualBandIndex);  +            lcd.print("IP SAVED"); 
-      else +            lcd.setCursor(0,1); 
-        setRelaysByBand(currentBand);+            lcd.print(effectiveIP); 
 +            delay(1200);
  
-      forceDisplayUpdate = true; +            ipEditMode = false; 
-      updateLCDIfNeeded(); +            forceDisplayUpdate = true; 
-      return;+            updateLCDIfNeeded(); 
 +            return
 +        } 
 + 
 +        drawIpEditor();
     }     }
 +}
  
-    if (pressTime >= SHORT_PRESS) { +void toggleAutoManual() { 
-      if (mode == AUTO) {+ 
 +    if (mode == AUTO) {
         mode = MANUAL;         mode = MANUAL;
         manualForced = true;         manualForced = true;
-        autoFallback false+         
-        setRelaysByBand(currentBand); + 
-      } else {+        manualBandIndex (currentBand >= 0 ? currentBand : 0)
 +        setRelaysByBand(manualBandIndex); 
 +    } 
 +    else { 
 +        if (!catActive) { 
 +            lcd.clear(); 
 +            lcd.setCursor(0,0); 
 +            lcd.print("NO CAT LINK"); 
 +            lcd.setCursor(0,1); 
 +            lcd.print("AUTO DISABLED"); 
 +            delay(1200); 
 + 
 +            forceDisplayUpdate = true; 
 +            updateLCDIfNeeded(); 
 +            return; 
 +        } 
         mode = AUTO;         mode = AUTO;
         manualForced = false;         manualForced = false;
-        autoFallback = false; +        
-        setRelaysByBand(currentBand); +
-      }+
  
-      forceDisplayUpdate true+        if (currentBand >0) 
-      updateLCDIfNeeded();+            setRelaysByBand(currentBand)
 +        else 
 +            disableAllRelays();
     }     }
-  }+ 
 +    forceDisplayUpdate = true; 
 +    updateLCDIfNeeded();
 } }
 +
 +void handleButtonRelease(unsigned long pressTime) {
 +
 +    // редактор
 +    if (ipEditMode) {
 +        handleIpEditorClick(pressTime);
 +        return;
 +    }
 +
 +    // длинное → вход в редактор
 +    if (pressTime >= LONG_PRESS) {
 +        enterIpEditMode();
 +        return;
 +    }
 +
 +    // короткое → AUTO/MANUAL
 +    if (!buttonHeld && pressTime >= SHORT_PRESS) {
 +        toggleAutoManual();
 +    }
 +
 +    buttonHeld = false;
 +}
 +
 +
 +//
 +// === КНОПКА С АНТИДРЕБЕЗГОМ И ЗАЩИТОЙ ОТ ЛОЖНЫХ СРАБАТЫВАНИЙ ===
 +//
 +void handleButton() {
 +    static unsigned long lastCheck = 0;
 +
 +    if (millis() - lastCheck < 30) return;
 +    lastCheck = millis();
 +
 +    bool btn = !digitalRead(ENC_BTN);
 +
 +    // начало нажатия
 +    if (btn && !pressed) {
 +        handleButtonPress();
 +        return;
 +    }
 +
 +    // удержание
 +    if (btn && pressed) {
 +        unsigned long held = millis() - pressStart;
 +        handleButtonHold(held);
 +        return;
 +    }
 +
 +    // отпускание
 +    if (!btn && pressed) {
 +        pressed = false;
 +        unsigned long pressTime = millis() - pressStart;
 +        handleButtonRelease(pressTime);
 +        return;
 +    }
 +}
 +
 +
  
 // //
Строка 284: Строка 589:
 // //
 void handleEncoder() { void handleEncoder() {
-  if (mode == AUTO) return; +  static unsigned long lastMove 0;
- +
-  static int lastA HIGH;+
  
   int A = digitalRead(ENC_A);   int A = digitalRead(ENC_A);
 +  if (A == lastA) return;
 +
 +  // реагируем только на фронт A == LOW
   if (A != lastA && A == LOW) {   if (A != lastA && A == LOW) {
 +
     bool clockwise = digitalRead(ENC_B);     bool clockwise = digitalRead(ENC_B);
  
-    if (clockwise) +    // === УДЕРЖАНИЕ КНОПКИ ПОВОРОТ === 
-      manualBandIndex (manualBandIndex 1) % BAND_COUNT; +    if (buttonHeld && !ipEditMode{
-    else +
-      manualBandIndex = (manualBandIndex - 1 + BAND_COUNT% BAND_COUNT;+
  
-    setRelaysByBand(manualBandIndex); +      if (clockwise) { 
-    forceDisplayUpdate = true; +        runRelayTest(); 
-    updateLCDIfNeeded();+      } else { 
 +        // резерв 
 +      } 
 + 
 +      buttonHeld = false; 
 +      lastA = A; 
 +      return; 
 +    } 
 + 
 +    // === РЕЖИМ IP-РЕДАКТОРА === 
 +    if (ipEditMode) { 
 + 
 +      if (millis() - lastMove < 80) { 
 +        lastA = A; 
 +        return; 
 +      } 
 +      lastMove = millis(); 
 + 
 +      int val = ipEdit[ipOctetIndex]; 
 +      if (clockwise) val++; 
 +      else val--; 
 + 
 +      if (val < 0) val = 255; 
 +      if (val > 255) val = 0; 
 + 
 +      ipEdit[ipOctetIndex] = val; 
 +      drawIpEditor(); 
 + 
 +      lastA = A; 
 +      return; 
 +    } 
 + 
 +    // === MANUAL режим === 
 +    if (mode == MANUAL) { 
 + 
 +      if (millis() - lastMove < 50) { 
 +        lastA = A; 
 +        return; 
 +      } 
 +      lastMove = millis(); 
 + 
 +      if (clockwise) 
 +        manualBandIndex = (manualBandIndex + 1) % BAND_COUNT; 
 +      else 
 +        manualBandIndex = (manualBandIndex - 1 + BAND_COUNT) % BAND_COUNT; 
 + 
 +      setRelaysByBand(manualBandIndex); 
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded(); 
 +    }
   }   }
 +
   lastA = A;   lastA = A;
 } }
 +
 +
 +
  
  
 void checkCatTimeout() { void checkCatTimeout() {
-  if (mode != AUTO) return; 
  
 +  // 1) Сбрасываем CAT независимо от режима
   if (catActive && millis() - lastCatTime > CAT_TIMEOUT) {   if (catActive && millis() - lastCatTime > CAT_TIMEOUT) {
-    catActive = false+      catActive = false;
-    mode = MANUAL; +
-    autoFallback = true; +
-    manualForced = false; +
-    manualBandIndex = (currentBand >= 0) ? currentBand : 0;+
  
-    disableAllRelays(); +      // ОБНОВЛЯЕМ ПЕРВУЮ СТРОКУ 
-    forceDisplayUpdate = true; +      updateTopLine(); 
-    updateLCDIfNeeded();+  } 
 + 
 +  // 2) Логика fallback только в AUTO 
 +  if (mode == AUTO && !catActive) { 
 +      mode = MANUAL;       
 +      manualForced = false; 
 + 
 +      if (currentBand >= 0) { 
 +          manualBandIndex = currentBand; 
 +      } 
 +      setRelaysByBand(manualBandIndex); 
 + 
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded();
   }   }
 } }
  
-void setup() {+ 
 + 
 + 
 +void setup() {   
 +  //Serial.begin(115200); delay(500); Serial.println("START DECODER");   
 + 
 +  // --- Пины энкодера ---
   pinMode(ENC_A, INPUT_PULLUP);   pinMode(ENC_A, INPUT_PULLUP);
   pinMode(ENC_B, INPUT_PULLUP);   pinMode(ENC_B, INPUT_PULLUP);
   pinMode(ENC_BTN, INPUT_PULLUP);   pinMode(ENC_BTN, INPUT_PULLUP);
  
 +  // --- Пины реле ---
   for (int i = 0; i < RELAY_COUNT; i++) {   for (int i = 0; i < RELAY_COUNT; i++) {
     pinMode(RELAYS[i], OUTPUT);     pinMode(RELAYS[i], OUTPUT);
Строка 332: Строка 706:
  
   disableAllRelays();   disableAllRelays();
 +
 +  // --- LCD ---
   lcd.begin();   lcd.begin();
   lcd.backlight();   lcd.backlight();
 +
 +  // если есть сохранённый — подхватим
 +  effectiveIP = ip; 
 +  loadIPFromEEPROM(effectiveIP); 
 +
 +  // Регистрируем кастомный символ CAT‑точки
 +  lcd.createChar(0, catDot);
 +
 +  // Splash screen
   splashScreen();   splashScreen();
  
-  Ethernet.begin(mac, ip);+  // --- Ethernet --- 
 +  Ethernet.begin(mac, effectiveIP);
   Udp.begin(localPort);   Udp.begin(localPort);
  
 +  // Первичное отображение IP (потом будет перерисовано updateTopLine)
   lcd.clear();   lcd.clear();
   lcd.setCursor(0,0);   lcd.setCursor(0,0);
   lcd.print("IP:");   lcd.print("IP:");
-  lcd.print(ip);+  lcd.print(effectiveIP);
   lcd.setCursor(0,1);   lcd.setCursor(0,1);
   lcd.print("READY");   lcd.print("READY");
  
 +  // --- Начальные значения логики ---
   currentBand = -1;   currentBand = -1;
   catActive = false;   catActive = false;
 +  manualBandIndex = 0;  
 +  lastFreq = 0;  
   lastPacketTime = millis();   lastPacketTime = millis();
 +
   disableAllRelays();   disableAllRelays();
-  forceDisplayUpdate = true;+ 
 +  // Обновляем дисплей по новой логике 
 +  forceDisplayUpdate = true;  
   updateLCDIfNeeded();   updateLCDIfNeeded();
 +
 +  // Инициализация энкодера (важно!)
 +  lastA = digitalRead(ENC_A);
 } }
  
-void loop() {+ 
 +void loop() {   
 +  // === Всегда читаем UDP ===
   readUDP();   readUDP();
 +
 +  // === Обработка энкодера и кнопки ===
   handleEncoder();   handleEncoder();
   handleButton();   handleButton();
 +
 +  // === Проверка таймаута CAT ===
   checkCatTimeout();   checkCatTimeout();
  
 +  // === Периодическое обновление дисплея ===
   static unsigned long lastDisplayUpdate = 0;   static unsigned long lastDisplayUpdate = 0;
-  if (millis() - lastDisplayUpdate > 1000) {+  if (!ipEditMode && millis() - lastDisplayUpdate > 1000) {
     lastDisplayUpdate = millis();     lastDisplayUpdate = millis();
     updateLCDIfNeeded();     updateLCDIfNeeded();
-  } +  }  
- +
-  if (millis() - lastPacketTime > NET_TIMEOUT && mode == AUTO && !catActive) { +
-    static unsigned long lastStatusUpdate = 0; +
-    if (millis() - lastStatusUpdate > 1000) { +
-      lastStatusUpdate = millis(); +
-      lcd.setCursor(0,0); +
-      lcd.print("IP:"); +
-      lcd.print(ip); +
-      lcd.setCursor(0,1); +
-      lcd.print("NO CAT        "); +
-    } +
-  } +
   delay(10);   delay(10);
 } }
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 </code> </code>
banddecoder_code.1768585034.txt.gz · Последнее изменение: eu8t