banddecoder_code
Это старая версия документа!
IP 192.168.0.240
v0.44
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
const float VERSION = 0.50;
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;
const unsigned long NET_TIMEOUT = 5000;
const int ENC_A = 8;
const int ENC_B = A1;
const int ENC_BTN = 3;
const int RELAYS[] = {4, 5, 6, 7};
const int RELAY_COUNT = 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;
};
Band bands[] = {
{"160M", 1800000, 2000000, 0b00000001},
{"80M", 3500000, 3800000, 0b00000010},
{"40M", 7000000, 7350000, 0b00000011},
{"20M", 14000000, 14350000, 0b00000101},
{"15M", 21000000, 21450000, 0b00000111},
{"10M", 28000000, 29700000, 0b00001001}
};
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 setRelaysByABCD(byte abcdCode) {
for (int i = 0; i < RELAY_COUNT; i++) {
bool state = (abcdCode >> i) & 1;
digitalWrite(RELAYS[i], state ? LOW : HIGH);
}
}
void setRelaysByBand(int bandIndex) {
if (bandIndex >= 0 && bandIndex < BAND_COUNT)
setRelaysByABCD(bands[bandIndex].abcdCode);
else
setRelaysByABCD(0);
}
void disableAllRelays() {
setRelaysByABCD(0);
}
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;
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;
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(" ");
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 v");
lcd.print(VERSION, 2);
lcd.setCursor(0,1);
lcd.print("ABCD Dec");
delay(2000);
}
void readUDP() {
int packetSize = Udp.parsePacket();
if (!packetSize) return;
char buf[200];
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;
setRelaysByBand(currentBand);
}
if (mode == AUTO)
setRelaysByBand(currentBand);
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;
lastCheck = millis();
bool btn = !digitalRead(ENC_BTN);
if (btn && !pressed) {
pressed = true;
pressStart = millis();
}
if (!btn && pressed) {
unsigned long pressTime = millis() - pressStart;
pressed = false;
if (pressTime >= LONG_PRESS) {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("TEST RELAYS");
for (int i = 0; i < BAND_COUNT; i++) {
setRelaysByBand(i);
delay(500);
}
disableAllRelays();
delay(500);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("ABCD:");
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);
// ВОССТАНАВЛИВАЕМ РЕЛЕ
if (mode == MANUAL)
setRelaysByBand(manualBandIndex);
else
setRelaysByBand(currentBand);
forceDisplayUpdate = true;
updateLCDIfNeeded();
return;
}
if (pressTime >= SHORT_PRESS) {
if (mode == AUTO) {
mode = MANUAL;
manualForced = true;
autoFallback = false;
setRelaysByBand(currentBand);
} else {
mode = AUTO;
manualForced = false;
autoFallback = false;
setRelaysByBand(currentBand);
}
forceDisplayUpdate = true;
updateLCDIfNeeded();
}
}
}
//
// === ЭНКОДЕР С ЗАЩИТОЙ ОТ ЛОЖНЫХ СРАБАТЫВАНИЙ ===
//
void handleEncoder() {
if (mode == AUTO) return;
static int lastA = HIGH;
int A = digitalRead(ENC_A);
if (A != lastA && A == LOW) {
bool clockwise = digitalRead(ENC_B);
if (clockwise)
manualBandIndex = (manualBandIndex + 1) % BAND_COUNT;
else
manualBandIndex = (manualBandIndex - 1 + BAND_COUNT) % BAND_COUNT;
setRelaysByBand(manualBandIndex);
forceDisplayUpdate = true;
updateLCDIfNeeded();
}
lastA = A;
}
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;
disableAllRelays();
forceDisplayUpdate = true;
updateLCDIfNeeded();
}
}
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);
digitalWrite(RELAYS[i], LOW);
}
disableAllRelays();
lcd.begin();
lcd.backlight();
splashScreen();
Ethernet.begin(mac, ip);
Udp.begin(localPort);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("IP:");
lcd.print(ip);
lcd.setCursor(0,1);
lcd.print("READY");
currentBand = -1;
catActive = false;
lastPacketTime = millis();
disableAllRelays();
forceDisplayUpdate = true;
updateLCDIfNeeded();
}
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 ");
}
}
delay(10);
}
banddecoder_code.1768585034.txt.gz · Последнее изменение: — eu8t

