Inhaltsverzeichnis:

VHDL Basys3: Connect 4 Game - Gunook
VHDL Basys3: Connect 4 Game - Gunook

Video: VHDL Basys3: Connect 4 Game - Gunook

Video: VHDL Basys3: Connect 4 Game - Gunook
Video: 4.FPGA FOR BEGINNERS- Combining logic gates in VHDL (DIGILENT Basys3) 2024, November
Anonim
VHDL Basys3: Connect 4 Spiel
VHDL Basys3: Connect 4 Spiel

Einführung:

Dies ist ein Connect 4 Digital Logic Game, das in VHDL mit der Vivado-Software entwickelt und auf das Basys3-Board programmiert wurde. Der Aufbau und das Design dieses Projekts sind mittelschwer, aber Neulinge können die Schritte kopieren und das digitale Spiel bauen.

Das Spiel funktioniert wie das Spiel Connect 4. Die Spieler können ihren Cursor mit den linken und rechten Tasten auf dem Brett über den Bildschirm bewegen. Durch Drücken des mittleren Knopfes auf dem Brett setzt der Spieler seinen Marker auf diese Spalte und dann ist der nächste Spieler an der Reihe. Sobald ein Spieler gewonnen hat, kann das Spiel durch Drücken der Aufwärtstaste auf dem Brett zurückgesetzt werden.

Schritt 1: Schnelle Details und Materialien

Schnelle technische Details:

  • Verwendet drei Sätze der PMOD-Anschlüsse auf der Platine (JA, JB, JC)

    • 8 Pins (außer Vcc & GND Pins) für jeden PMOD-Anschluss verwendet
    • JA - Kontrolle von Reihen
    • JB - Kontrolle der grünen Säulen
    • JC - Kontrolle der roten Säulen
  • Bildschirmuhr arbeitet mit 960 Hz

    Nur 8 LEDs leuchten gleichzeitig. Der Bildschirm wird mit einer ausreichend schnellen Taktfrequenz aktualisiert, um die Illusion zu erwecken, dass mehr als 8 LEDs gleichzeitig leuchten

  • Tastentakt arbeitet mit 5 Hz; Optional kann durch Bearbeiten des VHDL-Codes verfeinert werden.
  • Der Innenwiderstand von Darlington Arrays reicht aus, um ein Durchbrennen der LED zu verhindern

Das Spiel besteht aus den folgenden Komponenten und Werkzeugen:

  • (1) Basys3-Platine
  • (2) LED-Matrix zweifarbig 8x5:
  • (2) ULN2803 - Darlington-Transistor-Arrays - Datenblatt
  • Drahtspulen
  • Überbrückungsdrähte
  • Abisolierzange
  • Steckbretter (großes Quadrat sollte ausreichen)
  • Multimeter und Netzteil (Fehlerbehebung)

Schritt 2: Anschließen der Hardware

Anschließen der Hardware
Anschließen der Hardware
Anschließen der Hardware
Anschließen der Hardware

Richtlinien:

Die Verkabelung des Projekts kann sehr kompliziert sein. Bitte nehmen Sie sich Zeit und überprüfen Sie, ob alle Verbindungen einzeln richtig sind.

Das Projekt beinhaltet die Verwendung von zwei LED-Bildschirmen, die jedoch zu einem großen Bildschirm kombiniert werden. Dies kann erreicht werden, indem alle Zeilen mit demselben Punkt verbunden werden. Da jeder Bildschirm zweifarbig ist, müssen die roten und grünen Reihen des einen Bildschirms auch mit den roten und grünen Reihen des anderen Bildschirms verbunden werden. Auf diese Weise können wir alle Reihen mit nur 8 Pins steuern. Die anderen 16 Pins werden verwendet, um die Anzeigespalten zu steuern. Die 8 Pins für die können direkt über Jumperkabel mit den pmod-Anschlüssen verbunden werden. Pmod-Anschlüsse gehen zuerst zum Eingang des ULN2083A und der Ausgang des ULN2083A wird direkt mit der Spalte auf dem Bildschirm verbunden. Da das Design ein 8x8-Design ist, werden einige Säulen physisch nicht verbunden.

  • JA: Reihenverbindungen: Reihe 1 bis JA:1 bis Reihe 8 für JA:10.
  • JA: Rote Säulenanschlüsse:
  • JC: Anschlüsse der grünen Säule

Bitte beachten Sie die geposteten Bilder, um zu erfahren, welche Pins welchen Zeilen/Spalten entsprechen.

Hinweis: Die Transistoren haben eingebaute Widerstände, so dass die LEDs keinen zusätzlichen Widerstand benötigen, um sie in Reihe zu schalten.

Schritt 3: Technische Erklärung: Bildschirm

Der Bildschirm arbeitet mit der Persistenz des Sehens. Der Bildschirm aktualisiert sich so schnell, dass das menschliche Auge das schnelle Aus- und Einschalten einiger LEDs nicht sichtbar erkennen kann. Tatsächlich kann man das Blinken bemerken, indem man die Anzeigeuhr verlangsamt.

Die Anzeige schaltet alle acht Zeilen entsprechend den für diese Zeilen gespeicherten Daten ein, und die Anzeige schaltet eine Spalte ein. Dann wechselt es schnell zum nächsten Dateneintrag für die acht Zeilen und schaltet die nächste Spalte ein – während alle anderen Spalten ausgeschaltet sind. Dieser Vorgang wird mit einer ausreichend schnellen Taktrate fortgesetzt, sodass das Flackern der LED nicht mehr wahrnehmbar wird.

Die Datenspeicherung für die Anzeige wird unmittelbar nach der Architektur in der VHDL-Datei wie folgt initialisiert:

Signal RedA, RedB, RedC, RedD, RedE, RedF, RedG, RedH: std_logic_vector (7 downto 0):= "00000000";

Signal GreenA, GreenB, GreenC, GreenD, GreenE, GreenF, GreenG, GreenH: std_logic_vector (7 downto 0):= "00000000"; -- Zeilendaten je nach Spalte: GRÜN

Im Folgenden ein kleiner Ausschnitt des Prozesses, der die LED-Anzeigematrix steuert.

-- Prozess, der die LED-Anzeige steuert Matrixdisplay: Prozess (ColCLK) -- 0 - 16 um sowohl die 8X8 RED als auch die 8x8 GREEn Matrixvariable zu aktualisieren RowCount: Ganzzahlbereich 0 bis 16:= 0; begin if (rising_edge(ColCLK)) then if (RowCount = 0) then DORow <= RedA; -- Zeilendaten für die entsprechende Spalte DOCool <= "1000000000000000"; -- Spaltentrigger -- Wiederholen Sie diesen Code bis hinunter zu "0000000000000001" -- Wechseln Sie zu RedB, RedC…GreenA, GreenB…GreenH

Am Ende des GreenH, kurz bevor der Prozess beendet wird, wird dieser Ausschnitt eingefügt, um den RowCount auf Null zurückzusetzen.

if (RowCount = 15) then -- Neustart der Auffrischung von Spalte A RowCount:= 0; sonst RowCount:= RowCount + 1; -- Shift durch Spalten end if;

Nun, um die Uhr zu erklären, die sich in der Empfindlichkeitsliste des Anzeigeprozesses befindet. Das Basys3-Board verfügt über eine interne Uhr, die mit 100 MHz arbeitet. Für unsere Zwecke ist dies ein zu schneller Takt, daher müssen wir diesen Takt mit dem folgenden Verfahren auf einen 960-Hz-Takt aufteilen.

-- Taktprozess mit 960 HzCLKDivider: Prozessvariable (CLK) clkcount: Ganzzahlbereich 0 bis 52083:= 0; begin if (rising_edge(CLK)) then clkcount:= clkcount + 1; if (clkcount = 52083), dann ColCLK <= not(ColCLK); Klickzähler:= 0; Ende, wenn; Ende, wenn; Prozess beenden;

Schritt 4: Technische Erklärung: Ändern der angezeigten Informationen

Technische Erklärung: Ändern der angezeigten Informationen
Technische Erklärung: Ändern der angezeigten Informationen

Im VHDL-Code werden die Informationen oder Daten, die auf dem Bildschirm angezeigt werden, durch den Cursorprozess gesteuert, der eine andere Uhr in seiner Empfindlichkeitsliste hat. Dieser Code wurde BtnCLK genannt, eine Uhr, die entwickelt wurde, um das Debouchen der Tasten beim Drücken zu minimieren. Dies ist enthalten, damit sich der Cursor in der obersten Zeile nicht sehr schnell über die Spalten bewegt, wenn eine Schaltfläche gedrückt wird.

-- Taktprozess arbeitet mit 5 Hz. ButtonCLK: Prozessvariable (CLK) btnclkcount: Ganzzahlbereich 0 bis 10000001:= 0; begin if (rising_edge(CLK)) then if (btnclkcount = 10000000) then btnclkcount:= 0; BtnCLK <= nicht(BtnCLK); sonst btnclkcount:= btnclkcount + 1; Ende, wenn; Ende, wenn; Prozess beenden;

Mit der BtnCLK-Signalausgabe dieses Prozesses können wir nun den Cursor-Prozess erklären. Der Cursorprozess hat nur BtnCLK in seiner Sensitivitätsliste, aber im Codeblock wird der Zustand der Schaltflächen überprüft und dies führt dazu, dass sich die Daten für RedA, RedB…GreenH ändern. Hier ist ein Ausschnitt des Cursor-Codes, der den Reset-Block und den Block für die erste Spalte enthält.

Cursor: Prozessvariable (BtnCLK) OCursorCol: STD_LOGIC_VECTOR (2 bis 0):= "000"; -- OCursorCol verfolgt die vorherige Spaltenvariable NCursorCol: STD_LOGIC_VECTOR (2 bis 0):= "000"; -- NCursorCol setzt neue Cursor-Spalte beginnen --RESET-Bedingung (UP-Taste) --Board wird gelöscht, damit das Spiel neu gestartet wird if (rising_edge(BtnCLK)) then if (RST = '1') then RedA <= "00000000"; RedB <= "00000000"; RedC <= "00000000"; RedD <= "00000000"; RedE <= "00000000"; RedF <= "00000000"; RedG <= "00000000"; RotH <= "00000000"; GrünA <= "00000000"; GrünB <= "00000000"; GrünC <= "00000000"; GrünD <= "00000000"; GrünE <= "00000000"; GrünF <= "00000000"; GrünG <= "00000000"; GreenH if (Lbtn = '1') then NCursorCol:= "111"; -- Spalte H elsif (Rbtn = '1') dann NCursorCol:= "001"; -- Spalte B elsif (Cbtn = '1') dann NCursorCol:= OCursorCol; -- Spalte bleibt gleich NTurnState <= not(TurnState); -- Löst den Zug des nächsten Spielers aus -- Prüft die aktuelle Spalte von unten nach oben und schaltet die erste LED ein, die nicht leuchtet. Die Farbe hängt von der Cursorfarbe des aktuellen Spielers ab. for ck in 7 downto 1 loop if (RedA(0) = '1') und (RedA(ck) = '0') und (GreenA(ck) = '0') dann RedA(Ck) <= '1'; RotA(0) <= '0'; AUSFAHRT; Ende, wenn;

if (GreenA(0) = '1') und (RedA(ck) = '0') und (GreenA(ck) = '0') dann

GrünA(Ck) <= '1'; GreenA(0) -- Roter Spieler GreenA(0) <= '0'; if (NCursorCol = OCursorCol) then -- Wenn nichts gedrückt wurde RedA(0) <= '1'; elsif (NCursorCol = "111") then -- Wenn Lbtn gedrückt wurde RedH(0) <= '1'; RotA(0) <= '0'; elsif (NCursorCol = "001") then -- Iff Rbtn wurde gedrückt RedB(0) <= '1'; RedA(0) -- Grüner Spieler RedA(0) <= '0'; if (NCursorCol = OCursorCol) then GreenA(0) <= '1'; elsif (NCursorCol = "111") dann GreenH(0) <= '1'; GrünA(0) <= '0'; elsif (NCursorCol = "001") then GreenB(0) <= '1'; GrünA(0) <= '0'; Ende, wenn; Endfall;

Beachten Sie, dass die erste case-Anweisung mit dem Namen: OCursorCol (was für Old Cursor Column steht) der Anfang des endlichen Automaten ist. Jede Spalte der Anzeige wird im FSM als eigener Zustand behandelt. Es gibt 8 Spalten, daher wurde ein 3-Bit-Binärzahlensatz verwendet, um jede Spalte als einen Zustand zu identifizieren. Wie sich das FSM zwischen den Zuständen bewegt, hängt von der gedrückten Taste ab. Wenn im obigen Ausschnitt die linke Taste gedrückt wird, bewegt sich das FSM zu "111", was die letzte Spalte der Anzeige wäre. Wenn die rechte Taste gedrückt wird, bewegt sich das FSM zu "001", was die zweite Spalte des Displays wäre.

Wenn die mittlere Taste gedrückt wird, wechselt der FSM NICHT in einen neuen Zustand, sondern löst stattdessen eine Änderung des TurnState-Signals aus, das ein Ein-Bit-Signal ist, um zu notieren, welcher Spieler an der Reihe ist. Darüber hinaus führt die mittlere Schaltfläche einen Codeblock aus, der überprüft, ob ganz unten bis ganz oben eine leere Zeile vorhanden ist. Es wird versucht, einen Marker in die unterste, nicht gefüllte Reihe zu setzen. Denken Sie daran, dies ist ein Connect-Four-Spiel.

In der verschachtelten Case-Anweisung TurnState ändern wir die Cursorfarbe und die Spalte in der ersten Zeile, für die wir die Daten ändern möchten, damit der Anzeigeprozess die Änderung widerspiegeln kann.

Wir wiederholen diesen grundlegenden Code für die verbleibenden sieben Fälle. Das FSM-Diagramm kann hilfreich sein, um zu verstehen, wie sich die Zustände ändern.

Schritt 5: Code

Code
Code

Dies ist der Funktionscode für Connect 4, der mit der Vivado-Software in VHDL kompiliert werden kann.

Es wird auch eine Einschränkung bereitgestellt, damit Sie das Spiel zum Laufen bringen können.

Wir haben ein Blockdiagramm bereitgestellt, das erklärt, wie die Ein- und Ausgänge jedes Prozesses miteinander verbunden sind.

Empfohlen: