Schritt-für-Schritt-Anleitung: Ihre erste FPGA-LED-Blink-Schaltung erstellen
Schritt-für-Schritt-Anleitung: Erste FPGA-LED-Blink-Schaltung bauen
Teil 1: VHDL- oder Verilog-Design
In diesem Tutorial lernen Sie, wie Sie VHDL- und Verilog-Code erstellen, der eine LED mit einer benutzerdefinierten Frequenz ansteuert. Wählen Sie die Sprache, die am besten zu Ihrem Workflow passt.
Beim Schreiben von HDL müssen Sie überprüfen, ob sich das Design wie beabsichtigt verhält. Fehler sind unvermeidlich, daher ist Simulation unverzichtbar. Dieses Tutorial ist in zwei kritische Phasen unterteilt:
- HDL-Design
- HDL-Simulation
Das Überspringen der Simulation kann zu kostspieligem On-Hardware-Debugging führen. Behandeln Sie die Simulation als obligatorischen Kontrollpunkt.
Projektanforderungen
Schreiben Sie HDL, das eine LED mit 100 Hz, 50 Hz, 10 Hz oder 1 Hz bei 50 % Tastverhältnis blinken lässt. Zwei Schalter wählen die gewünschte Frequenz, und ein zusätzlicher LED_EN-Schalter muss high sein, um die LED zu aktivieren. Der FPGA läuft mit einem 25-MHz-Oszillator.
Wahrheitstabelle für den Frequenzwähler:
| Enable | Schalter 1 | Schalter 2 | LED-Ansteuerfrequenz |
|---|---|---|---|
| 0 | – | – | deaktiviert |
| 1 | 0 | 0 | 100 Hz |
| 1 | 0 | 1 | 50 Hz |
| 1 | 1 | 0 | 10 Hz |
| 1 | 1 | 1 | 1 Hz |
Signalübersicht:
| Signalname | Richtung | Beschreibung |
|---|---|---|
| i_clock | Eingang | 25 MHz Takt |
| i_enable | Eingang | Aktivierungsschalter (Logik 0 = LED aus) |
| i_switch_1 | Eingang | Frequenzwähler-Schalter 1 |
| i_switch_2 | Eingang | Frequenzwähler-Schalter 2 |
| o_led_drive | Ausgang | LED-Ansteuersignal |
Vier parallele Zählerprozesse überwachen den 25-MHz-Takt und erzeugen Toggles für jede Zielfrequenz. Selbst wenn eine bestimmte Frequenz nicht gewählt ist, läuft ihr Zähler weiter – ein Kernprinzip der Hardware-Konkurrenz.
Die Schalter bilden einen Multiplexer, der das gewählte Toggle zum LED-Ausgang routet. Multiplexer sind rein kombinatorische Logik und arbeiten ohne Takt.
Unten sehen Sie ein Blockdiagramm der Architektur:

VHDL-Implementierung
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tutorial_led_blink is
port (
i_clock : in std_logic;
i_enable : in std_logic;
i_switch_1 : in std_logic;
i_switch_2 : in std_logic;
o_led_drive : out std_logic
);
end tutorial_led_blink;
architecture rtl of tutorial_led_blink is
-- Konstanten für die benötigten Frequenzen:
-- Formel: (25 MHz / 100 Hz * 50% Tastverhältnis)
-- Für 100 Hz: 25.000.000 / 100 * 0.5 = 125.000
constant c_CNT_100HZ : natural := 125000;
constant c_CNT_50HZ : natural := 250000;
constant c_CNT_10HZ : natural := 1250000;
constant c_CNT_1HZ : natural := 12500000;
-- Zähler-Signale
signal r_CNT_100HZ : natural range 0 to c_CNT_100HZ;
signal r_CNT_50HZ : natural range 0 to c_CNT_50HZ;
signal r_CNT_10HZ : natural range 0 to c_CNT_10HZ;
signal r_CNT_1HZ : natural range 0 to c_CNT_1HZ;
-- Toggle-Signale für die Frequenzen
signal r_TOGGLE_100HZ : std_logic := '0';
signal r_TOGGLE_50HZ : std_logic := '0';
signal r_TOGGLE_10HZ : std_logic := '0';
signal r_TOGGLE_1HZ : std_logic := '0';
-- Ein-Bit-Auswahlsignal
signal w_LED_SELECT : std_logic;
begin
-- Alle Prozessen toggeln ein spezifisches Signal mit einer anderen Frequenz.
-- Sie laufen kontinuierlich, auch wenn die Schalter ihre Ausgabe nicht wählen.
p_100_HZ : process (i_clock) is
begin
if rising_edge(i_clock) then
if r_CNT_100HZ = c_CNT_100HZ-1 then
r_TOGGLE_100HZ <= not r_TOGGLE_100HZ;
r_CNT_100HZ <= 0;
else
r_CNT_100HZ <= r_CNT_100HZ + 1;
end if;
end if;
end process p_100_HZ;
p_50_HZ : process (i_clock) is
begin
if rising_edge(i_clock) then
if r_CNT_50HZ = c_CNT_50HZ-1 then
r_TOGGLE_50HZ <= not r_TOGGLE_50HZ;
r_CNT_50HZ <= 0;
else
r_CNT_50HZ <= r_CNT_50HZ + 1;
end if;
end if;
end process p_50_HZ;
p_10_HZ : process (i_clock) is
begin
if rising_edge(i_clock) then
if r_CNT_10HZ = c_CNT_10HZ-1 then
r_TOGGLE_10HZ <= not r_TOGGLE_10HZ;
r_CNT_10HZ <= 0;
else
r_CNT_10HZ <= r_CNT_10HZ + 1;
end if;
end if;
end process p_10_HZ;
p_1_HZ : process (i_clock) is
begin
if rising_edge(i_clock) then
if r_CNT_1HZ = c_CNT_1HZ-1 then
r_TOGGLE_1HZ <= not r_TOGGLE_1HZ;
r_CNT_1HZ <= 0;
else
r_CNT_1HZ <= r_CNT_1HZ + 1;
end if;
end if;
end process p_1_HZ;
-- Multiplexer basierend auf Schalter-Eingängen
w_LED_SELECT <= r_TOGGLE_100HZ when (i_switch_1 = '0' and i_switch_2 = '0') else
r_TOGGLE_50HZ when (i_switch_1 = '0' and i_switch_2 = '1') else
r_TOGGLE_10HZ when (i_switch_1 = '1' and i_switch_2 = '0') else
r_TOGGLE_1HZ;
-- o_led_drive nur treiben, wenn i_enable high ist (UND-Gatter).
o_led_drive <= w_LED_SELECT and i_enable;
end rtl;
Verilog-Implementierung
module tutorial_led_blink (
i_clock,
i_enable,
i_switch_1,
i_switch_2,
o_led_drive
);
input i_clock;
input i_enable;
input i_switch_1;
input i_switch_2;
output o_led_drive;
// Konstanten (Parameter) für die Frequenzen:
// Eingangstakt ist 25 kHz, willkürlich gewählt.
// Formel: (25 kHz / 100 Hz * 50% Tastverhältnis)
// Für 100 Hz: 25.000 / 100 * 0.5 = 125
parameter c_CNT_100HZ = 125;
parameter c_CNT_50HZ = 250;
parameter c_CNT_10HZ = 1250;
parameter c_CNT_1HZ = 12500;
// Zähler-Signale
reg [31:0] r_CNT_100HZ = 0;
reg [31:0] r_CNT_50HZ = 0;
reg [31:0] r_CNT_10HZ = 0;
reg [31:0] r_CNT_1HZ = 0;
// Toggle-Signale
reg r_TOGGLE_100HZ = 1'b0;
reg r_TOGGLE_50HZ = 1'b0;
reg r_TOGGLE_10HZ = 1'b0;
reg r_TOGGLE_1HZ = 1'b0;
// Ein-Bit-Auswahl
reg r_LED_SELECT;
wire w_LED_SELECT;
// Alle always-Blöcke toggeln ein spezifisches Signal mit einer anderen Frequenz.
// Sie laufen kontinuierlich, auch wenn die Schalter ihre Ausgabe nicht wählen.
always @ (posedge i_clock) begin
if (r_CNT_100HZ == c_CNT_100HZ-1) begin
r_TOGGLE_100HZ <= !r_TOGGLE_100HZ;
r_CNT_100HZ <= 0;
end else
r_CNT_100HZ <= r_CNT_100HZ + 1;
end
always @ (posedge i_clock) begin
if (r_CNT_50HZ == c_CNT_50HZ-1) begin
r_TOGGLE_50HZ <= !r_TOGGLE_50HZ;
r_CNT_50HZ <= 0;
end else
r_CNT_50HZ <= r_CNT_50HZ + 1;
end
always @ (posedge i_clock) begin
if (r_CNT_10HZ == c_CNT_10HZ-1) begin
r_TOGGLE_10HZ <= !r_TOGGLE_10HZ;
r_CNT_10HZ <= 0;
end else
r_CNT_10HZ <= r_CNT_10HZ + 1;
end
always @ (posedge i_clock) begin
if (r_CNT_1HZ == c_CNT_1HZ-1) begin
r_TOGGLE_1HZ <= !r_TOGGLE_1HZ;
r_CNT_1HZ <= 0;
end else
r_CNT_1HZ <= r_CNT_1HZ + 1;
end
// Multiplexer basierend auf Schalter-Eingängen
always @ (*) begin
case ({i_switch_1, i_switch_2}) // Konkatenationsoperator
2'b11 : r_LED_SELECT <= r_TOGGLE_1HZ;
2'b10 : r_LED_SELECT <= r_TOGGLE_10HZ;
2'b01 : r_LED_SELECT <= r_TOGGLE_50HZ;
2'b00 : r_LED_SELECT <= r_TOGGLE_100HZ;
endcase
end
assign o_led_drive = r_LED_SELECT & i_enable;
// Alternative Multiplexer-Design (gleich wie oben):
// Kompakter, aber schwerer lesbar, besonders für Verilog-Einsteiger
// assign w_LED_SELECT = i_switch_1 ? (i_switch_2 ? r_TOGGLE_1HZ : r_TOGGLE_10HZ) :
// (i_switch_2 ? r_TOGGLE_50HZ : r_TOGGLE_100HZ);
// assign o_led_drive = w_LED_SELECT & i_enable;
endmodule
Nächster Schritt: Simulieren Sie dieses Design in VHDL oder Verilog, um das korrekte Verhalten vor der Bereitstellung zu bestätigen.
VHDL
- VHDL & Verilog meistern: Saubere kombinatorische & sequentielle Logik schreiben
- FPGA Block RAM aus Textdateien mit VHDLs TEXTIO-Bibliothek initialisieren
- VUnit 101: Praktischer Leitfaden für automatisierte VHDL-Verifikation
- Einführung in VHDL: Ihr erstes AND-Gate bauen
- VHDL Procedure Beispiel: Inkrementieren eines Standard Logic Vectors
- Prozeduren in VHDL: Wiederverwendbaren Code für einfachere Designs
- Bedingte Logik in VHDL meistern: If-Then-Elsif-Else erklärt
- VHDL-Funktionen meistern: Praktischer Leitfaden für effizientes Design
- Umfassender Guide zu VHDL Typkonvertierungen mit Numeric_Std & Std_Logic_Arith
- While-Schleifen in VHDL meistern: Dynamische Iterationssteuerung