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

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


banddecoder_code

Различия

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

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

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
banddecoder_code [2026/01/10 16:28] eu8tbanddecoder_code [2026/01/23 08:04] (текущий) eu8t
Строка 1: Строка 1:
-CODE+IP 192.168.0.240 (можно сменить через настройки) 
 + 
 +v0.81 (примерно) 
 + 
 +{{:clip2net_menu_260117214628.jpeg?800|}} 
 + 
 +{{:clip2net_menu_260117214613.jpeg?800|}} 
 + 
  
 <code> <code>
Строка 7: Строка 15:
 #include <Wire.h> #include <Wire.h>
 #include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
 +#include <EEPROM.h>
  
-/================= НАСТРОЙКИ ================= */+/===================================================== 
 +// === CONFIG: все константы устройства в одном месте === 
 +// =====================================================
  
-LiquidCrystal_I2C lcd(0x27, 16, 2);+// --- EEPROM --- 
 +const byte EEPROM_MAGIC      = 0x42; 
 +const int  EEPROM_ADDR_MAGIC = 0; 
 +const int  EEPROM_ADDR_IP    = 1;   // 1..4
  
-// Ethernet +// --- Версия прошивки --- 
-byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +const float VERSION 0.81;
-IPAddress ip(192, 168, 0, 240);      // IP декодера +
-unsigned int localPort 12060;+
  
-// CAT timeout+// --- CAT / сеть ---
 const unsigned long CAT_TIMEOUT = 7000; const unsigned long CAT_TIMEOUT = 7000;
 +const unsigned long NET_TIMEOUT = 5000;
  
-// Энкодер (проверенные пины) +// --- Пины энкодера --- 
-const int ENC_A   10+const int ENC_A   8
-const int ENC_B   3+const int ENC_B   A1
-const int ENC_BTN = 2;+const int ENC_BTN = 3;
  
-// Реле +// --- Пины реле --- 
-const int RELAYS[] = {4, 5, 6, 7, 8, 9}; +const int RELAYS[] = {4, 5, 6, 7}; 
-const int RELAY_COUNT = sizeof(RELAYS) / sizeof(int);+const int RELAY_COUNT = 4;
  
-/================= СОСТОЯНИЯ ================= */+// --- Кнопка --- 
 +const unsigned long SHORT_PRESS 100; 
 +const unsigned long LONG_PRESS  3000; 
 +const unsigned long HOLD_TIME   700;
  
-enum Mode { AUTO, MANUAL }; +// --- Редактор IP --- 
-Mode mode AUTO;+const unsigned long EDITOR_CLICK_GUARD 200;
  
-// Причины MANUAL +// --- Анимация CAT --- 
-bool manualForced false  // пользователь +const int CAT_ANIM_STEPS 5;
-bool autoFallback = false;   // потеря CAT+
  
 +
 +// =====================================================
 +// === ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ (состояние устройства) ===
 +// =====================================================
 +
 +// --- 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; EthernetUDP Udp;
  
 +// --- CAT состояние ---
 unsigned long lastCatTime = 0; unsigned long lastCatTime = 0;
 bool catActive = false; bool catActive = false;
 +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;
   long from;   long from;
   long to;   long to;
 +  byte abcdCode;
 }; };
  
 Band bands[] = { Band bands[] = {
-  {"160M", 1800000, 2000000}, +  {"160M", 1800000, 2000000, 0b00000001}, 
-  {"80M",  3500000, 3800000}, +  {"80M",  3500000, 3800000, 0b00000010}, 
-  {"40M",  7000000, 7350000}, +  {"40M",  7000000, 7350000, 0b00000011}, 
-  {"20M", 14000000, 14350000}, +  {"20M", 14000000, 14350000, 0b00000101}, 
-  {"15M", 21000000, 21450000}, +  {"15M", 21000000, 21450000, 0b00000111}, 
-  {"10M", 28000000, 29700000}+  {"10M", 28000000, 29700000, 0b00001001}
 }; };
  
 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) {
Строка 76: Строка 144:
 } }
  
-void setRelays(int bandIndex) { +void setRelaysByABCD(byte abcdCode) { 
-  for (int i = 0; i < RELAY_COUNT; i++) +  for (int i = 0; i < RELAY_COUNT; i++) 
-    digitalWrite(RELAYS[i], (i == bandIndex) HIGH : LOW);+    bool state = (abcdCode >> i) & 1; 
 +    digitalWrite(RELAYS[i], state ? LOW : HIGH); 
 +  } 
 +}
  
-  if (bandIndex < 0+void setRelaysByBand(int bandIndex) { 
-    for (int i = 0; i RELAY_COUNT; i+++  if (bandIndex >= 0 && bandIndex BAND_COUNT
-      digitalWrite(RELAYS[i], LOW);+    setRelaysByABCD(bands[bandIndex].abcdCode); 
 +  else 
 +    setRelaysByABCD(0);
 } }
  
-// Формат: 7.165.7+void disableAllRelays() { 
 +  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) {
   int MHz = f / 1000000;   int MHz = f / 1000000;
   int kHz = (f / 1000) % 1000;   int kHz = (f / 1000) % 1000;
   int hundred = (f / 100) % 10;   int hundred = (f / 100) % 10;
 +  int tens = (f / 10) % 10;
  
   lcd.print(MHz);   lcd.print(MHz);
Строка 98: Строка 228:
   lcd.print(".");   lcd.print(".");
   lcd.print(hundred);   lcd.print(hundred);
 +  lcd.print(tens);
 } }
  
-/* ================= ЭКРАН ================= */ 
  
-void drawScreen() {+void runRelayTest() {
   lcd.clear();   lcd.clear();
 +  lcd.setCursor(0,0);
 +  lcd.print("TEST RELAYS");
  
-  lcd.setCursor(0, 0); +  for (int i = 0; i < BAND_COUNT; i++) { 
-  lcd.print("IP:"); + 
-  lcd.print(ip);+    // включаем реле 
 +    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() { 
 +  if (ipEditMode) return; 
 +  bool changed = false; 
 + 
 +  if (lastMode != mode) changed = true; 
 +  if (mode != AUTO && lastBandIndex != manualBandIndex) changed = true; 
 +  if (mode == AUTO && lastBandIndex != currentBand) changed = true; 
 +  if (mode == AUTO && lastDisplayedFreq != lastFreq) changed = true; 
 +  if (forceDisplayUpdate) { changed = true; forceDisplayUpdate = false; } 
 + 
 +  if (!changed) return; 
 + 
 +  updateTopLine(); 
 +   
 +  lcd.setCursor(0,1); 
 +  lcd.print("                "); 
 +  lcd.setCursor(0,1);
  
-  lcd.setCursor(0, 1); 
   if (mode == AUTO) {   if (mode == AUTO) {
-    lcd.print("AUTO:");+    lcd.print("[A] ");
     if (currentBand >= 0) lcd.print(bands[currentBand].name);     if (currentBand >= 0) lcd.print(bands[currentBand].name);
     else lcd.print("--");     else lcd.print("--");
 +
     lcd.print(" ");     lcd.print(" ");
     if (catActive) printFreqCompact(lastFreq);     if (catActive) printFreqCompact(lastFreq);
-    else lcd.print("NO CAT");+    else lcd.print("NO DATA       ")
 + 
 +    lastBandIndex = currentBand; 
 +    lastDisplayedFreq = lastFreq;
   } else {   } else {
-    lcd.print("MANUAL:");+    lcd.print("[M] ");
     lcd.print(bands[manualBandIndex].name);     lcd.print(bands[manualBandIndex].name);
 +    lcd.print(" ");
 +    for (int i = 3; i >= 0; i--)
 +      lcd.print((bands[manualBandIndex].abcdCode >> i) & 1);
 +
 +    lastBandIndex = manualBandIndex;
   }   }
 +
 +  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() {
   lcd.clear();   lcd.clear();
-  lcd.setCursor(0, 0); +  lcd.setCursor(0,0); 
-  lcd.print("EW8ZO ver 0.33"); +  lcd.print("EW8ZO v"); 
-  lcd.setCursor(0, 1); +  lcd.print(VERSION, 2); 
-  lcd.print("Band Decoder");+  lcd.setCursor(0,1); 
 +  lcd.print("ABCD Decoder");
   delay(2000);   delay(2000);
 } }
  
-/* ================= UDP ================= */ 
  
 void readUDP() { void readUDP() {
Строка 140: Строка 365:
   if (!packetSize) return;   if (!packetSize) return;
  
-  char buf[400];+  char buf[200];
   int len = Udp.read(buf, sizeof(buf) - 1);   int len = Udp.read(buf, sizeof(buf) - 1);
   if (len <= 0) return;   if (len <= 0) return;
   buf[len] = 0;   buf[len] = 0;
  
-  char* f strstr(buf, "<Freq>"); +  // Любой пакет связь жива 
-  if (!freturn;+  lastPacketTime = millis(); 
 +  lastCatTime = millis()
 +  catActive = true;
  
-  f +6+  // Если MANUAL был включён автоматически (fallback), а CAT снова появился — возвращаемся в AUTO 
-  lastFreq atol(f* 10;+  if (mode == MANUAL && !manualForced) { 
 +      mode = AUTO; 
 +       
 +   
 +      // Восстанавливаем реле по текущему диапазону 
 +      if (currentBand >0) 
 +          setRelaysByBand(currentBand); 
 +   
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded(); 
 +  }
  
-  int b = detectBand(lastFreq)+   
-  if (>= 0currentBand b;+  // Двигаем CAT-анимацию каждые 2 пакета   
 +  catPacketCounter++
 +  if (catPacketCounter >= 2{   // ← каждые 2 пакета 
 +      catPacketCounter 0; 
 +      catAnimPos = (catAnimPos + 1) % 5; 
 +      updateTopLine(); 
 +  }
  
-  catActive = true; 
-  lastCatTime = millis(); 
  
-  // 🔁 возврат из auto-fallback +  // Ищем <Freq> 
-  if (mode == MANUAL && autoFallback{ +  char* f = strstr(buf, "<Freq>"); 
-    mode AUTO+  if (f) { 
-    autoFallback false+    f +6; 
-    manualForced false;+ 
 +    lastFreq atol(f* 10; 
 +    freqReceived true  // ← ВОТ ЭТОТ if ТЕБЕ НУЖЕН 
 + 
 +    int b detectBand(lastFreq)
 +    if (b >0) 
 +      currentBand = b; 
 + 
 +    // В AUTO обновляем реле 
 +    if (mode == AUTO && currentBand >= 0) 
 +      setRelaysByBand(currentBand);
   }   }
  
-  if (mode == AUTO) setRelays(currentBand); +  // Если <Freq> нет — это heartbeat, ничего не трогаем 
-  drawScreen();+  updateLCDIfNeeded();
 } }
  
-/* ================= КНОПКА ================= */ 
  
-void handleButton() { 
-  static unsigned long pressTime = 0; 
-  static bool pressed = false; 
  
-  if (!digitalRead(ENC_BTN)) { +void handleButtonPress() { 
-    if (!pressed) { +    pressed = true; 
-      pressed = true+    pressStart = millis()
-      pressTime millis();+    buttonHeld = false; 
 +
 + 
 +void handleButtonHold(unsigned long held) { 
 + 
 +    // длинное → вход в редактор 
 +    if (!ipEditMode && held >= LONG_PRESS) { 
 +        enterIpEditMode(); 
 +        pressed = false
 +        buttonHeld false; 
 +        return;
     }     }
-  } else { + 
-    if (pressed && millis() - pressTime > 800) { +    // жест удержания 
-      if (mode == AUTO) {+    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) { 
 +        ipEditMode = false; 
 +        forceDisplayUpdate = true; 
 +        updateLCDIfNeeded(); 
 +        return; 
 +    } 
 + 
 +    // защита от двойного клика 
 +    if (millis() - lastEditorClick < 200) return; 
 +    lastEditorClick = millis(); 
 + 
 +    // короткое → следующий октет 
 +    if (pressTime >= 50) { 
 +        ipOctetIndex++; 
 + 
 +        if (ipOctetIndex > 3) { 
 +            effectiveIP = IPAddress(ipEdit[0], ipEdit[1], ipEdit[2], ipEdit[3]); 
 +            saveIPToEEPROM(effectiveIP); 
 + 
 +            lcd.clear(); 
 +            lcd.setCursor(0,0); 
 +            lcd.print("IP SAVED"); 
 +            lcd.setCursor(0,1); 
 +            lcd.print(effectiveIP); 
 +            delay(1200); 
 + 
 +            ipEditMode = false; 
 +            forceDisplayUpdate = true; 
 +            updateLCDIfNeeded(); 
 +            return; 
 +        } 
 + 
 +        drawIpEditor(); 
 +    } 
 +
 + 
 +void toggleAutoManual() { 
 + 
 +    if (mode == AUTO) {
         mode = MANUAL;         mode = MANUAL;
         manualForced = true;         manualForced = true;
-        autoFallback false+         
-        setRelays(-1); + 
-      } 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; +         
-        setRelays(currentBand); + 
-      } +        if (currentBand >= 0) 
-      drawScreen();+            setRelaysByBand(currentBand); 
 +        else 
 +            disableAllRelays();
     }     }
-    pressed false+ 
-  }+    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;
 +    }
 +}
 +
 +
 +
 +//
 +// === ЭНКОДЕР С ЗАЩИТОЙ ОТ ЛОЖНЫХ СРАБАТЫВАНИЙ ===
 +//
 void handleEncoder() { void handleEncoder() {
-  static int lastA HIGH;+  static unsigned long lastMove 0; 
   int A = digitalRead(ENC_A);   int A = digitalRead(ENC_A);
 +  if (A == lastA) return;
  
-  if (A != lastA && A == LOW && mode == MANUAL) { +  // реагируем только на фронт A == LOW 
-    if (digitalRead(ENC_B)) +  if (A != lastA && A == LOW) {
-      manualBandIndex = (manualBandIndex + 1) % BAND_COUNT; +
-    else +
-      manualBandIndex = (manualBandIndex - 1 + BAND_COUNT) % BAND_COUNT;+
  
-    drawScreen();+    bool clockwise = digitalRead(ENC_B); 
 + 
 +    // === УДЕРЖАНИЕ КНОПКИ + ПОВОРОТ === 
 +    if (buttonHeld && !ipEditMode) { 
 + 
 +      if (clockwise) { 
 +        runRelayTest(); 
 +      } 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;
 } }
  
-/* ================= TIMEOUT ================= */+ 
 + 
  
 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; +      updateTopLine(); 
-    manualBandIndex = (currentBand >= 0) currentBand : 0+  } 
-    setRelays(-1); + 
-    drawScreen();+  // 2) Логика fallback только в AUTO 
 +  if (mode == AUTO && !catActive) { 
 +      mode MANUAL      
 +      manualForced = false; 
 + 
 +      if (currentBand >= 0) 
 +          manualBandIndex = currentBand; 
 +      } 
 +      setRelaysByBand(manualBandIndex); 
 + 
 +      forceDisplayUpdate = true; 
 +      updateLCDIfNeeded();
   }   }
 } }
  
-/* ================= SETUP ================= */ 
  
-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);
 +    digitalWrite(RELAYS[i], LOW);
 +  }
  
-  setRelays(-1);+  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);
  
-  drawScreen();+  // Первичное отображение IP (потом будет перерисовано updateTopLine) 
 +  lcd.clear(); 
 +  lcd.setCursor(0,0); 
 +  lcd.print("IP:"); 
 +  lcd.print(effectiveIP); 
 +  lcd.setCursor(0,1); 
 +  lcd.print("READY"); 
 + 
 +  // --- Начальные значения логики --- 
 +  currentBand = -1; 
 +  catActive = false; 
 +  manualBandIndex = 0;   
 +  lastFreq = 0;   
 +  lastPacketTime = millis(); 
 + 
 +  disableAllRelays(); 
 + 
 +  // Обновляем дисплей по новой логике 
 +  forceDisplayUpdate = true;   
 +  updateLCDIfNeeded(); 
 + 
 +  // Инициализация энкодера (важно!) 
 +  lastA = digitalRead(ENC_A);
 } }
  
-/* ================= LOOP ================= */ 
  
-void loop() {+void loop() {   
 +  // === Всегда читаем UDP ===
   readUDP();   readUDP();
 +
 +  // === Обработка энкодера и кнопки ===
   handleEncoder();   handleEncoder();
   handleButton();   handleButton();
 +
 +  // === Проверка таймаута CAT ===
   checkCatTimeout();   checkCatTimeout();
 +
 +  // === Периодическое обновление дисплея ===
 +  static unsigned long lastDisplayUpdate = 0;
 +  if (!ipEditMode && millis() - lastDisplayUpdate > 1000) {
 +    lastDisplayUpdate = millis();
 +    updateLCDIfNeeded();
 +  }  
 +  delay(10);
 } }
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 </code> </code>
banddecoder_code.1768051739.txt.gz · Последнее изменение: eu8t