Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> VHDL

Tutorial:Ihr erstes FPGA-Programm:Ein LED-Blinker

Teil 1:Design von VHDL oder Verilog

Dieses Tutorial zeigt den Aufbau von VHDL- und Verilog-Code, der eine LED mit einer bestimmten Frequenz blinkt. Sowohl VHDL als auch Verilog werden angezeigt, und Sie können auswählen, was Sie zuerst lernen möchten. Wann immer Designcode geschrieben wird, muss der FPGA-Designer sicherstellen, dass er wie beabsichtigt funktioniert. Trotz Ihrer besten Bemühungen wird es immer Fehler in Ihrem ursprünglichen Design geben. Der beste Weg, diese Fehler zu finden, ist in einer Simulationsumgebung. Dieses Tutorial ist in 2 Phasen unterteilt:

  1. Design von HDL
  2. Simulation von HDL

Beide Schritte sind entscheidend für eine erfolgreiche FPGA-Entwicklung. Manchmal versuchen FPGA-Designer, die unter Zeitdruck stehen, Schritt zwei, die Simulation ihres Codes, zu überspringen. Dies ist jedoch ein äußerst wichtiger Schritt! Ohne eine ordnungsgemäße Simulation werden Sie gezwungen sein, Ihren Code auf Hardware zu debuggen, was ein sehr schwieriges und zeitaufwändiges Unterfangen sein kann.

Projektanforderungen:

Entwerfen Sie einen HDL-Code, der eine LED mit einer bestimmten Frequenz von 100 Hz, 50 Hz, 10 Hz oder 1 Hz blinken lässt. Für jede der Blinkfrequenzen wird die LED auf 50 % Einschaltdauer eingestellt (sie wird die Hälfte der Zeit eingeschaltet sein). Die LED-Frequenz wird über zwei Schalter gewählt, die Eingänge zum FPGA sind. Es gibt einen zusätzlichen Schalter namens LED_EN, der „1“ sein muss, um die LED einzuschalten. Das FPGA wird von einem 25-MHz-Oszillator angesteuert.

Lassen Sie uns zuerst die Wahrheitstabelle für den Frequenzwähler zeichnen:

Aktivieren 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

Damit dies richtig funktioniert, gibt es 4 Eingänge und 1 Ausgang. Die Signale sind:

Signalname Richtung Beschreibung i_clock Eingang 25 MHz Takt i_enable Eingang Der Aktivierungsschalter (logisch 0 =kein LED-Betrieb) i_switch_1 Eingang Schalter 1 in der obigen Wahrheitstabelle i_switch_2 Eingang Schalter 2 in der obigen Wahrheitstabelle o_led_drive Ausgang Das Signal, das die LED ansteuert

Für das Design gibt es vier Zählerprozesse, die gleichzeitig laufen. Das bedeutet, dass sie alle zur gleichen Zeit laufen. Ihre Aufgabe ist es, die Anzahl der Taktimpulse zu verfolgen, die für jede der verschiedenen Frequenzen gesehen werden. Selbst wenn die Schalter diese bestimmte Frequenz nicht auswählen, laufen die Zähler noch! Das ist das Schöne an Hardwaredesign und Parallelität. Alles läuft immer! Es kann zunächst schwierig sein, dies zu verstehen, aber es ist das Kernkonzept, das Sie beherrschen müssen.

Die Schalter dienen nur dazu, den zu verwendenden Ausgang auszuwählen. Sie bilden einen sogenannten Multiplexer. Ein Multiplexer oder kurz Mux ist ein Selektor, der aus einer Reihe von Eingängen einen auswählt, der an den Ausgang weitergegeben oder weitergegeben wird. Es ist ein kombinatorisches Stück Logik, was bedeutet, dass für den Betrieb keine Uhr erforderlich ist. Unten ist ein Blockdiagramm des Designs. Verbringen Sie einige Zeit damit, darüber nachzudenken, wie Sie dieses Design implementieren könnten. Versuchen Sie, den Code selbst zu schreiben. Die Art und Weise, für die ich mich entschieden habe, ist unten zu finden.

Blockdiagramm – LED-Blinkprogramm

VHDL-Code für das Design, tutorial_led_blink.vhd:

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-Code für das Design, tutorial_led_blink.v:

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 ({i_switch_1, i_switch_2}) // 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


VHDL

  1. C# Hello World – Ihr erstes C#-Programm
  2. Embedded Design mit FPGAs:Erstellen eines Projekts
  3. Vereinfachtes Design mit eingebetteter FPGA-Technologie
  4. So erstellen Sie Ihr erstes VHDL-Programm:Hallo Welt!
  5. Maximieren Sie Ihr Schmierölanalyseprogramm
  6. Verilog-Tutorial
  7. So entwerfen Sie ein vorbeugendes Wartungsprogramm für Ihre Ausrüstung
  8. 10 Hacks zur Verbesserung Ihres PM-Programms
  9. Ultiboard-PCB-Design-Tutorial
  10. KiCAD PCB-Design-Tutorial