Categories
Arduino ESP32

COM Antenna Switch

Viele Funkamateure kennen die Herausforderung nur zu gut: Man arbeitet mit mehreren Antennen – etwa für verschiedene Frequenzbänder oder Richtcharakteristiken – und möchte möglichst schnell zwischen ihnen wechseln. Das manuelle Umstecken der Antennenkabel ist jedoch unpraktisch und kann die Anschlüsse belasten. Außerdem möchte schnell umschalten können. – Genau aus dieser alltäglichen Anforderung heraus ist COM Antenna Switch entstanden – meine eigene Lösung, um das Umschalten zwischen Antennen einfach, zuverlässig und komfortabel zu gestalten. Die Anwendung richtet sich besonders an Funkamateure, die ihre Station modernisieren und Prozesse automatisieren möchten, ohne gleich eine komplexe oder teure Steuerhardware anschaffen zu müssen. Die Inspiration stammt von DL1DJH, vielen Dank dafür!

Funktionsweise

Die Kommunikation zwischen PC und Mikrocontroller erfolgt über eine COM‑Schnittstelle, die in der Praxis über USB bereitgestellt wird. Sobald die Anwendung startet, lässt sich der Port auswählen und die Verbindung herstellen. – Ein Arduino oder ESP32 empfängt anschließend serielle Befehle vom PC. Diese Befehle steuern die Relais, die wiederum die Antennenpfade schalten. Dabei gilt ein zentrales Sicherheitsprinzip: Es kann immer nur eine Antenne aktiv sein. Wählt man eine bereits aktive Antenne erneut an, wird diese deaktiviert, sodass bewusst gar keine Antenne geschaltet ist. Zusätzlich besitzt der Mikrocontroller eigene Eingänge, die zur Steuerung genutzt werden können, beispielsweise via Taster. Die Funktionalität bleibt dabei identisch: Umschalten und Deaktivieren.

Hardware

Die Hardware basiert auf bewährten Komponenten, die leicht zu beschaffen und zuverlässig im Betrieb sind. Kernstück ist wahlweise ein Arduino (z.B. Nano) oder ein ESP32. Beide Mikrocontroller eignen sich aufgrund ihrer seriellen Schnittstellen und Anzahl der Ein- und Ausgänge hervorragend für den Betrieb als COM‑Empfänger. Als Schaltelemente kommen Standard‑Relaismodule für Mikrocontroller zum Einsatz – die Anwendung unterstützt derzeit bis zu 7 Relais, die sich direkt an die GPIO‑Pins anschließen lassen. Diese Module sind robust, preiswert und ideal geeignet, um Antennenleitungen zu schalten. Die Verkabelung bleibt bewusst einfach: USB‑Verbindung zum PC, Relais an die Mikrocontroller‑Pins, dazu eine saubere Spannungsversorgung. Fertig ist die Grundinstallation.

Software

Die PC‑Anwendung verwendet ein schlankes layout mit intuitiver Bedienung. Die Benutzeroberfläche zeigt an, welche Antenne aktuell aktiv ist, und erlaubt den Wechsel mit nur einem Klick. Die Software steht kostenlos auf https://pautsch-edv.com/com-antenna-switch/ zur Verfügung. Sie lässt sich ohne Installation starten – ideal für den täglichen Betrieb im Shack.

Code

// v 1.1
const int outSerialNum[7] = {1, 2, 3, 4, 5, 6, 7}; // Antennenummern
const size_t outSerialNum_Size = sizeof(outSerialNum) / sizeof(outSerialNum[0]); // = 7

const int out[7] = {2, 3, 4, 5, 6, 7, 8}; // Esp32
//const int out[7] = {16, 17, 18, 19, 20, 21, 22}; // Ardino Nano
const size_t out_Size = sizeof(out) / sizeof(out[0]); // = 7

const int schalt[7] = {9, 10, 11, 12, 14, 15, 16}; // Esp32
//const int schalt[7] = {23, 24, 25, 26, 27, 28, 29}; // Ardino Nano
const size_t schalt_Size = sizeof(schalt) / sizeof(schalt[0]); // = 7

int outPinStatus[] = {0, 0, 0, 0, 0, 0, 0};
const size_t outPinStatus_Size = sizeof(outPinStatus) / sizeof(outPinStatus[0]); // = 7

void setup()
{
  initPinModes();
  initSerial();
}

void loop()
{
  for (int i=0; i < 10; i++)
  {
    receiveSerial();
    sendSerial();
    handleSwitches();
    delay(500);
  }

  outputPinLayout();
}

void initSerial()
{
  Serial.begin(115200); 
  while(!Serial){} // Waiting for serial connection
  Serial.println();
}

void initPinModes()
{
  for (int i=0; i < schalt_Size; i++)
  {
    pinMode(schalt[i], INPUT_PULLUP);
  }

  for (int i=0; i < schalt_Size; i++)
  {
    pinMode(out[i], OUTPUT);
    digitalWrite(out[i], HIGH); // LOW für umgekehrtes schalten
  }
}

void receiveSerial()
{
  // CHANGE;1=0
  // CHANGE;3=1
  
  if (Serial.available())
  {
    String line = Serial.readStringUntil('\n'); // liest bis '\n' oder Timeout
    line.trim();
    
    int sep = line.indexOf(';');   // trennt command und Daten
    int eq  = line.indexOf('=');   // trennt Key und Value

    if (sep > 0 && eq > sep)
    {
      String keyStr = line.substring(sep + 1, eq);   // "1"
      String valStr = line.substring(eq + 1);        // "0"

      int key = keyStr.toInt();  // = 1
      int val = valStr.toInt();  // = 0

      for(int i=0; i < outSerialNum_Size; i++)
      {
        if (key == outSerialNum[i])
        {
          if (val == 0)
          {
            enableAntenna(i, false);
          }
          else
          {
            enableAntenna(i, true);
          }
        }
      }
    }
    else
    {
      Serial.println("Formatfehler");
    }
  }
}

void handleSwitches()
{
  for(int i=0; i < schalt_Size; i++)
  {
    if (digitalRead(schalt[i]) == 0)
    {
      enableAntenna(i, true);
    }
  }
}

void sendSerial()
{
  // STATUS;1=0;2=0;3=....;

  String sendStr = "STATUS;";

  for (int i=0; i < outPinStatus_Size && i < outSerialNum_Size; i++)
  {
    sendStr += (String)outSerialNum[i] + (String)"=" + (String)outPinStatus[i] + (String)";";
  }

  Serial.println(sendStr);
}

void enableAntenna(int iArrPos, bool enable)
{
  if (iArrPos >= outPinStatus_Size)
  {
    return;
  }

  if (enable == true)
  {
    if (outPinStatus[iArrPos] == 0)
    {
      outPinStatus[iArrPos] = 1;
      digitalWrite(out[iArrPos], LOW); // HIGH für umgekehrtes schalten

      // disable rest
      for (int i=0; i < schalt_Size; i++)
      {
        if (i != iArrPos)
        {
          outPinStatus[i] = 0;
          digitalWrite(out[i], HIGH); // LOW für umgekehrtes schalten
        }
      }
    }
    else
    {
      outPinStatus[iArrPos] = 0;
      digitalWrite(out[iArrPos], HIGH); // LOW für umgekehrtes schalten
    }
  }
  else
  {
    outPinStatus[iArrPos] = 0;
    digitalWrite(out[iArrPos], HIGH); // LOW für umgekehrtes schalten
  }
}

void outputPinLayout()
{
  String sendStr = "";

  // OUTSERIAL;1;2;3;4....;
  sendStr = "OUTSERIAL;";
  for (int i=0; i < outSerialNum_Size; i++)
  {
    sendStr += (String)outSerialNum[i] + (String)";";
  }
  Serial.println(sendStr);

  // OUTDIGITAL;2;3;4;5....;
  sendStr = "OUTDIGITAL;";
  for (int i=0; i < out_Size && i < out_Size; i++)
  {
    sendStr += (String)out[i] + (String)";";
  }
  Serial.println(sendStr);

  // INSCHALT;9;10;11;....;
  sendStr = "INSCHALT;";
  for (int i=0; i < schalt_Size; i++)
  {
    sendStr += (String)schalt[i] + (String)";";
  }
  Serial.println(sendStr);
}