So bauen Sie Ihren ersten FPGA-LED-Blinker:Eine Schritt-für-Schritt-Anleitung
Schritt-für-Schritt-Anleitung:Bauen Sie Ihren ersten FPGA-LED-Blinker
Teil 1:Entwerfen von VHDL oder Verilog
In diesem Tutorial erfahren 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 sicherstellen, dass 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 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 und einem Arbeitszyklus von 50 % blinken lässt. Zwei Schalter wählen die gewünschte Frequenz und ein zusätzlicher LED_EN Der Schalter muss hoch sein, um die LED zu aktivieren. Das FPGA läuft auf einem 25-MHz-Oszillator.
Wahrheitstabelle für den Frequenzselektor:
| Aktivieren | Schalter1 | Schalter2 | LED-Antriebsfrequenz |
|---|---|---|---|
| 0 | – | – | deaktiviert |
| 1 | 0 | 0 | 100Hz |
| 1 | 0 | 1 | 50Hz |
| 1 | 1 | 0 | 10Hz |
| 1 | 1 | 1 | 1Hz |
Signalzusammenfassung:
| Signalname | Richtung | Beschreibung |
|---|---|---|
| i_clock | Eingabe | 25-MHz-Takt |
| i_enable | Eingabe | Aktivierungsschalter (Logik0 =LED aus) |
| i_switch_1 | Eingabe | Frequenzwahlschalter1 |
| i_switch_2 | Eingabe | Frequenzwahlschalter2 |
| o_led_drive | Ausgabe | LED-Antriebssignal |
Vier gleichzeitige Zählerprozesse überwachen den 25-MHz-Takt und erzeugen Umschaltungen für jede Zielfrequenz. Auch wenn eine bestimmte Frequenz nicht ausgewählt ist, läuft der Zähler weiter – ein Kernprinzip der Hardware-Parallelität.
Die Schalter bilden einen Multiplexer, der den gewählten Schalter an den LED-Ausgang weiterleitet. Multiplexer sind rein kombinatorische Logik, arbeiten also ohne Takt.
Unten finden Sie ein Blockdiagramm, das die Architektur veranschaulicht:

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 -- Constants to create the frequencies needed: -- Formula is: (25 MHz / 100 Hz * 50% duty cycle) -- So for 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; -- These signals will be the counters: 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; -- These signals will toggle at the frequencies needed: 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'; -- One bit select wire. signal w_LED_SELECT : std_logic; begin -- All processes toggle a specific signal at a different frequency. -- They all run continuously even if the switches are -- not selecting their particular output. p_100_HZ : process (i_clock) is begin if rising_edge(i_clock) then if r_CNT_100HZ = c_CNT_100HZ-1 then -- -1, since counter starts at 0 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 -- -1, since counter starts at 0 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 -- -1, since counter starts at 0 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 -- -1, since counter starts at 0 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; -- Create a multiplexor based on switch inputs 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; -- Only allow o_led_drive to drive when i_enable is high (and gate). 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; // Constants (parameters) to create the frequencies needed: // Input clock is 25 kHz, chosen arbitrarily. // Formula is: (25 kHz / 100 Hz * 50% duty cycle) // So for 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; // These signals will be the counters: 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; // These signals will toggle at the frequencies needed: reg r_TOGGLE_100HZ = 1'b0; reg r_TOGGLE_50HZ = 1'b0; reg r_TOGGLE_10HZ = 1'b0; reg r_TOGGLE_1HZ = 1'b0; // One bit select reg r_LED_SELECT; wire w_LED_SELECT; begin // All always blocks toggle a specific signal at a different frequency. // They all run continuously even if the switches are // not selecting their particular output. always @ (posedge i_clock) begin if (r_CNT_100HZ == c_CNT_100HZ-1) // -1, since counter starts at 0 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) // -1, since counter starts at 0 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) // -1, since counter starts at 0 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) // -1, since counter starts at 0 begin r_TOGGLE_1HZ <= !r_TOGGLE_1HZ; r_CNT_1HZ <= 0; end else r_CNT_1HZ <= r_CNT_1HZ + 1; end // Create a multiplexer based on switch inputs always @ (*) begin case () // Concatenation Operator 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 way to design multiplexer (same as above): // More compact, but harder to read, especially to those new to Verilog // 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; end endmodule
Nächster Schritt:Simulieren Sie dieses Design in VHDL oder Verilog, um das korrekte Verhalten vor der Bereitstellung zu bestätigen.
VHDL
- Grundlegendes VHDL-Quiz – Teil 1
- Beispiele für VHDL-Konvertierungen
- So verknüpfen Sie Quartus Prime IP-Bibliotheken mit VUnit
- Einsteigerleitfaden zur Verwendung von Modelsim für die FPGA- und ASIC-Simulation
- Erste Schritte mit VUnit
- Variablen – VHDL-Beispiel
- So bauen Sie Ihren ersten FPGA-LED-Blinker:Eine Schritt-für-Schritt-Anleitung
- So verwenden Sie die Port Map-Instanziierung in VHDL
- So erstellen Sie einen getakteten Prozess in VHDL
- So erstellen Sie einen PWM-Controller in VHDL