Eine Schaltung mit blinkender LED

Hier ist der fertige Code bei der die LED mit ca. 1 Hz blinkt:

library ieee;
	use ieee.std_logic_1164.all;
	use ieee.numeric_std.all;
	use ieee.std_logic_unsigned.all ;

--! Toggle a LED
entity BlinkingLed is
	port (
		CLK100MHZ 	: in  std_logic; --! 100 MHz system clock
		BTN 		: in  std_logic_vector(3 downto 0); --! Button inputs, high active
		LED 		: out std_logic --! LED output, high active
	);
end BlinkingLed;

--! Toggle a LED
architecture RTL of BlinkingLed is

-- ============================================================================
-- signal declarations
-- ===================

-- reset
signal GenInitR 		: std_logic := '1'; 			--! Causes an init pulse after power on
signal InitC			: std_logic;					--! Synchronous reset condition
signal InitR			: std_logic;					--! Synchronous reset

-- input and output
signal Clk				: std_logic;					--! Internal processing clock

-- counter
signal ToggleCntR		: std_logic_vector(26 downto 0);	--! Generate main time base

begin

-- clock generation
	Clk 	<= CLK100MHZ;

	--! Simple Flip-Flops
	p_simple : process (Clk)
	begin
		if rising_edge(Clk) then
			GenInitR	<= GenInitR and not InitR;	-- Release InitR after it was activated
			InitR		<= InitC;
		end if;
	end process;

	InitC				<=	GenInitR;				-- Reset on power on

	--! Flip-Flops with synchronous reset
	p_sync : process (Clk)
	begin
		if rising_edge(Clk) then
			if (InitR = '1') then
				ToggleCntR		<= (others => '0');
			else
				ToggleCntR		<= ToggleCntR + 1;
			end if;
		end if;
	end process;
	LED <= ToggleCntR(26);

end RTL;

Was macht die Schaltung?

Unsere Schaltung lässt eine LED mit etwa 1 Hz blinken, also ungefähr einmal pro Sekunde (0,5 Sekunden an, 0,5 Sekunden aus). Wir haben:  

  • Einen Takt (CLK100MHZ), der 100 Millionen Mal pro Sekunde tickt (100 MHz).  
  • Einen Taster-Eingang (BTN), der später für Reset oder andere Funktionen genutzt werden kann.  
  • Eine LED (LED), die blinken soll.

Die Schaltung benutzt einen 26-Bit-Zähler, um den schnellen 100 MHz Takt in einen langsamen 1 Hz Takt umzuwandeln. Außerdem gibt es einen Reset-Mechanismus, der sicherstellt, dass die Schaltung nach dem Einschalten sauber startet.

1. Der Takt und die Eingänge  

  • CLK100MHZ ist unser Takt, der 100 MHz schnell ist. Das bedeutet, er tickt 100 Millionen Mal pro Sekunde – viel zu schnell, um eine LED sichtbar blinken zu lassen! Deshalb brauchen wir einen Zähler, um den Takt zu verlangsamen.  
  • BTN ist ein std_logic_vector(3 downto 0), also 4 Bits, die 4 Taster repräsentieren können (Taster 0 bis 3). In dieser Schaltung benutzen wir die Taster noch nicht, aber sie sind da, falls wir sie später brauchen.  
  • LED ist der Ausgang, der die LED steuert („1“ = an, „0“ = aus).

2. Der Zähler (ToggleCntR)

Der Zähler ToggleCntR ist ein 26-Bit-Zähler, also ein std_logic_vector(26 downto 0). Er zählt bei jedem Takt (jeder steigenden Flanke von Clk) um 1 hoch:  

  • Er startet bei 0 ("000...0", 27 Bits).  
  • Bei jedem Takt wird er um 1 erhöht, bis er den maximalen Wert erreicht.

Die LED ist direkt mit dem obersten Bit des Zählers verbunden:

LED <= ToggleCntR(26);
  • ToggleCntR(26) ist das höchste Bit (Bit 26) des Zählers.  
  • Ein std_logic_vector(26 downto 0) hat 27 Bits (von 0 bis 26). Das bedeutet, der Zähler zählt von 0 bis 227−1=134.217.727.
  • Wenn wir bis 134.217.727 zählen, dauert das bei 100 MHz:
    134.217.728÷100.000.000=1,34217728 Sekunden.
  • Jedes Mal, wenn der Zähler den Maximalwert erreicht, wird ToggleCntR(26) von „1“ zu „0“ (oder umgekehrt), weil der Zähler zurück auf 0 springt. Das passiert alle 1,342 Sekunden, also blinkt die LED mit einer Frequenz von:
    1/1,34217728≈0,745 Hz, was etwas langsamer als 1 Hz ist.

3. Der Reset-Mechanismus (GenInitR, InitC, InitR)

Die Schaltung hat einen Reset-Mechanismus, der sicherstellt, dass der Zähler nach dem Einschalten bei 0 startet. Schauen wir uns das genauer an:

Reset Timing

GenInitR ist ein Signal, das nach dem Einschalten „1“ ist (:= '1'). Das bedeutet, die Schaltung startet mit einem Reset.

InitC ist ein kombinatorisches Signal (C am Ende), das direkt mit GenInitR verbunden ist:

InitC <= GenInitR;

Es sagt: „Solange GenInitR ‚1‘ ist, soll ein Reset ausgelöst werden.“  

InitR ist ein getaktetes Signal (R am Ende), das den Reset speichert:

InitR <= InitC;

GenInitR wird zurückgesetzt, sobald der Reset aktiv war: 

GenInitR <= GenInitR and not InitR;

Das bedeutet: Sobald InitR „1“ wird (nach dem ersten Takt), wird GenInitR auf „0“ gesetzt, und der Reset ist vorbei.

Im Zähler-Prozess wird der Reset benutzt:

if (InitR = '1') then
    ToggleCntR <= (others => '0');
else
    ToggleCntR <= ToggleCntR + 1;
end if;

Wenn InitR = '1', wird der Zähler auf 0 gesetzt ((others => '0')).

Sonst wird der Zähler bei jedem Takt um 1 erhöht.

Zusammenfassung des Resets: Nach dem Einschalten sorgt GenInitR dafür, dass der Zähler auf 0 gesetzt wird. Danach wird der Reset deaktiviert, und der Zähler zählt normal weiter.

4. Wie blinkt die LED?  

  • Der Zähler ToggleCntR zählt von 0 bis 134.217.727 (maximaler Wert eines 27-Bit-Zählers).  
  • Das dauert 1,342 Sekunden bei 100 MHz.  
  • Das höchste Bit ToggleCntR(26) wechselt alle 0,671Sekunden zwischen „0“ und „1“, weil:  
    • Für die ersten 67.108.864 Ticks (0 bis 226−1) ist ToggleCntR(26) = '0'.  
    • Für die nächsten 67.108.864 Ticks (von 226 bis 227−1) ist ToggleCntR(26) = '1'.  
    • Danach springt der Zähler zurück auf 0, und es beginnt von vorne.

Die LED blinkt also mit etwa 0,745 Hz (1,342 Sekunden pro Periode), was etwas langsamer als 1 Hz ist.

Weiter zu Schritt 2.