wokwi sketch.ino

// #define BOARD_WITH_MORE_THAN_200_KB_FLASH

#ifdef BOARD_WITH_MORE_THAN_200_KB_FLASH
#include <iostream>
#endif

#include <string>
#include <map>


namespace N_Wokwi_Upload
{

  namespace N_Settings
  { // ??? in englisch
    // Falls für die Onboard-LED Symbole definiert sind, verwendet man am besten diese:
    // const int Pin_Onboard_LED = PICO_DEFAULT_LED_PIN; // #define PICO_DEFAULT_LED_PIN 25
    // const int Pin_Onboard_LED = 2; // ESP32
    const int Pin_Onboard_LED{ LED_BUILTIN }; // STM32 Nucleo 32: 23, 64: 52, 144: 117

    // Pins für die wokwi-Projekte
    const int32_t Ampel_rot_pin = 2;    // statt #define ROT 2       // pin_red_Light
    const int32_t Ampel_gelb_pin = 4;   // int32_t anstelle von int  // pin_yellow_Light
    const int32_t Ampel_gruen_pin{ 5 };
    const int32_t HC_SR04_trigger_pin = { 12 };
    const int32_t HC_SR04_echo_pin{ 13 };
    const int32_t PushButton_pin{ 14 };
    const int32_t Potentiometer_pin{ 26 };

    const int trafficlight_red_pin = 2;
    const int trafficlight_yellow_pin = 4;
    const int trafficlight_green_pin = 5;

    const int32_t Dauer_Rotphase{ 5000 };      // red_time
    const int32_t Dauer_RotGelbphase{ 1000 };  // redyellow_time
    const int32_t Dauer_Gruenphase{ 5000 };    // green_time
    const int32_t Dauer_Gelbphase{ 1000 };     // yellow_time

    const bool debug_log = true;
    void log(std::string msg)
    {
      msg += " " + std::to_string(millis()) + "ms";
      Serial.println(msg.c_str());
    }

    void Fehlermeldung(std::string msg)
    {
      printf("%s\n", msg.c_str());
      // oder eine Exception auslösen
      // oder einen Errorcode setzen
      // oder einen std::optional-Wert zurückgeben
    };



    // nur für das erste Beispiel mit der Ampelschaltung in C:
#define ROT 2
#define GELB 4
#define GRUEN 5
  }

  namespace N_Fahrbahnampel_in_C // oder "Verkehrsampel"
  { // erste Version, nur C
    // Werte für https://wokwi.com/projects/348849468083274322

    void setup()
    {
      Serial.begin(9600); // öffnet die serielle Schnittstelle mit der Datenrate 9600 bps
      // Danach kann man mit Serial.println Meldungen an die Konsole ausgeben, z.B.
      Serial.println("Version 1: eine_Fahrbahnampel_in_C"); // öffnet die serielle Schnittstelle mit der Datenrate 9600 bps
      pinMode(ROT, OUTPUT); // Konfiguriert den Pin 5 als Ausgang  
      pinMode(GELB, OUTPUT);
      pinMode(GRUEN, OUTPUT);
    }

    void loop()
    {
      digitalWrite(ROT, HIGH); // Bei Pin 5 Spannung anlegen. Da dieser mit der roten LED verbunden ist, leuchtet diese auf
      delay(6000); // Das Programm für 6 Sekunden anhalten - 6 Sekunden rot
      digitalWrite(GELB, HIGH); // gelbe LED an
      delay(1000); // 1 Sekunde gelb, weiterhin rot
      digitalWrite(ROT, LOW);    // Spannung bei Pin5 auf wegnehmen: rote LED aus
      digitalWrite(GELB, LOW);   // gelb aus
      digitalWrite(GRUEN, HIGH); // grün an
      delay(5000); // 5 Sekunden grün
      digitalWrite(GRUEN, LOW); // grün aus
      digitalWrite(GELB, HIGH); // gelb an
      delay(1000);  // 1 Sekunde gelb
      digitalWrite(GELB, LOW); // gelb aus
    }

  } // namespace N_Fahrbahnampel_in_C


  class DigitalOut
  {
    enum class Zustand { angeschaltet, ausgeschaltet };
    const uint32_t pin_;
    Zustand an_aus_;
    const std::string Beschreibung_; // #include <string>
  public:
    // kein Standardkonstruktor, damit nicht vergessen werden kann,
    // einen Pin festzulegen.

    DigitalOut(uint32_t Pin, const std::string& Beschreibung) :
      pin_(Pin), an_aus_(Zustand::ausgeschaltet), Beschreibung_(Beschreibung)
    {// in ??? mit Elementinitialisierern
      pinMode(pin_, OUTPUT); // #define OUTPUT 0x1
    }

    DigitalOut(const DigitalOut&) = delete; // Kopien unterbinden - rule of zero
    DigitalOut operator=(const DigitalOut&) = delete;  // Kopien unterbinden

    void anschalten()
    {
      digitalWrite(pin_, HIGH);
      an_aus_ = Zustand::angeschaltet;
    }

    void ausschalten()
    {
      digitalWrite(pin_, LOW);
      an_aus_ = Zustand::ausgeschaltet;
    }

    std::string to_string() const
    {
      std::string Zustand_string = " an";
      if (an_aus_ == Zustand::ausgeschaltet)
        Zustand_string = " aus";
      return Beschreibung_ + ", Pin=" + std::to_string(pin_) + Zustand_string;
    }

    void anzeigen() const
    { // bei Boards mit genügend Flash-RAM: std::cout << to_string() << std::endl; 
#ifdef BOARD_WITH_MORE_THAN_200_KB_FLASH
      std::cout << to_string() << std::endl; // #include <iostream>
#else
      printf("%s\n", to_string().c_str()); // std::cout << to_string() << std::endl;
#endif // #if BOARD_WITH_MORE_THAN_200_KB_FLASH
    }

    ~DigitalOut() // was soll hier in DigitalIn passieren? ebenso AnalogIn/Out
    { // Bei speziellen Lampen sind hier vielleicht noch andere Aktionen notwendig
      ausschalten(); // ??? ist das notwendig
    }
  }; // class DigitalOut


  namespace N_Fahrbahnampel_mit_Klassen
  {
    class Verkehrsampel // läuft auch unter www.wokwi.com
    {
      DigitalOut rote_Lampe_;
      DigitalOut gelbe_Lampe_;
      DigitalOut gruene_Lampe_;
    public:
      Verkehrsampel(int pin_rote_Lampe, int pin_gelbe_Lampe,
        int pin_gruene_Lampe, std::string Beschreibung) :
        rote_Lampe_(pin_rote_Lampe, Beschreibung + "rote Lampe"),
        gelbe_Lampe_(pin_gelbe_Lampe, Beschreibung + "gelbe Lampe"),
        gruene_Lampe_(pin_gruene_Lampe, Beschreibung + "gruene Lampe")
        // Da DigitalOut keinen Standardkonstruktor hat, müssen Elementinitialisierer 
        // für die Datenelemente angegeben werden, d.h. die Initialisierung kann nicht 
        // vergessen werden.
      {}
      void regeln()
      {
        rote_Lampe_.anschalten();
        delay(6000); // Das Programm für 6 Sekunden anhalten - 6 Sekunden rot
        gelbe_Lampe_.anschalten();
        delay(1000); // 1 Sekunde gelb, weiterhin rot
        rote_Lampe_.ausschalten();
        gelbe_Lampe_.ausschalten();
        gruene_Lampe_.anschalten();
        delay(5000); // 5 Sekunden grün
        gruene_Lampe_.ausschalten();
        gelbe_Lampe_.anschalten();
        delay(1000);  // 1 Sekunde gelb
        gelbe_Lampe_.ausschalten();
      }
    };
    const int pin_rote_Lampe = 2;
    const int pin_gelbe_Lampe = 4;
    const int pin_gruene_Lampe = 5;

    Verkehrsampel Ampel_vor_dem_Rathaus(pin_rote_Lampe, pin_gelbe_Lampe, pin_gruene_Lampe, "Ampel vor dem Rathaus");

    void setup()
    {
      // keine Initialisierung der Verkehrsampel notwendig, da die Lampen in ihrem Konstruktor 
      // initialisiert werden 
    }

    void loop()
    {
      Ampel_vor_dem_Rathaus.regeln();
    }
  } // N_Fahrbahnampel_mit_Klassen


  namespace N_Zeitsteuerung_mit_Zustandsautomat
  {
    enum class AmpelPhasen { Rot, RotGelb, Gelb, Gruen };
    AmpelPhasen AmpelPhase = AmpelPhasen::Rot; // mit Rot anfangen
    int Start_Rotphase = 0;     // =0 unnötig, da global
    int Start_RotGelbphase = 0;
    int Start_Gelbphase = 0;
    int Start_Gruenphase = 0;

    const int pin_rote_Lampe = N_Settings::Ampel_rot_pin;
    const int pin_gelbe_Lampe = N_Settings::Ampel_gelb_pin;
    const int pin_gruene_Lampe = N_Settings::Ampel_gruen_pin;

    const int Dauer_Rotphase = N_Settings::Dauer_Rotphase;
    const int Dauer_RotGelbphase = N_Settings::Dauer_RotGelbphase;
    const int Dauer_Gruenphase = N_Settings::Dauer_Gruenphase;
    const int Dauer_Gelbphase = N_Settings::Dauer_Gelbphase;


    class Verkehrsampel // läuft auch unter www.wokwi.com
    {
      DigitalOut rote_Lampe_;
      DigitalOut gelbe_Lampe_;
      DigitalOut gruene_Lampe_;
    public:
      Verkehrsampel(int pin_rote_Lampe, int pin_gelbe_Lampe,
        int pin_gruene_Lampe, std::string Beschreibung) :
        rote_Lampe_(pin_rote_Lampe, Beschreibung + "rote Lampe"),
        gelbe_Lampe_(pin_gelbe_Lampe, Beschreibung + "gelbe Lampe"),
        gruene_Lampe_(pin_gruene_Lampe, Beschreibung + "gruene Lampe")
        // Da DigitalOut keinen Standardkonstruktor hat, müssen Elementinitialisierer 
        // für die Datenelemente angegeben werden, d.h. die Initialisierung kann nicht 
        // vergessen werden.
      {}
      void regeln()
      {
        rote_Lampe_.anschalten();
        delay(6000); // Das Programm für 6 Sekunden anhalten - 6 Sekunden rot
        gelbe_Lampe_.anschalten();
        delay(1000); // 1 Sekunde gelb, weiterhin rot
        rote_Lampe_.ausschalten();
        gelbe_Lampe_.ausschalten();
        gruene_Lampe_.anschalten();
        delay(5000); // 5 Sekunden grün
        gruene_Lampe_.ausschalten();
        gelbe_Lampe_.anschalten();
        delay(1000);  // 1 Sekunde gelb
        gelbe_Lampe_.ausschalten();
      }

      void regeln_ohne_delay()
      {
        if (AmpelPhase == AmpelPhasen::Rot)
        {
          if (millis() > Start_Rotphase + Dauer_Rotphase)
          { // auf RotGelbphase umschalten
            AmpelPhase = AmpelPhasen::Rot;
            Start_RotGelbphase = millis();
            gelbe_Lampe_.anschalten();  // siehe ???, statt digitalWrite(GELB, HIGH);
          }
        }
        else if (AmpelPhase == AmpelPhasen::RotGelb)
        {
          if (millis() > Start_RotGelbphase + Dauer_RotGelbphase)
          { // auf Gruenphase umschalten
            AmpelPhase = AmpelPhasen::Gruen;
            Start_Gruenphase = millis();
            rote_Lampe_.ausschalten();
            gelbe_Lampe_.ausschalten();
            gruene_Lampe_.anschalten();  // siehe ???, statt digitalWrite(GRUEN, HIGH);
          }
        }
        else if (AmpelPhase == AmpelPhasen::Gruen)
        {
          if (millis() > Start_Gruenphase + Dauer_Gruenphase)
          {
            AmpelPhase = AmpelPhasen::Gelb;
            Start_Gelbphase = millis();
            gruene_Lampe_.ausschalten();  // siehe ???, statt digitalWrite(GRUEN, LOW);
            gelbe_Lampe_.anschalten();    // siehe ???, statt digitalWrite(GELB, HIGH);
          }
        }
        else if (AmpelPhase == AmpelPhasen::Gelb)
        {
          if (millis() > Start_Gelbphase + Dauer_Gelbphase)
          {
            AmpelPhase = AmpelPhasen::Rot;
            gelbe_Lampe_.ausschalten();
            rote_Lampe_.anschalten();  // statt 		digitalWrite(GELB, LOW);
            Start_Rotphase = millis();
          }
        }
        else
        {
          Serial.println("Fehler: Unzulässige Phase in N_warten_ohne_blockierendes_delay");
        }
      };

    };

    Verkehrsampel Ampel_vor_dem_Rathaus(pin_rote_Lampe, pin_gelbe_Lampe, pin_gruene_Lampe, "Ampel vor dem Rathaus");
    void setup()
    {
      // keine Initialisierung der Verkehrsampel notwendig, da die Lampen in ihrem Konstruktor 
      // initialisiert werden 
    }

    void loop()
    {
      Ampel_vor_dem_Rathaus.regeln();
    }

  }



  namespace N_Zeitsteuerung_mit_Zustandsautomat_raus
  {
    enum class AmpelPhasen { Rot, RotGelb, Gelb, Gruen };
    AmpelPhasen AmpelPhase = AmpelPhasen::Rot; // mit Rot anfangen
    int Start_Rotphase = 0;     // =0 unnötig, da global
    int Start_RotGelbphase = 0;
    int Start_Gelbphase = 0;
    int Start_Gruenphase = 0;

    const int pin_rote_Lampe = N_Settings::Ampel_rot_pin;
    const int pin_gelbe_Lampe = N_Settings::Ampel_gelb_pin;
    const int pin_gruene_Lampe = N_Settings::Ampel_gruen_pin;

    const int Dauer_Rotphase = N_Settings::Dauer_Rotphase;
    const int Dauer_RotGelbphase = N_Settings::Dauer_RotGelbphase;
    const int Dauer_Gruenphase = N_Settings::Dauer_Gruenphase;
    const int Dauer_Gelbphase = N_Settings::Dauer_Gelbphase;


    class Verkehrsampel // läuft auch unter www.wokwi.com
    {
      DigitalOut rote_Lampe_;
      DigitalOut gelbe_Lampe_;
      DigitalOut gruene_Lampe_;
    public:
      Verkehrsampel(int pin_rote_Lampe, int pin_gelbe_Lampe,
        int pin_gruene_Lampe, std::string Beschreibung) :
        rote_Lampe_(pin_rote_Lampe, Beschreibung + "rote Lampe"),
        gelbe_Lampe_(pin_gelbe_Lampe, Beschreibung + "gelbe Lampe"),
        gruene_Lampe_(pin_gruene_Lampe, Beschreibung + "gruene Lampe")
        // Da DigitalOut keinen Standardkonstruktor hat, müssen Elementinitialisierer 
        // für die Datenelemente angegeben werden, d.h. die Initialisierung kann nicht 
        // vergessen werden.
      {}
      void regeln()
      {
        rote_Lampe_.anschalten();
        delay(6000); // Das Programm für 6 Sekunden anhalten - 6 Sekunden rot
        gelbe_Lampe_.anschalten();
        delay(1000); // 1 Sekunde gelb, weiterhin rot
        rote_Lampe_.ausschalten();
        gelbe_Lampe_.ausschalten();
        gruene_Lampe_.anschalten();
        delay(5000); // 5 Sekunden grün
        gruene_Lampe_.ausschalten();
        gelbe_Lampe_.anschalten();
        delay(1000);  // 1 Sekunde gelb
        gelbe_Lampe_.ausschalten();
      }

      void regeln_ohne_delay()
      {
        if (AmpelPhase == AmpelPhasen::Rot)
        {
          if (millis() > Start_Rotphase + Dauer_Rotphase)
          { // auf RotGelbphase umschalten
            AmpelPhase = AmpelPhasen::Rot;
            Start_RotGelbphase = millis();
            gelbe_Lampe_.anschalten();  // siehe ???, statt digitalWrite(GELB, HIGH);
          }
        }
        else if (AmpelPhase == AmpelPhasen::RotGelb)
        {
          if (millis() > Start_RotGelbphase + Dauer_RotGelbphase)
          { // auf Gruenphase umschalten
            AmpelPhase = AmpelPhasen::Gruen;
            Start_Gruenphase = millis();
            rote_Lampe_.ausschalten();
            gelbe_Lampe_.ausschalten();
            gruene_Lampe_.anschalten();  // siehe ???, statt digitalWrite(GRUEN, HIGH);
          }
        }
        else if (AmpelPhase == AmpelPhasen::Gruen)
        {
          if (millis() > Start_Gruenphase + Dauer_Gruenphase)
          {
            AmpelPhase = AmpelPhasen::Gelb;
            Start_Gelbphase = millis();
            gruene_Lampe_.ausschalten();  // siehe ???, statt digitalWrite(GRUEN, LOW);
            gelbe_Lampe_.anschalten();    // siehe ???, statt digitalWrite(GELB, HIGH);
          }
        }
        else if (AmpelPhase == AmpelPhasen::Gelb)
        {
          if (millis() > Start_Gelbphase + Dauer_Gelbphase)
          {
            AmpelPhase = AmpelPhasen::Rot;
            gelbe_Lampe_.ausschalten();
            rote_Lampe_.anschalten();  // statt 		digitalWrite(GELB, LOW);
            Start_Rotphase = millis();
          }
        }
        else
        {
          Serial.println("Fehler: Unzulässige Phase in N_warten_ohne_blockierendes_delay");
        }
      };

    };
  }


  namespace N_Zeitsteuerung_mit_Zustandsautomat_und_map
  {
    using N_Zeitsteuerung_mit_Zustandsautomat::AmpelPhasen;

    int Start_Rotphase = 0;     // =0 unnötig, da global
    int Start_RotGelbphase = 0;
    int Start_Gelbphase = 0;
    int Start_Gruenphase = 0;

    const int pin_rote_Lampe = N_Settings::Ampel_rot_pin;
    const int pin_gelbe_Lampe = N_Settings::Ampel_gelb_pin;
    const int pin_gruene_Lampe = N_Settings::Ampel_gruen_pin;

    const int Dauer_Rotphase = N_Settings::Dauer_Rotphase;
    const int Dauer_RotGelbphase = N_Settings::Dauer_RotGelbphase;
    const int Dauer_Gruenphase = N_Settings::Dauer_Gruenphase;
    const int Dauer_Gelbphase = N_Settings::Dauer_Gelbphase;

    std::map<AmpelPhasen, int> Starttime{};
    std::map<AmpelPhasen, int> Dauer{ // const geht nicht
      {AmpelPhasen::Rot,     Dauer_Rotphase},
      {AmpelPhasen::RotGelb, Dauer_RotGelbphase},
      {AmpelPhasen::Gelb,    Dauer_Gelbphase},
      {AmpelPhasen::Gruen,   Dauer_Gruenphase } };
    std::map<AmpelPhasen, AmpelPhasen> Next{ // const geht nicht
      {AmpelPhasen::Rot, AmpelPhasen::RotGelb},
      {AmpelPhasen::RotGelb, AmpelPhasen::Gruen},
      {AmpelPhasen::Gruen, AmpelPhasen::Gelb},
      {AmpelPhasen::Gelb, AmpelPhasen::Rot} };

    namespace N_function
    {
      AmpelPhasen Next(AmpelPhasen p)
      {
        if (p == AmpelPhasen::Rot)
          return AmpelPhasen::RotGelb;
        else if (p == AmpelPhasen::RotGelb)
          return AmpelPhasen::Gruen;
        else if (p == AmpelPhasen::Gruen)
          return AmpelPhasen::Gelb;
        else if (p == AmpelPhasen::Gelb)
          return AmpelPhasen::Rot;
      }
    }

    AmpelPhasen AmpelPhase = AmpelPhasen::Gruen;  // Damit erste Next in loop die Ampelphase auf Rot setzt

    class Verkehrsampel // läuft auch unter www.wokwi.com
    {
      DigitalOut rote_Lampe_;
      DigitalOut gelbe_Lampe_;
      DigitalOut gruene_Lampe_;
    public:
      Verkehrsampel(int pin_rote_Lampe, int pin_gelbe_Lampe,
        int pin_gruene_Lampe, std::string Beschreibung) :
        rote_Lampe_(pin_rote_Lampe, Beschreibung + "rote Lampe"),
        gelbe_Lampe_(pin_gelbe_Lampe, Beschreibung + "gelbe Lampe"),
        gruene_Lampe_(pin_gruene_Lampe, Beschreibung + "gruene Lampe")
        // Da DigitalOut keinen Standardkonstruktor hat, müssen Elementinitialisierer 
        // für die Datenelemente angegeben werden, d.h. die Initialisierung kann nicht 
        // vergessen werden.
      {}

      void regeln()
      {
        if (millis() > Starttime[AmpelPhase] + Dauer[AmpelPhase])
        {
          AmpelPhase = Next[AmpelPhase];
          Starttime[AmpelPhase] = millis();
          if (AmpelPhase == AmpelPhasen::Rot)
          {
            gelbe_Lampe_.anschalten();
          }
          else if (AmpelPhase == AmpelPhasen::RotGelb)
          {
            rote_Lampe_.ausschalten();
            gelbe_Lampe_.ausschalten();
            gruene_Lampe_.anschalten();
          }
          else if (AmpelPhase == AmpelPhasen::Gruen)
          {
            gruene_Lampe_.ausschalten();
            gelbe_Lampe_.anschalten();
          }
          else if (AmpelPhase == AmpelPhasen::Gelb)
          {
            gelbe_Lampe_.ausschalten();
            rote_Lampe_.anschalten();  // statt 		digitalWrite(GELB, LOW);
          }
        }
      }
    };

    Verkehrsampel Ampel_vor_dem_Rathaus(pin_rote_Lampe, pin_gelbe_Lampe, pin_gruene_Lampe, "Ampel vor dem Rathaus");
    void setup()
    {
      // keine Initialisierung der Verkehrsampel notwendig, da die Lampen in ihrem Konstruktor 
      // initialisiert werden 
    }

    void loop()
    {
      Ampel_vor_dem_Rathaus.regeln();
    }
  }


  class DigitalIn
  {
    enum class Zustand { angeschaltet, ausgeschaltet };
    const uint32_t pin_;
    Zustand an_aus_;
    const std::string Beschreibung_; // #include <string>
  public:
    DigitalIn(uint32_t Pin, const std::string& Beschreibung) :
      pin_(Pin), an_aus_(Zustand::ausgeschaltet), Beschreibung_(Beschreibung)
    {
      pinMode(pin_, INPUT);
    }

    DigitalIn(const DigitalIn&) = delete; // Kopien unterbinden - rule of zero
    DigitalIn operator=(const DigitalIn&) = delete;  // Kopien unterbinden

    bool ist_an() const
    {
      if (digitalRead(pin_) == HIGH)
        return true;
      else if (digitalRead(pin_) == LOW)
        return false;
      else
        N_Wokwi_Upload::N_Settings::Fehlermeldung("Unzulaessiger Wert von pin " + std::to_string(pin_) + " gelesen");
    }

    bool ist_aus() const
    {
      return not ist_an();
    }

    std::string to_string() const
    {
      std::string Zustand_string = " an";
      if (ist_aus())
        Zustand_string = " aus";
      return Beschreibung_ + ", Pin=" + std::to_string(pin_) + Zustand_string;
    }

    void anzeigen() const
    { // bei Boards mit genügend Flash-RAM: std::cout << to_string() << std::endl; 
#ifdef BOARD_WITH_MORE_THAN_200_KB_FLASH
      std::cout << to_string() << std::endl; // #include <iostream>
#else
      printf("%s\n", to_string().c_str()); // std::cout << to_string() << std::endl;
#endif // #if BOARD_WITH_MORE_THAN_200_KB_FLASH
    }

    ~DigitalIn()
    {
      // ??? was soll hier in passieren? 
    }
  };

  namespace N_Lichtschranke
  {
    class Lichtschranke
    {
      DigitalIn di;
    public:
      Lichtschranke(uint32_t pin, std::string Beschreibung) :di(pin, Beschreibung) {}
      bool ist_offen() const // ??? Namen
      {
        return di.ist_an();
      }
      bool ist_belegt() const
      {
        return not ist_offen();
      }
    };
  } // namespace N_Lichtschranke




  enum class resolution_in_bits_t { Bits_8, Bits_10, Bits_12 }; // If this type is needed in other classes, define it outside the class

  namespace N_use_function
  {
    const int32_t bit_to_int_resolution(resolution_in_bits_t bit_res)
    {
      int32_t result = 0;
      if (bit_res == resolution_in_bits_t::Bits_8)
        result = 256;
      else if (bit_res == resolution_in_bits_t::Bits_10)
        result = 1024;
      else if (bit_res == resolution_in_bits_t::Bits_12)
        result = 4096;
      return result;
    }
  }

  namespace N_use_map
  {
    uint32_t bit_to_int_resolution(resolution_in_bits_t resolution)
    {
      std::map<resolution_in_bits_t, uint32_t> int_res{
        {resolution_in_bits_t::Bits_8, 256},
        {resolution_in_bits_t::Bits_10, 1024},
        {resolution_in_bits_t::Bits_12, 4096}
      };
      return int_res[resolution];
    }
  } // N_use_map

  class AnalogIn // AD-Wandler
  {
    const uint32_t pin_;
    // Zustand an_aus;
    const std::string Beschreibung; // #include <string>
    const resolution_in_bits_t resolution_in_bits_;// Auflösung von ::analogRead
    const uint32_t resolution_in_ints_;
  public:
    AnalogIn(uint32_t Pin, resolution_in_bits_t bit_resolution, std::string Beschreibung_) :
      pin_{ Pin }, Beschreibung{ Beschreibung_ },
      resolution_in_bits_{ bit_resolution },
      resolution_in_ints_{ N_use_map::bit_to_int_resolution({bit_resolution }) }
      // oder mit der Funktion 
      // resolution_in_ints_{ bit_to_int_resolution({bit_resolution }) }
    {
      // analogReadResolution(10); // ??? Auflösung von ::analogRead
      pinMode(pin_, INPUT); // #define INPUT 0x0
    }

    AnalogIn(const AnalogIn&) = delete; // Kopien unterbinden - rule of zero
    AnalogIn operator=(const AnalogIn&) = delete;  // Kopien unterbinden

    int int_resolution() const
    {
      return resolution_in_ints_;
    }

    resolution_in_bits_t bit_resolution() const
    {
      return resolution_in_bits_;
    }

    uint32_t Read() const
    {
      return analogRead(pin_);
    }

    ~AnalogIn()
    {
      // ??? was soll hier in passieren? ebenso AnalogIn/Out
    }
  };





  enum class Beispiel {
    Fahrbahnampel_in_C, 
    Fahrbahnampel_mit_Klassen,
    Zeitsteuerung_mit_Zustandsautomat, 
    Zeitsteuerung_mit_Zustandsautomat_und_map
  };

   Beispiel  bsp = Beispiel::Fahrbahnampel_in_C;
  // Beispiel  bsp = Beispiel::Fahrbahnampel_mit_Klassen;
  // Beispiel  bsp = Beispiel::Zeitsteuerung_mit_Zustandsautomat;
  // Beispiel  bsp = Beispiel::Zeitsteuerung_mit_Zustandsautomat_und_map;

  void Beispiele_setup()
  {
    if (bsp == Beispiel::Fahrbahnampel_in_C)
      N_Fahrbahnampel_in_C::setup();
    else if (bsp == Beispiel::Fahrbahnampel_mit_Klassen)
      N_Fahrbahnampel_mit_Klassen::setup();
    else if (bsp == Beispiel::Zeitsteuerung_mit_Zustandsautomat)
      N_Zeitsteuerung_mit_Zustandsautomat::setup();
    else if (bsp == Beispiel::Zeitsteuerung_mit_Zustandsautomat_und_map)
      N_Zeitsteuerung_mit_Zustandsautomat::setup();
  }

  void Beispiele_loop()
  {
    if (bsp == Beispiel::Fahrbahnampel_in_C)
      N_Fahrbahnampel_in_C::loop();
    else if (bsp == Beispiel::Fahrbahnampel_mit_Klassen)
      N_Fahrbahnampel_mit_Klassen::loop();
    else if (bsp == Beispiel::Zeitsteuerung_mit_Zustandsautomat)
      N_Zeitsteuerung_mit_Zustandsautomat::loop();
    else if (bsp == Beispiel::Zeitsteuerung_mit_Zustandsautomat_und_map)
      N_Zeitsteuerung_mit_Zustandsautomat::loop();
  }
} // namespace N_Wokwi_Upload




void setup() 
{
  Serial.begin(115200);
  Serial.println("STM32 circuit for Embedded C++ (www.rkaiser.de)");
N_Wokwi_Upload::Beispiele_setup();
}

void loop()
{
N_Wokwi_Upload::Beispiele_loop();
  delay(100);
}