Hallo! Ich bin ein absoluter Neuling, was VHDL angeht. Ich versuche
einen Zähler zu schreiben, damit ich eine LED zum blinken bringen kann.
Hier mein Versuch:
entity BlinkerSchaltung is
Port ( CLK : in std_logic;
LD4 : out std_logic);
end BlinkerSchaltung;
architecture Behavioral of BlinkerSchaltung is
signal divider : std_logic;
signal led : std_logic;
begin
process(CLK)
begin
if (CLK'event and CLK = '1') then
if divider = 0 then
divider <= 50000000;
LD4 <= led;
else
divider <= divider -1;
end if;
end if;
end process;
end Behavioral;
Das Starter Board hat ja an der Unterseite einen Quarz, der einen Takt
von 50MHz erzeugt, deswegen der Zähler, von 50000000 abwärts. Dann würde
die LED pro Sekunde einmal aufblinken. Also immer wenn der Zähler bei
Null ankommt. Ich entdecke meinen Denkfehler einfach nicht. Kann mir da
jemand weiterhelfen?
>Hallo! Ich bin ein absoluter Neuling,
Wenn ich mich nicht täusche bekommt dein signal led doch nirgends einen
Wert zugewiesen. Und stets nur "LD4 <= led;" macht doch auch keinen
Sinn. Nebenbei, statt Divider würde ich die Bezeichnung Counter
verwenden.
Ninn doch für den Anfang eines der zahlreichen Blinker-Beispiele aus den
Tutorials, hatte ich auch gemacht als ich mein erstes Board bekam.
>signal divider : std_logic;
OK, das ist natürlich auch Quatsch. Mit einem Bit kann man ja schlecht
einen Zähler bauen, also std_logic_vector, integer, signed oder unsigned
als sinnvollere Datentypen nehmen.
Wenn du die LED Toggeln willst solltest du wie schon erwähnt zumindest
dein Signal led am Anfang einen Wert zuweisen und dann würde ich das im
Code noch so abändern:
1
ifdivider=0then
2
divider<=50000000;
3
LD4<=led;
4
led<=notled;
5
else
6
divider<=divider-1;
7
endif;
Da ja immer erst nach dem Ende des Prozesses die Werte übergeben werden
übergibst du hier wenn der Zähler auf 0 ist den "alten" Wert von led und
speicherst dann den neuen Wert in led, der einfach nur invertiert ist.
Somit toggelt deine Led.
Gruß Phil
Hallo Michael,
hier der Code - so müsste es funktionieren...
entity BlinkerSchaltung is
Port ( CLK : in std_logic;
LD4 : out std_logic);
end BlinkerSchaltung;
architecture Behavioral of BlinkerSchaltung is
signal divider : integer range 0 to 50000000;
signal led : std_logic;
begin
process(CLK)
begin
if (CLK'event and CLK = '1') then
if divider = 0 then
divider <= 50000000;
led <= not led;
else
divider <= divider -1;
end if;
end if;
end process;
ld4 <= led;
end Behavioral;
damit es "sauber" wäre, wäre es noch sinvoll als 1. if bedingung einen
reset einzubauen. Und if clk'event and clk='1' als elsif danach
abzufragen... aber funktionieren tuts so auch..
so würde die led jetzt immer wenn die 50 mio abgelaufen wären ihren
zustand ändern...
Viel Glück damit :-)
Martin schrieb:
> damit es "sauber" wäre, wäre es noch sinvoll als 1. if bedingung einen> reset einzubauen. Und if clk'event and clk='1' als elsif danach> abzufragen... aber funktionieren tuts so auch..>> so würde die led jetzt immer wenn die 50 mio abgelaufen wären ihren> zustand ändern...>> Viel Glück damit :-)
Genau das ist nicht sauber weil das ein asynchroner Reset ist. Wenn
Reset dann synchron.
Außerdem wird 50.000.001 gezählt, also die Led toggelt 1s+20ns.
Vielen Dank für eure tollen Antworten. Ich denke so werde ich das
hinbekommen. Ich tue mich etwas schwer mit VHDL. Ich dachte eigentlich,
dass es mir mit meinen C Kenntnissen wesentlich einfacher fallen wird.
Aber nur Übung macht den Meister :-) . Danke nochmal...
Ich würde sogar soweit gehen, zu sagen, dass C-Kenntnisse eher ein
Hindernis beim Erlernen von VHDL sind. Viel besser ist, sich hinter dem
Quellcode immer FlipFlops und Gatter vorzustellen.
Hallo nochmal! Also hier habe ich dann jetzt den Zähler mit RST.
entity BlinkerSchaltung is
Port ( CLK : in std_logic;
RST : in std_logic;
LD4 : out std_logic);
end BlinkerSchaltung;
architecture Behavioral of BlinkerSchaltung is
signal divider : integer range 0 to 50000000;
signal led : std_logic;
begin
process(CLK, RST)
begin
if RST = '1' then
divider <= 50000000;
led <= '0'; -- mit '1' funktioniert es nicht.
else
if (CLK'event and CLK = '1') then
if divider = 0 then
divider <= 50000000;
led <= not led;
else
divider <= divider -1;
end if;
end if;
end if;
end process;
LD4 <= led;
end Behavioral;
So funktioniert die Schaltung einwandfrei, bei ISE bekommt man nur bei
dem Vorgang "synthesize xst" ein Ausrufezeichen. UNten im Reiter steht
aber nix. Hat das dann was zu bedeuten? Und oben bei led <= '0' ,ich
kann für den Reset keine 1 eingeben. Wisst ihr da vll eine Lösung?
Dass C und VHDL nichts gemeinsam haben, dachte ich mir. Ich ging einfach
nur davon aus, wenn man schon eine Programmiersprache relativ gut
beherrscht, sollte es wohl leichter fallen eine andere zu erlenen, als
wenn man noch nie etwas mit Progsprachen zu tun gehabt hätte.
Du solltest den Reset synchron machen, sieh dir dazu die Seite von
Lothar Miller an warum.
Zum Unterschied: Mag wohl daran liegen das C eine Programmiersprache ist
und VHDL eine Hardwarebeschreibungssprache
>Du solltest den Reset synchron machen,
Ich wüsste jetzt so spontan nicht warum...
>signal divider : integer range 0 to 50000000;
Mal so am Rande, das sind 50000000+1 Zustände, wenn man bei 50MHz Takt
eine Periode von exakt 1 Sekunde will benötigt man einen weniger.
@Michael Kremer
>beherrscht, sollte es wohl leichter fallen eine andere zu erlenen,
Ich würde an Deiner Stelle schon mal einen kurzen Blick in ein Buch
werfen, sonst bleibt es lange Stümperei. Wenn man die ersten 200 Seiten
vom Reichardt/Schwarz durch hat, so kennt man die Grundbegriffe. Viel
weiter bin ich leider auch noch nicht gekommen...
Daher verstehe ich auch nicht, warum es mit '1' nicht funkionieren
sollte.
>led <= '0'; -- mit '1' funktioniert es nicht.
Übrigens, deine Einrückungen sind sehr seltsam, könnte an Tabulatoren
liegen, die unterschiedlich behandelt werden, je nach Editor.
Wobei ich mich auch frage, wozu Reset, wenn es nur blinken soll, der
Anfangszustand also egal ist. Und warum überhaupt ein internes Signal
led?
Ich hätte es womöglich so probiert:
Ah halt, led wird gelesen und geschrieben, und wir wollen den Datentyp
buffer vermeiden, also doch ein internes Signal.
entity BlinkerSchaltung is
Port ( CLK : in std_logic;
LD4 : out std_logic);
end BlinkerSchaltung;
architecture Behavioral of BlinkerSchaltung is
signal divider : integer range 0 to (50000000-1);
signal led : std_logic;
begin
if (divider<0) or (divider>=50000000) then --ensure safe start
condition
divider <= '0';
end if;
process(CLK)
begin
if (CLK'event and CLK = '1') then -- if rising_edge(CLK)
if divider = 0 -- should take minimal resources
divider <= (50000000-1);
led <= not led;
else
divider <= divider - 1;
end if;
end if;
end process;
LD4 <= led;
end Behavioral;
Ohne Gewähr, wer mag mag es testen oder kommentieren.
>Eine sequentielle if-anweisung außerhalb eines prozesses scheint mir>fragwürdig und '0' kann man nicht an integer zuweisen
Ja klar, es muss
divider <= 0;
heißen.
Wobei ich mich momentan frage, wie man sonst für ein Signal bzw. einen
Zähler einen "sicheren" Anfangszustand gewährleisten kann, wenn man kein
RESET-Signal verwenden möchte.
Sollte
signal divider : integer range 0 to (50000000-1);
bereits gewährleisten, dass der Anfangswert in diesem Bereich liegt?
Ich meine mich zu errinnern, mal eine direkte Zuweisung eines
Anfangswertes gesehen zu haben, irgendwie signal x:integer <= 0; oder
so, aber das mag nur für die Simulation möglich sein. Ich finde es im
Buch gerade nicht, muss ich mal nachlesen...
Stefan Salewski schrieb:
> Wobei ich mich momentan frage, wie man sonst für ein Signal bzw. einen> Zähler einen "sicheren" Anfangszustand gewährleisten kann, wenn man kein> RESET-Signal verwenden möchte.
Du kannst einen Reset verwenden, jedoch sollte der synchron sein und
nicht asynchron. Also erst Clock abfragen und darin dann den reset als
erstes.
Alternativ kannst du auch eine FSM mit INIT state verwenden, so mache
ich das immer, wenn ich keinen reset von außen brauche
Autor: D. I. (grotesque)
Datum: 02.04.2010 19:45
>Eine sequentielle if-anweisung außerhalb eines prozesses scheint mir>fragwürdig
Richtig, Reichardt/Schwarz schreiben (3.6.1):
4. Signalen oder Variablen, denen innerhalb einer getakteten
if-Anweisung ein Wert so zugewiesen wird, dass sie zu D-Flipflops bzw.
Registern synthetisiert werden, darf außerhalb dieser getakteten
Anweisung kein Wert zugewiesen werden. Einzige Ausnahme ist die
Zuweisung eines asynchronen RESET- oder PRESET-Signals, welches vor der
getakteten if-Anweisung zugewiesen werden muss.
Wobei, irgendwie entspricht meine Initialisierung ja einem RESET?
>Du kannst einen Reset verwenden, jedoch sollte der synchron sein und>nicht asynchron. Also erst Clock abfragen und darin dann den reset als>erstes.
Also Reichardt/Schwarz machen gerne asynchrone RESETs, beispielsweise
bei ihrem 4-Bit-Binärzählers SN74xx161 (code 5-3, Seite 97, 4. Auflage)
und auch anderswo. Wobei, du machst ja durchaus recht haben...
>Alternativ kannst du auch eine FSM mit INIT state verwenden, so mache>ich das immer, wenn ich keinen reset von außen brauche
Ah ja, muss ich wohl auch noch mal nachlesen...
Stefan Salewski schrieb:
> Also Reichardt/Schwarz machen gerne asynchrone RESETs
Diese asynchrone Resetterei machte bei ASICs noch Sinn. Und es ist ja
auch durchaus eine gültige, sehr gängige, weit verbreitete und überall
unterrichtete VHDL-Schreibweise....
Aber bei der Synthese für FPGAs muß man eben auch und gerade die
Technologie mitbeschreiben, um ein gutes Design zu bekommen. Deshalb muß
den Synthesizer ein wenig "nach dem Maul" beschrieben werden. Gerade für
FFs gibt es bei Xilinx 2 Betreibearten: asynchron oder synchron. Wenn
du asynchron zurücksetzt, dann wird ein synchrones Laden automatisch in
erhöhtem Ressourcenbedarf resultieren. Dazu liest sich schön das öfters
erwähnte WhitePaper 272 von Xilinx:
http://www.xilinx.com/support/documentation/white_papers/wp272.pdf
Ich habe ein ähnliches Problem.
das signal "drehzahl" soll hochgezählt werden.
1
libraryIEEE;
2
useIEEE.std_logic_1164.all;
3
useieee.std_logic_arith.all;
4
useIEEE.NUMERIC_STD.ALL;
5
6
7
entityanlauf_stris
8
port(
9
clk:INSTD_LOGIC;
10
drehzahl_max:inSTD_LOGIC_VECTOR(7downto0);
11
drehzahl:outSTD_LOGIC_VECTOR(7downto0)
12
);
13
endanlauf_str;
14
15
architecturebehavioralofanlauf_stris
16
17
18
begin
19
20
process(clk)
21
variableanlauf:std_logic:='1';
22
variabledz_buff:STD_LOGIC_VECTOR(7downto0);-- buffer für signal-drehzahl
23
24
begin
25
26
ifdz_buff="11111111"then
27
anlauf:='0';
28
endif;
29
30
ifdz_buff="00000000"then
31
anlauf:='1';
32
endif;
33
34
ifanlauf='1'then
35
36
dz_buff:=dz_buff+1;
37
38
elsifanlauf='0'then
39
40
dz_buff:=dz_buff-1;
41
endif;
42
43
drehzahl<=dz_buff;-- dieses signal soll hochgezählt werden
44
endprocess;
45
46
47
endbehavioral;
Fehlermeldung:
1
found 0 definitions for operator "+".
ich habe jetz eine weile im Forum und über google nach lösungen gesucht
und bin nur auf die erklärung gestoßen, dass es an unterschiedlichen
datentypen der operanden liegen kann. Aber das ist doch nicht der fall.
Weeiß wer rat?
in Verbindung mit Rechenoperationen als Signaltyp "unsigned" benutzen.
Rechnen mit std_logic_vector geht mit anderen Bibliotheken, ist aber
nicht sauber. Mit
1
variabledz_buff:unsigned(7downto0);
sollte die Fehlermeldung erstmal behoben sein. Dein Prozess reagiert
aber auf positive und negative Flanken - solche FFs gibt es aber (mit
wenigen ausnahmen nicht). Du müsstest also in den Prozess noch ein
1
ifrising_edge(clk)
einbauen und deinen Code simulieren um zu gucken, was da eigentlich so
passiert.
Viele Grüße
Tobias
danny w. schrieb:> Ich habe ein ähnliches Problem.
Besten Dank auch. Da habe ich einen ganzen Thread gelesen, um zum
Schluss zu sehen, dass eine NEUE FRAGE angehängt wurde...
> Ich habe ein ähnliches Problem.
Du hast dir den vorgehenden Thread aber nicht durchgelesen!
> das signal "drehzahl" soll hochgezählt werden.
Alle Zähler brauchen einen Takt und Speicherelemente.
Entweder die hier:
> use IEEE.std_logic_1164.all;> use ieee.std_logic_arith.all;
Oder besser die:
> use IEEE.NUMERIC_STD.ALL;
Aber niemals beide zusammen!
Zu den Gründen such mal hier im Forum nach "std_logic_arith obsolete":
http://www.mikrocontroller.net/search?query=std_logic_arith+obsolete> variable dz_buff: STD_LOGIC_VECTOR(7 downto 0);> dz_buff:=dz_buff+1;
Mit Vektoren rechnet man nicht.
Dafür gibt es die Datentypen signed/unsigned und integer.
Zur ausdauernden und unnötigen Verwendung von Variablen lies mal den
Beitrag "Variable vs Signal"
Ich rate dir DRINGEND:
Lies das Buch VHDL-Synthese von Reichardt&Schwarz.
Du machst im Laufe deiner Beiträge tatsächlich JEDEN Fehler, der denkbar
ist... :-o
Das z.B., was du da oben beschrieben hast, nennt sich "kombinatorische
Schleife":
http://www.lothar-miller.de/s9y/categories/36-Kombinatorische-Schleife
xilinx gefrusteter schrieb:> Hast du schon mal VHDL gesehen, dass Xilinx SysGen produziert?
Die Welt ist nicht perfekt:
für den Microblaze werden sogar Vektoren mit (0 to 31) erzeugt... :-/