Hallo :)
wiedermal habe ich ein "kleines" Problem mit einer Hardwarebeschreibung.
Diesmal soll eine kleine Ampelschaltung realisiert werden. Die Ampel
soll zuerst nur die einzelnen Phasen durchlaufen, d.h.
1. Rot (Ausgangszustand) - dieser Zustand soll eine gewisse Zeit
gehalten werden.
2. Rot/Gelb - dieser Zustand soll nur einen Clocktakt anhalten.
3. Grün - dieser Zustand soll eine gewisse Zeit gehalten werden.
4. Gelb - auch dieser Zustand soll etwas länger andauern, jedoch kürzer
als die Grünphase.
Meine VHDL-Beschreibung:
1
Libraryieee;
2
useieee.std_logic_1164.all;
3
useieee.std_logic_unsigned.all;
4
5
entityAmpelis
6
generic(k:positive:=6);
7
port(clk:instd_logic;
8
lights:outstd_logic_vector(2downto0));
9
endAmpel;
10
11
12
13
architectureRTLofAmpelis
14
15
typestate_typeis(A,B,C,D);
16
17
signalstate:state_type;
18
19
signalNew_Clock:std_logic;
20
signalGlobalcount:integerrange0to15;
21
signalClear:std_logic;
22
23
begin
24
25
26
Takt:process(clk)-- 16 MHz zu 1 Hz
27
28
variablecounter:integerrange0to7999999:=0;
29
30
begin
31
32
ifrising_edge(clk)then
33
ifcounter=7999999then
34
New_Clock<=notNew_Clock;
35
counter:=0;
36
else
37
counter:=counter+1;
38
endif;
39
endif;
40
41
endprocessTakt;
42
43
44
45
46
Zaehler:process(New_Clock,Clear)
47
48
begin
49
50
ifClear='1'then
51
52
Globalcount<='0';
53
54
elsifrising_edge(New_Clock)then
55
56
Globalcount<=Globalcount+1;
57
58
endif;
59
60
endprocessZaehler;
61
62
63
64
65
FSM:process(Clk)
66
67
begin
68
69
70
ifrising_edge(clk)then
71
72
casestateis
73
74
whenA=>ifGlobalcount=kthen
75
State<=B;
76
else
77
State<=A;
78
endif;
79
80
whenB=>State<=C;
81
82
whenC=>ifGlobalcount=kthen
83
State<=D;
84
else
85
State<=C;
86
endif;
87
88
whenD=>ifGlobalcount=3then
89
State<=D;
90
else
91
State<=A;
92
endif;
93
endcase;
94
endif;
95
endprocessFSM;
96
97
98
99
100
Ampel_Zuweisung:
101
Lights<="100"when(State=A)else
102
"110"when(State=B)else
103
"001"when(State=C)else
104
"010"when(State=D)else
105
"111";
106
107
108
Clear_Zuweisung:?????
109
110
111
112
113
endRTL;
Wie man sieht habe ich ein Problem mit der Clear-Zuweisung, d.h.
Globalcount soll immer wieder auf 0 zurückgesetzt werden, sobald man in
einen neuen Zustand gelangt. Allerdings weiß ich einfach nicht, wie ich
dies machen soll! Clear soll also immer zu Beginn eines Zustandes auf
high gehen damit der Counter auf 0 gesetzt wird.
Oder ist das zu schwer gedacht? Seht ihr noch andere Probleme?
Vielen Dank für eure Mithilfe!
LG
Was ich mal von Beginn weg ändern würde: Alles mit dem schnellen Clock
takten (es gibt verschiedene Threads zum Thema hier drin).
Dann generierst Du beim Erreichen des jeweiligen Zählerstandes ein
Triggersignal, dass Dir die zu implementierende Ampel-FSM einen Zustand
weiter bringt.
Ein Clear brauchst Du nicht (schon gar kein asynchrones). Du setzt den
Zähler mit demselben Triggersignal zurück, wie Du die Ampel-FSM
weiterbringst.
Vielen Dank für deine Antwort! Leider "hinke" ich deiner Ausführung noch
etwas hinterher. Verstehe ich es richtig, dass du die 16 MHz-Clock
generell anwenden willst, d.h. mein Taktprozess würde entfallen. Aber so
etwas wie einen Counter muss ich doch integrieren, oder etwa nicht? Wie
soll dieses Triggersignal aussehen, ich kann mir da gerade nicht
wirklich etwas vorstellen? Wenn ich das richtig verstehe, müsste ich
dann eine komplett andere FSM entwickeln ?
Oder meinst du als Trigger vllt einen Counter, der bis zu einem gewissen
Wert hochläuft. Hat er diesen erreicht, wird dann per if-Abfrage die FSM
angesprochen. Neben der Aktivierung der FSM wird dann auch noch
zeitgleich der Counter zurückgesetzt. Allerdings verstehe ich nicht, wie
ich den Counter für die Zustandsdauer die Ampelphasen takten soll...mit
16 MHz zählt der ja ein bissel schnell ;).
Für den Zähler-Prozess würde ich keinen selbstgenerierten Takt verwenden
sondern ein Clock-Enable Signal, welches du im Takt-Prozess jeweils für
einen Takt setzt.
Etwa so:
Christian Klingler schrieb:> Allerdings weiß ich einfach nicht, wie ich dies machen soll!
Der pragmatische Ansatz wäre, alles im selben Prozess zu machen:
1
Zaehler:process(New_Clock,Clear)
2
3
begin
4
5
FSM:process(Clk)begin
6
7
ifrising_edge(clk)then
8
9
ifCLK_EN='1'then-- siehe Code von Alexander
10
Globalcount<=Globalcount+1;
11
endif;
12
13
casestateis
14
whenA=>ifGlobalcount=kthen
15
State<=B;
16
else
17
State<=A;
18
endif;
19
Globalcount<='0';
20
whenB=>State<=C;
21
22
whenC=>ifGlobalcount=kthen
23
State<=D;
24
else
25
State<=C;
26
endif;
27
Globalcount<='0';
28
29
whenD=>ifGlobalcount=3then
30
State<=D;
31
else
32
State<=A;
33
endif;
34
Globalcount<='0';
35
36
endcase;
37
endif;
38
endprocessFSM;
BTW:
Wenn schon States, warum nicht gleich sprechende:
1
Lights<=
2
"100"when(State=gruen)else
3
"110"when(State=rotgelb)else
4
"001"when(State=rot)else
5
"010"when(State=gelb)else
6
"111";
BTW2:
Wenn du schon alle States verwendet hast, dann brauchst du kein else
mehr, denn es wird schlicht&einfach ignoriert, weil es ja keinen
weiteren Zustand mehr gibt! Fazit:
Allerdings erhalte ich nun die folgenden Warnungend es
Synopsis-Compilers:
Pruning register CLK_EN
Register bit Count(0) is always 0, optimizing ...
|Register bit Count(1) is always 0, optimizing ...
Register bit Count(2) is always 0, optimizing ...
|Register bit Count(3) is always 0, optimizing ...
Found inferred clock Ampel|clk with period 5.00ns. Please declare a
user-defined clock on object "p:clk"
WARNING - ngdbuild: logical net 'clk' has no load
WARNING - ngdbuild: DRC complete with 1 warnings
So, ich denke das Problem in diesem Fall ist die count <= 0 Zuweisung.
Da ja alles parallel in der Hardware implementiert ist (oder?), ist
count immer 0. Das heißt, das zurücksetzen des Zählers muss ich anders
realisieren.
Christian Klingler schrieb:> So, ich denke das Problem in diesem Fall ist die count <= 0 Zuweisung.> Da ja alles parallel in der Hardware implementiert ist (oder?), ist> count immer 0.
Richtig, daran liegt es. Kleiner Fehler der Lothar unterlaufen ist, auch
Chuck Norris ist nicht perfekt :-)
Christian Klingler schrieb:> Das heißt, das zurücksetzen des Zählers muss ich anders> realisieren.
Einfach nur jeweils im if-Zweig in dem auf den nächsten State gewechselt
wird.
Okay es funktioniert...Stufe 2 :) Wie schwierig ist es jetzt, das
Durchlaufen einer Phase, mittels einem Taster auszulösen. Sprich, man
drückt auf einen Taster und die Ampel beginnt aus dem Zustand Rot die
verschiedenen anderen Zustände zu durchlaufen.
Die Schwierigkeit, die ich in diesem Fall sehe, ist die Erzeugung der
Bedingung, d.h. es muss ein drücken des Schalters detektiert werden,
vllt so: ?
1
Push:process(clk)
2
3
begin
4
5
ifrising_edge(clk)
6
7
ifButton=1andButton_old=0then
8
Button_Pushed<='1';
9
else
10
Button_Pushed<='0';
11
endif;
12
13
Button_old<=Button;
14
15
endif;
16
endprocessPush;
Und kann ich dann einfach noch eine If-Abfrage um count und um das
case-Statement packen?
Ähm..erfülle ich denn nicht genau diese beiden Aspekte mit meiner Idee?
Oder was genau meinst du mit "eintakten"?
Bezüglich der Entprellung...mal ganz naiv gefragt, entprelle ich den
Schalter nicht, da ich eine Flankenerkennung durchführe?
@ Lothar
ich habe mir jetzt einfach mal dein Beispiel mit dem Schieberegister
angeschaut, hätte aber noch zwei Fragen.
Mir ist auf der einen Seite die Funktion des Vorteilers noch nicht ganz
klar, warum wird dieser gebraucht?
Und zweitens ...inputsr <= inputsr(2 downto 0) & input;
Wie interpretiert der Compiler das? Ist Input dann das LSB ?
Vielen Dank!
Edit: Ich habe auf dieser Seite ein Beispiel für die Softwareentprellung
mittels reine Flankenerkennung gefunden, wie kann das dann
funktionieren? Da ja zB eine steigende Flanke mehrmals vorliegt?!
Der Vorteiler wird gebraucht, weil sonst bei 50 MHz das Schieberegister
in 80ns durch wäre. Ein Taster prellt sicher länger.
Der & Operator ist bei VHDL ein Verkettungsoperator, der input wird
daher zum LSB.