Heim Der Blog Blog Details

Entwurf eines Ampelsteuerungssystems auf FPGA-Basis

September 05 2025
Ampheo

Anfrage

Globaler Lieferant elektronischer Komponenten AMPHEO PTY LTD: Umfangreiches Inventar für One-Stop-Shopping. Einfache Anfragen, schnelle, individuelle Lösungen und Angebote.

SCHNELLE ANFRAGE
ZUR RFQ-LISTE HINZUFÜGEN
Dies ist ein klassisches FPGA-Projekt, das FSM-Design, Debouncing, Clock-Domain-Hygiene, Timing und Hardware-Bring-up berührt. Im Folgenden finden Sie ein komplettes, synthetisierbares SystemVerilog-Design für eine Zweiwegkreuzung mit Fußgängertasten, Nacht-(blinkendem)Modus und Notfallvorsorge.

Dies ist ein klassisches FPGA-Projekt, das FSM-Design, Debouncing, Clock-Domain-Hygiene, Timing und Hardware-Bring-up berührt. Im Folgenden finden Sie ein komplettes, synthetisierbares SystemVerilog-Design für eine Zweiwegkreuzung mit Fußgängertasten, Nacht-(blinkendem)Modus und Notfallvorsorge. Es ist parametriert, einfach auf jedes Board zu portieren und kommt mit einer Testbank, Timing-Notizen und einer Bring-up-Checkliste.

Entwurf eines Ampelsteuerungssystems auf FPGA-Basis

1) Umfang & Funktionen

  • Zwei Richtungen: Nord–Süd (NS) und Ost–West (EW)

  • Phasen: Grün → Gelb → Rot-Zwischenschaltung → (andere Straße) Grün → …

  • Fußgängeranforderungen (zwei Taster): werden während der Grünphase der querenden Straße bedient, mit garantierter GEH-Zeit

  • Nachtmodus: blinkendes Gelb auf NS und blinkendes Rot auf EW

  • Vorrangschaltung für Einsatzfahrzeuge (zwei Eingänge): sofortige Räumung auf Rot, dann Grün für die anfordernde Richtung

  • Parametrisierte Dauerwerte und Taktfrequenz

  • Sauberer 1-Hz-„Sekundentakt“, robuste Tasterentprellung

  • One-Hot-FSM, synchrone Resets, kein #delay (voll synthesefähig)


2) Zeitplan (Standardwerte)

  • GRÜN_MIN_SEK_NS = 15, GRÜN_MIN_SEK_EW = 12

  • GELB_SEK = 3, ALLE_ROT_SEK = 1

  • GEH_SEK = 10

  • VORRANG_ROT_SEK = 2 (alle Rot vor Freigabe der Vorrangrichtung)


3) Zustandsdiagramm (Konzept)

 

NS_GRÜN -> NS_GELB -> ALLE_ROT_1 -> EW_GRÜN -> EW_GELB -> ALLE_ROT_2 -> (zurück zu NS_GRÜN)

Notfall_NS: beliebiger_Zustand -> VORRANG_ROT_NS -> NS_GRÜN
Notfall_EW: beliebiger_Zustand -> VORRANG_ROT_EW -> EW_GRÜN

Nachtmodus: Ausgangsüberschreibung (FSM-Fortschritt angehalten)

Fußgängerüberquerung der NS-Fahrbahn ist während EW_GRÜN erlaubt (und umgekehrt). GEH-Signal wird für die ersten GEH_SEK Sekunden der betreffenden Grünphase gegeben, wenn ein Taster gedrückt wurde.


4) Top-Level I/O (Vorschlag)

Eingänge

  • clk — Board-Takt (z. B. 100 MHz auf vielen Artix-7 Boards)

  • rst_n — Reset aktiv-low

  • ped_btn_ns, ped_btn_ew — Fußgängertaster (asynchron, intern entprellt)

  • emergency_ns, emergency_ew — Vorranganforderungen (level-sensitiv)

  • night_mode — Nachtmodus aktivieren (level-sensitiv)

Ausgänge

  • ns_red, ns_yel, ns_grn

  • ew_red, ew_yel, ew_grn

  • ped_walk_ns — „GEH“ über NS-Fahrbahn (aktiv während EW-Grün bei Anforderung)

  • ped_walk_ew — „GEH“ über EW-Fahrbahn (aktiv während NS-Grün bei Anforderung)


5) Synthesefähiges SystemVerilog

5.1 Sekunden Tick Generator (parametriert)

 

module tick_gen #(
  parameter int unsigned F_CLK_HZ = 100_000_000
)(
  input  logic clk,
  input  logic rst_n,
  output logic tick_1hz,     // 1-cycle pulse per second
  output logic blink_1hz     // 0.5 duty square wave @ 1 Hz
);
  localparam int unsigned CNT_MAX = F_CLK_HZ - 1;
  logic [$clog2(F_CLK_HZ)-1:0] cnt;
  logic                        sq;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      cnt <= '0;
      tick_1hz <= 1'b0;
      sq <= 1'b0;
    end else begin
      tick_1hz <= 1'b0;
      if (cnt == CNT_MAX) begin
        cnt <= '0;
        tick_1hz <= 1'b1;
        sq <= ~sq;
      end else begin
        cnt <= cnt + 1'b1;
      end
    end
  end

  assign blink_1hz = sq;
endmodule

5.2 Druckknopf Debouncer (pro Knopf)

 

module debounce #(
  parameter int unsigned F_CLK_HZ = 100_000_000,
  parameter int unsigned STABLE_MS = 20
)(
  input  logic clk,
  input  logic rst_n,
  input  logic din_async,      // raw button
  output logic dout_stable,    // debounced level
  output logic dout_rise       // 1-cycle pulse on rising edge
);
  // Two-flop synchronizer
  logic d0, d1;
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin d0 <= 0; d1 <= 0; end
    else begin d0 <= din_async; d1 <= d0; end
  end

  // Debounce counter
  localparam int unsigned THRESH = (F_CLK_HZ/1000) * STABLE_MS;
  logic [$clog2(THRESH+1)-1:0] cnt;
  logic filtered;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      cnt <= '0;
      filtered <= 1'b0;
    end else begin
      if (d1 != filtered) begin
        if (cnt == THRESH[$clog2(THRESH+1)-1:0]) begin
          filtered <= d1;
          cnt <= '0;
        end else begin
          cnt <= cnt + 1'b1;
        end
      end else begin
        cnt <= '0;
      end
    end
  end

  logic filtered_q;
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin filtered_q <= 0; end
    else filtered_q <= filtered;
  end

  assign dout_stable = filtered;
  assign dout_rise   = filtered & ~filtered_q;
endmodule

5.3 Verkehrsregler FSM

 

module traffic_controller #(
  parameter int unsigned F_CLK_HZ            = 100_000_000,
  parameter int unsigned GREEN_MIN_SEC_NS    = 15,
  parameter int unsigned GREEN_MIN_SEC_EW    = 12,
  parameter int unsigned YELLOW_SEC          = 3,
  parameter int unsigned ALL_RED_SEC         = 1,
  parameter int unsigned WALK_SEC            = 10,
  parameter int unsigned PREEMPT_RED_SEC     = 2
)(
  input  logic clk,
  input  logic rst_n,
  // control inputs
  input  logic tick_1hz,
  input  logic blink_1hz,
  input  logic ped_req_ns,     // debounced pulse (rise) requesting to cross NS roadway
  input  logic ped_req_ew,     // debounced pulse (rise) requesting to cross EW roadway
  input  logic emergency_ns,
  input  logic emergency_ew,
  input  logic night_mode,

  // lights
  output logic ns_red, ns_yel, ns_grn,
  output logic ew_red, ew_yel, ew_grn,
  // pedestrians
  output logic ped_walk_ns,    // walk across NS roadway (allowed during EW green)
  output logic ped_walk_ew     // walk across EW roadway (allowed during NS green)
);

  // Latch pedestrian requests until served
  logic latched_ped_ns, latched_ped_ew;
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      latched_ped_ns <= 1'b0;
      latched_ped_ew <= 1'b0;
    end else begin
      if (ped_req_ns) latched_ped_ns <= 1'b1;
      if (ped_req_ew) latched_ped_ew <= 1'b1;
      // cleared when served (see below)
    end
  end

  // FSM states (one-hot)
  typedef enum logic [7:0] {
    S_NS_GREEN           = 8'b0000_0001,
    S_NS_YELLOW          = 8'b0000_0010,
    S_ALL_RED_1          = 8'b0000_0100,
    S_EW_GREEN           = 8'b0000_1000,
    S_EW_YELLOW          = 8'b0001_0000,
    S_ALL_RED_2          = 8'b0010_0000,
    S_PREEMPT_ALL_RED_NS = 8'b0100_0000,
    S_PREEMPT_ALL_RED_EW = 8'b1000_0000
  } state_t;

  state_t state, next_state;

  // Per-state target duration in seconds, set on entry
  int unsigned target_sec;
  int unsigned sec_count;

  // Enter detection
  logic enter_state;

  // State register & per-state timer
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state      <= S_NS_GREEN;
      sec_count  <= 0;
      target_sec <= GREEN_MIN_SEC_NS;
    end else begin
      state <= next_state;

      // per-second counter
      if (night_mode) begin
        sec_count <= 0;       // paused (not used)
      end else if (tick_1hz) begin
        if (enter_state) sec_count <= 1;           // start counting from 1 on entry tick
        else if (sec_count < target_sec) sec_count <= sec_count + 1;
      end
    end
  end

  // Determine next_state and target_sec
  always_comb begin
    next_state = state;
    enter_state = 1'b0;

    // default target (hold previous)
    int unsigned next_target = target_sec;

    // Emergency pre-emption has priority unless we’re already granting that direction
    logic want_preempt_ns = emergency_ns && (state != S_NS_GREEN) && !night_mode;
    logic want_preempt_ew = emergency_ew && (state != S_EW_GREEN) && !night_mode;

    if (want_preempt_ns) begin
      if (state != S_PREEMPT_ALL_RED_NS) begin
        next_state  = S_PREEMPT_ALL_RED_NS;
        next_target = PREEMPT_RED_SEC;
        enter_state = 1'b1;
      end else if (tick_1hz && sec_count >= target_sec) begin
        next_state  = S_NS_GREEN;
        // Ensure at least minimum NS green
        next_target = GREEN_MIN_SEC_NS;
        enter_state = 1'b1;
      end
    end
    else if (want_preempt_ew) begin
      if (state != S_PREEMPT_ALL_RED_EW) begin
        next_state  = S_PREEMPT_ALL_RED_EW;
        next_target = PREEMPT_RED_SEC;
        enter_state = 1'b1;
      end else if (tick_1hz && sec_count >= target_sec) begin
        next_state  = S_EW_GREEN;
        next_target = GREEN_MIN_SEC_EW;
        enter_state = 1'b1;
      end
    end
    else if (!night_mode) begin
      case (state)
        S_NS_GREEN: begin
          // If EW pedestrians requested, ensure NS_GREEN lasts at least WALK_SEC for crossing EW roadway
          int unsigned need = (latched_ped_ew ? ((WALK_SEC > GREEN_MIN_SEC_NS) ? WALK_SEC : GREEN_MIN_SEC_NS)
                                             : GREEN_MIN_SEC_NS);
          next_target = need;
          if (tick_1hz && sec_count >= next_target) begin
            next_state  = S_NS_YELLOW;
            next_target = YELLOW_SEC;
            enter_state = 1'b1;
          end
        end
        S_NS_YELLOW: begin
          if (tick_1hz && sec_count >= target_sec) begin
            next_state  = S_ALL_RED_1;
            next_target = ALL_RED_SEC;
            enter_state = 1'b1;
          end
        end
        S_ALL_RED_1: begin
          if (tick_1hz && sec_count >= target_sec) begin
            next_state  = S_EW_GREEN;
            // If NS pedestrians requested, ensure EW_GREEN covers WALK_SEC
            int unsigned need = (latched_ped_ns ? ((WALK_SEC > GREEN_MIN_SEC_EW) ? WALK_SEC : GREEN_MIN_SEC_EW)
                                                : GREEN_MIN_SEC_EW);
            next_target = need;
            enter_state = 1'b1;
          end
        end
        S_EW_GREEN: begin
          if (tick_1hz && sec_count >= target_sec) begin
            next_state  = S_EW_YELLOW;
            next_target = YELLOW_SEC;
            enter_state = 1'b1;
          end
        end
        S_EW_YELLOW: begin
          if (tick_1hz && sec_count >= target_sec) begin
            next_state  = S_ALL_RED_2;
            next_target = ALL_RED_SEC;
            enter_state = 1'b1;
          end
        end
        S_ALL_RED_2: begin
          if (tick_1hz && sec_count >= target_sec) begin
            next_state  = S_NS_GREEN;
            int unsigned need = (latched_ped_ew ? ((WALK_SEC > GREEN_MIN_SEC_NS) ? WALK_SEC : GREEN_MIN_SEC_NS)
                                                : GREEN_MIN_SEC_NS);
            next_target = need;
            enter_state = 1'b1;
          end
        end
        default: begin
          next_state  = S_NS_GREEN;
          next_target = GREEN_MIN_SEC_NS;
          enter_state = 1'b1;
        end
      endcase
    end

    // commit target update
    if (enter_state) begin
      // clear served ped latches when we *leave* the relevant green
      // (do this by recognizing entry into the next state)
      // NS pedestrians are served during EW_GREEN. When we exit EW_GREEN (entry to EW_YELLOW), clear latched_ped_ns.
      // EW pedestrians are served during NS_GREEN. When we exit NS_GREEN (entry to NS_YELLOW), clear latched_ped_ew.
    end
  end

  // Target register update
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) target_sec <= GREEN_MIN_SEC_NS;
    else if (enter_state)   target_sec <= (next_state == S_NS_GREEN) ? GREEN_MIN_SEC_NS : target_sec;
    else                    target_sec <= target_sec; // keep
  end

  // Manage pedestrian latch clears + outputs and light driving
  // We’ll compute outputs combinationally; clears happen on entry to the *next* state.
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      // nothing extra
    end else if (enter_state) begin
      // Clear latches when we *enter* the state after their green has completed
      unique case (next_state)
        S_NS_YELLOW:    latched_ped_ew <= 1'b0; // just left NS_GREEN
        S_EW_YELLOW:    latched_ped_ns <= 1'b0; // just left EW_GREEN
        default: ;
      endcase
    end
  end

  // Outputs
  always_comb begin
    // defaults off
    ns_red = 0; ns_yel = 0; ns_grn = 0;
    ew_red = 0; ew_yel = 0; ew_grn = 0;
    ped_walk_ns = 0;
    ped_walk_ew = 0;

    if (night_mode) begin
      // Flashing: NS yellow blinks, EW red blinks
      ns_yel = blink_1hz;
      ew_red = blink_1hz;
    end else begin
      unique case (state)
        S_NS_GREEN, S_PREEMPT_ALL_RED_EW: begin
          ns_grn = (state == S_NS_GREEN);
          ns_yel = 0;
          ns_red = ~ns_grn;

          ew_red = 1;
          // Pedestrians cross EW roadway during NS green if requested: WALK for the first WALK_SEC seconds
          if (state == S_NS_GREEN && latched_ped_ew && (sec_count <= WALK_SEC)) ped_walk_ew = 1;
        end

        S_NS_YELLOW: begin
          ns_yel = 1; ew_red = 1;
        end

        S_ALL_RED_1, S_ALL_RED_2: begin
          ns_red = 1; ew_red = 1;
        end

        S_EW_GREEN, S_PREEMPT_ALL_RED_NS: begin
          ew_grn = (state == S_EW_GREEN);
          ew_yel = 0;
          ew_red = ~ew_grn;

          ns_red = 1;
          // Pedestrians cross NS roadway during EW green if requested
          if (state == S_EW_GREEN && latched_ped_ns && (sec_count <= WALK_SEC)) ped_walk_ns = 1;
        end

        S_EW_YELLOW: begin
          ew_yel = 1; ns_red = 1;
        end

        default: begin
          ns_red = 1; ew_red = 1;
        end
      endcase
    end
  end

endmodule

5.4 Top Modul (Verkabelung Tick + Debouncer + Controller)

 

module traffic_top #(
  parameter int unsigned F_CLK_HZ            = 100_000_000,
  parameter int unsigned GREEN_MIN_SEC_NS    = 15,
  parameter int unsigned GREEN_MIN_SEC_EW    = 12,
  parameter int unsigned YELLOW_SEC          = 3,
  parameter int unsigned ALL_RED_SEC         = 1,
  parameter int unsigned WALK_SEC            = 10,
  parameter int unsigned PREEMPT_RED_SEC     = 2
)(
  input  logic clk,
  input  logic rst_n,
  input  logic ped_btn_ns, ped_btn_ew,
  input  logic emergency_ns, emergency_ew,
  input  logic night_mode,

  output logic ns_red, ns_yel, ns_grn,
  output logic ew_red, ew_yel, ew_grn,
  output logic ped_walk_ns, ped_walk_ew
);

  logic tick_1hz, blink_1hz;
  tick_gen #(.F_CLK_HZ(F_CLK_HZ)) u_tick (
    .clk, .rst_n, .tick_1hz, .blink_1hz
  );

  logic ped_ns_level, ped_ns_rise;
  logic ped_ew_level, ped_ew_rise;

  debounce #(.F_CLK_HZ(F_CLK_HZ)) u_db_ns (
    .clk, .rst_n, .din_async(ped_btn_ns),
    .dout_stable(ped_ns_level), .dout_rise(ped_ns_rise)
  );
  debounce #(.F_CLK_HZ(F_CLK_HZ)) u_db_ew (
    .clk, .rst_n, .din_async(ped_btn_ew),
    .dout_stable(ped_ew_level), .dout_rise(ped_ew_rise)
  );

  traffic_controller #(
    .F_CLK_HZ(F_CLK_HZ),
    .GREEN_MIN_SEC_NS(GREEN_MIN_SEC_NS),
    .GREEN_MIN_SEC_EW(GREEN_MIN_SEC_EW),
    .YELLOW_SEC(YELLOW_SEC),
    .ALL_RED_SEC(ALL_RED_SEC),
    .WALK_SEC(WALK_SEC),
    .PREEMPT_RED_SEC(PREEMPT_RED_SEC)
  ) u_ctrl (
    .clk, .rst_n,
    .tick_1hz, .blink_1hz,
    .ped_req_ns(ped_ns_rise), .ped_req_ew(ped_ew_rise),
    .emergency_ns, .emergency_ew,
    .night_mode,
    .ns_red, .ns_yel, .ns_grn,
    .ew_red, .ew_yel, .ew_grn,
    .ped_walk_ns, .ped_walk_ew
  );

endmodule

 


6) Minimaler Testbench (schnelle Simulation)

Ein Testbench mit reduziertem Takt (1 kHz) und verkürzten Zeitwerten, damit ein kompletter Zyklus in Millisekunden abläuft.

`timescale 1us/1ns
module tb_traffic;
  localparam int F_CLK_HZ_SIM = 1000;

  logic clk = 0;
  logic rst_n = 0;
  always #0.5 clk = ~clk; // 1 kHz

  // Shrink times for simulation
  localparam int GNS = 5, GEW = 4, Y = 2, AR = 1, WALK = 3, PRE = 1;

  logic ped_btn_ns, ped_btn_ew, emergency_ns, emergency_ew, night_mode;
  wire ns_r, ns_y, ns_g, ew_r, ew_y, ew_g, ped_w_ns, ped_w_ew;

  traffic_top #(
    .F_CLK_HZ(F_CLK_HZ_SIM),
    .GREEN_MIN_SEC_NS(GNS),
    .GREEN_MIN_SEC_EW(GEW),
    .YELLOW_SEC(Y),
    .ALL_RED_SEC(AR),
    .WALK_SEC(WALK),
    .PREEMPT_RED_SEC(PRE)
  ) dut (
    .clk, .rst_n,
    .ped_btn_ns, .ped_btn_ew,
    .emergency_ns, .emergency_ew,
    .night_mode,
    .ns_red(ns_r), .ns_yel(ns_y), .ns_grn(ns_g),
    .ew_red(ew_r), .ew_yel(ew_y), .ew_grn(ew_g),
    .ped_walk_ns(ped_w_ns), .ped_walk_ew(ped_w_ew)
  );

  initial begin
    ped_btn_ns = 0; ped_btn_ew = 0; emergency_ns = 0; emergency_ew = 0; night_mode = 0;
    #5  rst_n = 1;

    // Request to cross NS roadway (served during upcoming EW green)
    #200 ped_btn_ns = 1; #3 ped_btn_ns = 0;

    // Later, trigger emergency in NS direction
    #400 emergency_ns = 1; #50 emergency_ns = 0;

    // Night mode for a moment
    #400 night_mode = 1; #200 night_mode = 0;

    // Request to cross EW roadway (served during upcoming NS green)
    #100 ped_btn_ew = 1; #3 ped_btn_ew = 0;

    #1000 $finish;
  end
endmodule


7) Constraints (Xilinx-Beispiel)

Anpassung der Pins/Takte an dein FPGA-Board (z. B. Basys-3: 100 MHz-Takt auf W5).
LED-Pins nach eigener Belegung ersetzen.

# Clock
set_property PACKAGE_PIN W5 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
create_clock -period 10.000 -name sys_clk [get_ports clk]  ;# 100 MHz

# Reset (active-low button)
set_property PACKAGE_PIN U18 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property PULLUP true [get_ports rst_n]

# Buttons (debounced inside FPGA)
set_property PACKAGE_PIN T18 [get_ports ped_btn_ns]
set_property PACKAGE_PIN U17 [get_ports ped_btn_ew]
set_property IOSTANDARD LVCMOS33 [get_ports {ped_btn_ns ped_btn_ew}]

# Emergency & night mode (switches)
set_property PACKAGE_PIN V17 [get_ports emergency_ns]
set_property PACKAGE_PIN V16 [get_ports emergency_ew]
set_property PACKAGE_PIN W16 [get_ports night_mode]
set_property IOSTANDARD LVCMOS33 [get_ports {emergency_ns emergency_ew night_mode}]

# LEDs (example pins—replace!)
set_property PACKAGE_PIN U16 [get_ports ns_red]
set_property PACKAGE_PIN E19 [get_ports ns_yel]
set_property PACKAGE_PIN U19 [get_ports ns_grn]
set_property PACKAGE_PIN V19 [get_ports ew_red]
set_property PACKAGE_PIN W18 [get_ports ew_yel]
set_property PACKAGE_PIN W19 [get_ports ew_grn]
set_property PACKAGE_PIN U15 [get_ports ped_walk_ns]
set_property PACKAGE_PIN V15 [get_ports ped_walk_ew]
set_property IOSTANDARD LVCMOS33 [get_ports {ns_red ns_yel ns_grn ew_red ew_yel ew_grn ped_walk_ns ped_walk_ew}]


8) Inbetriebnahme-Checkliste

  1. Takt prüfen: GPIO mit 1-Hz-Blinksignal ausgeben.

  2. Reset: rst_n=0 halten, dann loslassen — Start bei NS-Grün.

  3. Standardzyklus: ohne Eingaben den Ablauf G→Y→Rot→G prüfen.

  4. Fußgänger: Taster während der anderen Grünphase drücken; GEH-Signal für GEH_SEK Sekunden sichtbar.

  5. Vorrang: emergency_ns oder emergency_ew aktivieren; kurzer Rot-Block, dann sofort Grün für die Richtung.

  6. Nachtmodus: night_mode aktivieren; Blinken (NS Gelb / EW Rot) unabhängig vom FSM-Zustand.


9) Erweiterungen (leicht umsetzbar)

  • Fahrzeug-Induktionsschleifen zur dynamischen Grünverlängerung

  • 7-Segment- oder OLED-Countdownanzeige

  • Akustischer Fußgängersignalgeber & blinkendes „DON’T WALK“

  • Zeitgesteuerter Nachtmodus (z. B. 00:00–05:00)

  • TMR (Triple Modular Redundancy) zur Fehlertoleranz

  • Formale Verifikation der Zustandsübergänge (niemals beide Richtungen grün gleichzeitig)

Ampheo