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

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


banddecoder_code

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


v0.42

CODE

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

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

LiquidCrystal_I2C lcd(0x27, 16, 2);

// Ethernet
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 240);      // IP декодера
unsigned int localPort = 12060;

// CAT timeout
const unsigned long CAT_TIMEOUT = 7000;

// Энкодер (проверенные пины)
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;

// Причины MANUAL
bool manualForced = false;   // пользователь
bool autoFallback = false;   // потеря CAT

EthernetUDP Udp;

unsigned long lastCatTime = 0;
bool catActive = false;

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);
}

// Формат: 7.165.7
void printFreqCompact(long f) {
  int MHz = f / 1000000;
  int kHz = (f / 1000) % 1000;
  int hundred = (f / 100) % 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);
}

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

void drawScreen() {
  lcd.clear();

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

  lcd.setCursor(0, 1);
  if (mode == AUTO) {
    lcd.print("AUTO:");
    if (currentBand >= 0) lcd.print(bands[currentBand].name);
    else lcd.print("--");
    lcd.print(" ");
    if (catActive) printFreqCompact(lastFreq);
    else lcd.print("NO CAT");
  } else {
    lcd.print("MANUAL:");
    lcd.print(bands[manualBandIndex].name);
  }
}

/* ================= СТАРТ ================= */

void splashScreen() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("EW8ZO ver 0.33");
  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;

  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();

  // 🔁 возврат из auto-fallback
  if (mode == MANUAL && autoFallback) {
    mode = AUTO;
    autoFallback = false;
    manualForced = false;
  }

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

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

void handleButton() {
  static unsigned long pressTime = 0;
  static bool pressed = false;

  if (!digitalRead(ENC_BTN)) {
    if (!pressed) {
      pressed = true;
      pressTime = millis();
    }
  } else {
    if (pressed && millis() - pressTime > 800) {
      if (mode == AUTO) {
        mode = MANUAL;
        manualForced = true;
        autoFallback = false;
        setRelays(-1);
      } else {
        mode = AUTO;
        manualForced = false;
        autoFallback = false;
        setRelays(currentBand);
      }
      drawScreen();
    }
    pressed = false;
  }
}

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

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

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

    drawScreen();
  }
  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);
    drawScreen();
  }
}

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

void setup() {
  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);
  Udp.begin(localPort);

  drawScreen();
}

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

void loop() {
  readUDP();
  handleEncoder();
  handleButton();
  checkCatTimeout();
}
banddecoder_code.1768119237.txt.gz · Последнее изменение: eu8t