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

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


banddecoder_code

Это старая версия документа!


IP 192.168.0.240

v0.44

NEW CODE

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

/* ================= НАСТРОЙКИ ================= */
const float VERSION = 0.46; // Версия изменена
LiquidCrystal_I2C lcd(0x27, 16, 2);

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 240);
unsigned int localPort = 12060;

EthernetUDP Udp;

const unsigned long CAT_TIMEOUT = 7000;   // переключение в MANUAL
const unsigned long NET_TIMEOUT = 5000;   // только надпись WAIT CAT DATA

const int ENC_A   = 10;
const int ENC_B   = 3;
const int ENC_BTN = 2;

// Используем 4 реле (A,B,C,D) + 5-й провод - земля
const int RELAYS[] = {4, 5, 6, 7}; // Реле A,B,C,D
const int RELAY_COUNT = 4; // Теперь точно 4 реле

/* ================= СОСТОЯНИЯ ================= */
enum Mode { AUTO, MANUAL };
Mode mode = AUTO;

bool manualForced = false;
bool autoFallback = false;

unsigned long lastCatTime = 0;
bool catActive = false;

unsigned long lastPacketTime = 0;

long lastFreq = 0;
int currentBand = -1;
int manualBandIndex = 0;

/* ================= ДИАПАЗОНЫ ================= */
struct Band {
  const char* name;
  long from;
  long to;
  byte abcdCode; // Код ABCD для этого диапазона
};

// Коды ABCD согласно вашей схеме:
// 4 реле: A(бит0), B(бит1), C(бит2), D(бит3)
// 160M = 0001 (A=1, B=0, C=0, D=0)
// 80M  = 0010 (A=0, B=1, C=0, D=0)
// 40M  = 0011 (A=1, B=1, C=0, D=0)
// 20M  = 0101 (A=1, B=0, C=1, D=0)
// 15M  = 0111 (A=1, B=1, C=1, D=0)
// 10M  = 1001 (A=1, B=0, C=0, D=1)
Band bands[] = {
  {"160M", 1800000, 2000000, 0b00000001}, // 0001
  {"80M",  3500000, 3800000, 0b00000010}, // 0010
  {"40M",  7000000, 7350000, 0b00000011}, // 0011
  {"20M", 14000000, 14350000, 0b00000101}, // 0101
  {"15M", 21000000, 21450000, 0b00000111}, // 0111
  {"10M", 28000000, 29700000, 0b00001001}  // 1001
};

const int BAND_COUNT = sizeof(bands) / sizeof(Band);

/* ================= СЛУЖЕБНЫЕ ================= */
int detectBand(long freq) {
  for (int i = 0; i < BAND_COUNT; i++) {
    if (freq >= bands[i].from && freq <= bands[i].to)
      return i;
  }
  return -1;
}

// Устанавливаем реле согласно коду ABCD
void setRelaysByABCD(byte abcdCode) {
  Serial.print("Setting ABCD code: 0b");
  for (int i = 3; i >= 0; i--) {
    Serial.print((abcdCode >> i) & 1);
  }
  Serial.print(" (0x");
  if (abcdCode < 0x10) Serial.print("0");
  Serial.print(abcdCode, HEX);
  Serial.println(")");
  
  for (int i = 0; i < RELAY_COUNT; i++) {
    // Проверяем соответствующий бит в коде ABCD
    // i=0 -> бит0 (A), i=1 -> бит1 (B), i=2 -> бит2 (C), i=3 -> бит3 (D)
    bool state = (abcdCode >> i) & 1;
    digitalWrite(RELAYS[i], state ? HIGH : LOW);
    
    Serial.print("  Relay ");
    Serial.print((char)('A' + i));
    Serial.print(" (pin ");
    Serial.print(RELAYS[i]);
    Serial.print("): ");
    Serial.println(state ? "HIGH" : "LOW");
  }
  Serial.println();
}

// Установить реле для конкретного диапазона
void setRelaysByBand(int bandIndex) {
  if (bandIndex >= 0 && bandIndex < BAND_COUNT) {
    Serial.print("Setting band: ");
    Serial.print(bands[bandIndex].name);
    Serial.print(" [");
    Serial.print(bandIndex);
    Serial.println("]");
    setRelaysByABCD(bands[bandIndex].abcdCode);
  } else {
    // Неизвестный диапазон - выключаем все реле
    Serial.println("Unknown band - disabling all relays");
    setRelaysByABCD(0b00000000);
  }
}

// Выключить все реле
void disableAllRelays() {
  Serial.println("Disabling all relays");
  setRelaysByABCD(0b00000000);
}

void printFreqCompact(long f) {
  int MHz = f / 1000000;
  int kHz = (f / 1000) % 1000;
  int hundred = (f / 100) % 10;
  int tens = (f / 10) % 10;

  lcd.print(MHz);
  lcd.print(".");
  if (kHz < 100) lcd.print("0");
  if (kHz < 10)  lcd.print("0");
  lcd.print(kHz);
  lcd.print(".");
  lcd.print(hundred);
  lcd.print(tens);
}

/* ================= ЭКРАН ================= */
Mode lastMode = AUTO;
int lastBandIndex = -1;
long lastDisplayedFreq = 0;
bool forceDisplayUpdate = false;

void updateLCDIfNeeded() {
  bool changed = false;

  if (lastMode != mode) {
    changed = true;
    Serial.print("Mode changed: ");
    Serial.println(mode == AUTO ? "AUTO" : "MANUAL");
  }
  
  if (mode != AUTO && lastBandIndex != manualBandIndex) {
    changed = true;
    Serial.print("Manual band changed to: ");
    Serial.println(manualBandIndex);
  }
  
  if (mode == AUTO && lastBandIndex != currentBand) {
    changed = true;
    Serial.print("Auto band changed to: ");
    Serial.println(currentBand);
  }
  
  if (mode == AUTO && lastDisplayedFreq != lastFreq) {
    changed = true;
  }

  if (forceDisplayUpdate) {
    changed = true;
    forceDisplayUpdate = false;
  }

  if (!changed) return;

  lcd.setCursor(0,0);
  lcd.print("IP:");
  lcd.print(ip);

  lcd.setCursor(0,1);
  lcd.print("                ");
  lcd.setCursor(0,1);

  if (mode == AUTO) {
    lcd.print("[A] ");
    if (currentBand >= 0) {
      lcd.print(bands[currentBand].name);
    } else {
      lcd.print("--");
    }
    
    lcd.print(" ");
    if (catActive) {
      printFreqCompact(lastFreq);
    } else {
      lcd.print("NO CAT");
    }

    lastBandIndex = currentBand;
    lastDisplayedFreq = lastFreq;
  } else {
    lcd.print("[M] ");
    lcd.print(bands[manualBandIndex].name);
    lcd.print(" ABCD:");
    for (int i = 3; i >= 0; i--) {
      lcd.print((bands[manualBandIndex].abcdCode >> i) & 1);
    }
    lastBandIndex = manualBandIndex;
  }

  lastMode = mode;
}

/* ================= СТАРТОВЫЙ ЭКРАН ================= */
void splashScreen() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("EW8ZO ver ");
  lcd.print(VERSION, 2);
  lcd.setCursor(0,1);
  lcd.print("ABCD Decoder");
  delay(1000);
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("ABCD Codes:");
  lcd.setCursor(0,1);
  for (int i = 0; i < min(6, BAND_COUNT); i++) {
    lcd.print((char)('0' + (bands[i].abcdCode & 0x0F)));
  }
  delay(2000);
}

/* ================= UDP ================= */
void readUDP() {
  int packetSize = Udp.parsePacket();
  if (!packetSize) return;

  char buf[400];
  int len = Udp.read(buf, sizeof(buf) - 1);
  if (len <= 0) return;
  buf[len] = 0;

  lastPacketTime = millis();

  char* f = strstr(buf, "<Freq>");
  if (!f) return;

  f += 6;
  lastFreq = atol(f) * 10;
  
  Serial.print("Received freq: ");
  Serial.print(lastFreq);
  Serial.print(" Hz (");

  int b = detectBand(lastFreq);
  Serial.print("Band detection: ");
  Serial.print(b);
  Serial.println(")");

  if (b >= 0) currentBand = b;

  catActive = true;
  lastCatTime = millis();

  if (mode == MANUAL && autoFallback) {
    Serial.println("Auto-fallback to AUTO mode");
    mode = AUTO;
    autoFallback = false;
    manualForced = false;
    setRelaysByBand(currentBand);
  }

  if (mode == AUTO) {
    setRelaysByBand(currentBand);
  }

  updateLCDIfNeeded();
}

/* ================= КНОПКА ================= */
void handleButton() {
  static bool pressed = false;
  static unsigned long lastPress = 0;
  const unsigned long DEBOUNCE_DELAY = 50;

  if (!digitalRead(ENC_BTN)) {
    if (!pressed && (millis() - lastPress > DEBOUNCE_DELAY)) {
      pressed = true;
      lastPress = millis();
      
      Serial.println("Button pressed - toggling mode");
      
      if (mode == AUTO) {
        mode = MANUAL;
        manualForced = true;
        autoFallback = false;
        Serial.println("Switching to MANUAL mode");
        disableAllRelays(); // Выключаем все реле при ручном режиме
      } else {
        mode = AUTO;
        manualForced = false;
        autoFallback = false;
        Serial.println("Switching to AUTO mode");
        setRelaysByBand(currentBand); // Включаем реле для текущего диапазона
      }
      forceDisplayUpdate = true;
      updateLCDIfNeeded();
    }
  } else {
    pressed = false;
  }
}

/* ================= ЭНКОДЕР ================= */
void handleEncoder() {
  static int lastA = HIGH;
  static unsigned long lastTurn = 0;
  const unsigned long TURN_DEBOUNCE = 100;

  if (mode == AUTO) return; // В автоматическом режиме энкодер не активен

  int A = digitalRead(ENC_A);

  if (A != lastA && A == LOW && (millis() - lastTurn > TURN_DEBOUNCE)) {
    lastTurn = millis();
    
    bool clockwise = digitalRead(ENC_B);
    
    if (clockwise) {
      manualBandIndex = (manualBandIndex + 1) % BAND_COUNT;
      Serial.print("Encoder CW -> Band: ");
    } else {
      manualBandIndex = (manualBandIndex - 1 + BAND_COUNT) % BAND_COUNT;
      Serial.print("Encoder CCW -> Band: ");
    }
    Serial.print(manualBandIndex);
    Serial.print(" (");
    Serial.print(bands[manualBandIndex].name);
    Serial.println(")");
    
    // Устанавливаем реле согласно выбранному диапазону в ручном режиме
    setRelaysByBand(manualBandIndex);
    forceDisplayUpdate = true;
    updateLCDIfNeeded();
  }
  lastA = A;
}

/* ================= TIMEOUT ================= */
void checkCatTimeout() {
  if (mode != AUTO) return;

  if (catActive && millis() - lastCatTime > CAT_TIMEOUT) {
    catActive = false;
    mode = MANUAL;
    autoFallback = true;
    manualForced = false;
    manualBandIndex = (currentBand >= 0) ? currentBand : 0;
    
    Serial.println("CAT timeout - switching to MANUAL mode");
    
    disableAllRelays(); // Выключаем все реле при переходе в ручной режим
    forceDisplayUpdate = true;
    updateLCDIfNeeded();
  }
}

// Тестовая функция для проверки всех диапазонов
void testAllBands() {
  Serial.println("\n=== TESTING ALL BANDS ===");
  for (int i = 0; i < BAND_COUNT; i++) {
    Serial.print("Testing ");
    Serial.print(bands[i].name);
    Serial.print(": ABCD=");
    for (int j = 3; j >= 0; j--) {
      Serial.print((bands[i].abcdCode >> j) & 1);
    }
    Serial.println();
    
    setRelaysByBand(i);
    delay(1000);
  }
  
  Serial.println("Test complete - disabling all relays");
  disableAllRelays();
}

/* ================= SETUP ================= */
void setup() {
  Serial.begin(115200);
  Serial.println("\n=== Band Decoder ABCD Setup ===");
  Serial.print("Version: ");
  Serial.println(VERSION, 2);

  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  pinMode(ENC_BTN, INPUT_PULLUP);

  // Инициализируем 4 реле
  for (int i = 0; i < RELAY_COUNT; i++) {
    pinMode(RELAYS[i], OUTPUT);
    digitalWrite(RELAYS[i], LOW); // Гарантируем выключенное состояние
  }

  disableAllRelays(); // Выключаем все реле при старте

  lcd.begin();     
  lcd.backlight();
  splashScreen();

  Ethernet.begin(mac, ip);
  Serial.print("Assigned IP: ");
  Serial.println(Ethernet.localIP());

  Udp.begin(localPort);
  Serial.print("UDP started on port ");
  Serial.println(localPort);

  // Выводим таблицу кодов ABCD при старте
  Serial.println("\n=== BAND CONFIGURATION ===");
  Serial.println("Band    Freq Range      ABCD   Binary   Hex");
  Serial.println("--------------------------------------------");
  for (int i = 0; i < BAND_COUNT; i++) {
    Serial.print(bands[i].name);
    Serial.print("\t");
    Serial.print(bands[i].from);
    Serial.print("-");
    Serial.print(bands[i].to);
    Serial.print("\t");
    
    // Показываем ABCD код
    Serial.print("ABCD=");
    for (int j = 3; j >= 0; j--) {
      Serial.print((bands[i].abcdCode >> j) & 1);
    }
    
    Serial.print("  (0b");
    for (int j = 3; j >= 0; j--) {
      Serial.print((bands[i].abcdCode >> j) & 1);
    }
    Serial.print(")");
    
    Serial.print("  0x");
    if (bands[i].abcdCode < 0x10) Serial.print("0");
    Serial.println(bands[i].abcdCode, HEX);
  }
  
  Serial.println("\n=== PIN CONFIGURATION ===");
  Serial.println("Relay  Pin  Bit");
  Serial.println("----------------");
  for (int i = 0; i < RELAY_COUNT; i++) {
    Serial.print("Relay ");
    Serial.print((char)('A' + i));
    Serial.print(": ");
    Serial.print(RELAYS[i]);
    Serial.print("    ");
    Serial.print(i);
    Serial.print(" (");
    Serial.print("Bit ");
    Serial.print(i);
    Serial.println(")");
  }

  Serial.println("\n=== CONTROL ===");
  Serial.println("- Button: Toggle AUTO/MANUAL");
  Serial.println("- Encoder: Change band in MANUAL mode");
  Serial.println("- CAT Timeout: ");
  Serial.print(CAT_TIMEOUT);
  Serial.println(" ms");
  Serial.println("- Network Timeout: ");
  Serial.print(NET_TIMEOUT);
  Serial.println(" ms");

  // Запускаем тест всех диапазонов
  Serial.println("\n=== STARTUP RELAY TEST ===");
  testAllBands();

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("IP:");
  lcd.print(ip);
  lcd.setCursor(0,1);
  lcd.print("READY");

  Serial.println("\n=== Setup complete ===");
  Serial.println("System READY");
  Serial.println("==============================\n");
}

/* ================= LOOP ================= */
void loop() {
  readUDP();
  handleEncoder();
  handleButton();
  checkCatTimeout();

  // Периодическое обновление дисплея
  static unsigned long lastDisplayUpdate = 0;
  if (millis() - lastDisplayUpdate > 1000) {
    lastDisplayUpdate = millis();
    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 SIGNAL   ");
    }
  }
  
  // Небольшая задержка для стабильности
  delay(10);
}

OLD CODE

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

/* ================= НАСТРОЙКИ ================= */

const float VERSION = 0.44;
LiquidCrystal_I2C lcd(0x27, 16, 2);

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 240);
unsigned int localPort = 12060;

EthernetUDP Udp;

const unsigned long CAT_TIMEOUT = 7000;   // переключение в MANUAL
const unsigned long NET_TIMEOUT = 5000;   // только надпись WAIT CAT DATA

const int ENC_A   = 10;
const int ENC_B   = 3;
const int ENC_BTN = 2;

const int RELAYS[] = {4, 5, 6, 7, 8, 9};
const int RELAY_COUNT = sizeof(RELAYS) / sizeof(int);

/* ================= СОСТОЯНИЯ ================= */

enum Mode { AUTO, MANUAL };
Mode mode = AUTO;

bool manualForced = false;
bool autoFallback = false;

unsigned long lastCatTime = 0;
bool catActive = false;

unsigned long lastPacketTime = 0;

long lastFreq = 0;
int currentBand = -1;
int manualBandIndex = 0;

/* ================= ДИАПАЗОНЫ ================= */

struct Band {
  const char* name;
  long from;
  long to;
};

Band bands[] = {
  {"160M", 1800000, 2000000},
  {"80M",  3500000, 3800000},
  {"40M",  7000000, 7350000},
  {"20M", 14000000, 14350000},
  {"15M", 21000000, 21450000},
  {"10M", 28000000, 29700000}
};

const int BAND_COUNT = sizeof(bands) / sizeof(Band);

/* ================= СЛУЖЕБНЫЕ ================= */

int detectBand(long freq) {
  for (int i = 0; i < BAND_COUNT; i++) {
    if (freq >= bands[i].from && freq <= bands[i].to)
      return i;
  }
  return -1;
}

void setRelays(int bandIndex) {
  for (int i = 0; i < RELAY_COUNT; i++)
    digitalWrite(RELAYS[i], (i == bandIndex) ? HIGH : LOW);

  if (bandIndex < 0)
    for (int i = 0; i < RELAY_COUNT; i++)
      digitalWrite(RELAYS[i], LOW);
}

void printFreqCompact(long f) {
  int MHz = f / 1000000;
  int kHz = (f / 1000) % 1000;
  int hundred = (f / 100) % 10;
  int tens = (f / 10) % 10;

  lcd.print(MHz);
  lcd.print(".");
  if (kHz < 100) lcd.print("0");
  if (kHz < 10)  lcd.print("0");
  lcd.print(kHz);
  lcd.print(".");
  lcd.print(hundred);
  lcd.print(tens);
}

/* ================= ЭКРАН ================= */

Mode lastMode = AUTO;
int lastBandIndex = -1;
long lastDisplayedFreq = 0;

void updateLCDIfNeeded() {
  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 (!changed) return;

  lcd.setCursor(0,0);
  lcd.print("IP:");
  lcd.print(ip);

  lcd.setCursor(0,1);
  lcd.print("                ");
  lcd.setCursor(0,1);

  if (mode == AUTO) {
    lcd.print("[A]");
    if (currentBand >= 0) lcd.print(bands[currentBand].name);
    else lcd.print("--");
    lcd.print(" ");
    if (catActive) printFreqCompact(lastFreq);
    else lcd.print("WAIT CAT DATA");

    lastBandIndex = currentBand;
    lastDisplayedFreq = lastFreq;
  } else {
    lcd.print("MANUAL ");
    lcd.print(bands[manualBandIndex].name);
    lastBandIndex = manualBandIndex;
  }

  lastMode = mode;
}

/* ================= СТАРТОВЫЙ ЭКРАН ================= */

void splashScreen() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("EW8ZO ver ");
  lcd.print(VERSION, 2);
  lcd.setCursor(0,1);
  lcd.print("Band Decoder");
  delay(2000);
}

/* ================= UDP ================= */

void readUDP() {
  int packetSize = Udp.parsePacket();
  if (!packetSize) return;

  char buf[400];
  int len = Udp.read(buf, sizeof(buf) - 1);
  if (len <= 0) return;
  buf[len] = 0;

  lastPacketTime = millis();

  char* f = strstr(buf, "<Freq>");
  if (!f) return;

  f += 6;
  lastFreq = atol(f) * 10;

  int b = detectBand(lastFreq);
  if (b >= 0) currentBand = b;

  catActive = true;
  lastCatTime = millis();

  if (mode == MANUAL && autoFallback) {
    mode = AUTO;
    autoFallback = false;
    manualForced = false;
    setRelays(currentBand);
  }

  if (mode == AUTO) setRelays(currentBand);

  updateLCDIfNeeded();
}

/* ================= КНОПКА ================= */

void handleButton() {
  static bool pressed = false;

  if (!digitalRead(ENC_BTN)) {
    pressed = true;
  } else {
    if (pressed) {
      if (mode == AUTO) {
        mode = MANUAL;
        manualForced = true;
        autoFallback = false;
        setRelays(-1);
      } else {
        mode = AUTO;
        manualForced = false;
        autoFallback = false;
        setRelays(currentBand);
      }
      updateLCDIfNeeded();
    }
    pressed = false;
  }
}

/* ================= ЭНКОДЕР ================= */

void handleEncoder() {
  static int lastA = HIGH;
  int A = digitalRead(ENC_A);

  if (A != lastA && A == LOW && mode != AUTO) {
    if (digitalRead(ENC_B))
      manualBandIndex = (manualBandIndex + 1) % BAND_COUNT;
    else
      manualBandIndex = (manualBandIndex - 1 + BAND_COUNT) % BAND_COUNT;

    updateLCDIfNeeded();
  }
  lastA = A;
}

/* ================= TIMEOUT ================= */

void checkCatTimeout() {
  if (mode != AUTO) return;

  if (catActive && millis() - lastCatTime > CAT_TIMEOUT) {
    catActive = false;
    mode = MANUAL;
    autoFallback = true;
    manualForced = false;
    manualBandIndex = (currentBand >= 0) ? currentBand : 0;
    setRelays(-1);
    updateLCDIfNeeded();
  }
}

/* ================= SETUP ================= */

void setup() {
  Serial.begin(115200);
  Serial.println("=== Setup start ===");

  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  pinMode(ENC_BTN, INPUT_PULLUP);

  for (int i = 0; i < RELAY_COUNT; i++)
    pinMode(RELAYS[i], OUTPUT);

  setRelays(-1);

  lcd.begin();     
  lcd.backlight();
  splashScreen();

  Ethernet.begin(mac, ip);
  Serial.print("Assigned IP: ");
  Serial.println(Ethernet.localIP());

  Udp.begin(localPort);
  Serial.println("UDP started");

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("IP:");
  lcd.print(ip);
  lcd.setCursor(0,1);
  lcd.print("WAIT CAT DATA");

  Serial.println("=== Setup end ===");
}

/* ================= LOOP ================= */

void loop() {
  readUDP();
  handleEncoder();
  handleButton();
  checkCatTimeout();  // переключение в MANUAL при CAT_TIMEOUT

  // только надпись при NET_TIMEOUT
  if (millis() - lastPacketTime > NET_TIMEOUT && mode == AUTO) {
    lcd.setCursor(0,0);
    lcd.print("IP:");
    lcd.print(ip);
    lcd.setCursor(0,1);
    lcd.print("WAIT CAT DATA  ");
  }
}
banddecoder_code.1768297988.txt.gz · Последнее изменение: eu8t