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:
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.