Forum: FPGA, VHDL & Co. Uhr Beschreiben


von Flo S. (tuxianer)


Lesenswert?

Hallo,

nach dem ich mich jetzt ein wenig mit der Entwicklungsumgebung vertraut 
gemacht habe, möchte ich neben dem VHDL lernen an sich, auch nebenbei 
ein kleines Projekt anfangen. Für den Anfang hätte ich da an eine Uhr 
gedacht.
Leider bin ich noch nicht so mit der Herangehensweise der FPGA 
Entwicklung vertraut.
Ich habe mir das jetzt grob so überlegt. Mir stehen 4 7-Segment anzeigen 
zur Verfügung. Davon würde ich je zwei zusammenfassen, und diese zwei 
wiederum in ein Modul "Anzeige" packen. Dieses Modul bietet 2 Eingänge 
an (5 und 6 Bit breit).
Die Uhr als solche würde ich dann wieder in ein extra Modul packen und 
dort dann die anfallenden "Berechnungen" durchführen. Und damit die 
Anzeige ansteuern.
Die Sekunden würde ich binär über LEDs ausgeben.
Was haltet ihr von dem Ansatz, oder habt ihr noch bessere Vorschläge?

Viele Grüße

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florentin S. schrieb:
> habt ihr noch bessere Vorschläge?
Zähl jede Stelle einzeln...

> Mir stehen 4 7-Segment anzeigen zur Verfügung.
Also Stunder 10er, Stunden 1er sowie Minuten 10er und 1er.
Also würde ich einfach die Minuten 1er hochzählen bis zum Überlauf, dann 
die Minuten 10er usw.
Dann hast du nicht die (recht aufwendige) Trennung in 10er und 1er 
Stellen extra zu machen...

> Und damit die Anzeige ansteuern.
Ist die Anzeige gemultiplext?

von Flo S. (tuxianer)


Lesenswert?

Die vier 7-Segment Anzeigen sind gemultiplext. Deswegen war es ja meine 
Idee, die Anzeigenansteuerung, und die eigentliche Uhr zu separieren.

Also würdest du vorschlagen, die Ansteuerung der Anzeigen, und die Uhr 
quasi in eine Architektur zu packen, und dort immer nur die Stellen bis 
zum Überlauf zählen?

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

So ich habe mich gerade mal an die Ansteuerung der gemultiplexten 
7-Segment Anzeige gemacht, und vermutlich alles falsch gemacht, was man 
als Anfänger nur falsch machen kann :-).
Der Code ist im Anhang.

von D. I. (Gast)


Angehängte Dateien:

Lesenswert?

Schonmal garnicht so schlecht.

Man sollte nur nicht mehr die alten Libs verwenden.

Hier ein Vorschlag von mir

von Flo S. (tuxianer)


Lesenswert?

D. I. schrieb:
> Man sollte nur nicht mehr die alten Libs verwenden.

Ok. Da ist wohl mein Buch nicht mehr ganz auf dem neusten Stand. Was 
wären denn hier die aktuellen?

D. I. schrieb:
> Hier ein Vorschlag von mir

Danke. Aber da sind leider noch zu viele Sachen dabei, die ich noch 
nicht kenne. Da muss ich mich erst einmal weiter mit der Theorie 
beschäftigen.

Noch eine Allgemeine Frage, bezogen auf den Code von mir. Ich habe ja 
jetzt für jede Anzeige ein Eingangssignal inpx. Nun würde ich gerne noch 
ein Modul "Zeitgeber" o.ä. anlegen, der die Stellen durch zählt, und 
dann den Zeitgeber und die Anzeige beispielsweise im Modul "Uhr" 
instanziieren.

Dazu ein paar Fragen. Muss ich für jedes entity samt architecture eine 
eigene Datei anlegen?
Dem "Zeitgeber" würde ich erst einmal 4 Ausgangsports geben. Diese 
möchte ich zum testen erst einmal mit konstanten Werten belegen. Das 
hatte auch geklappt. Nur irgendwie gab es ein Problem mit der Modul 
"Uhr", in dem ich die beiden Sachen  instanziiert und verbunden habe.
Könnte mir eventuell jemand dafür eine Grobstruktur geben? Ich werde es 
jetzt auch noch einmal probieren, und dann den Code hier posten.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florentin S. schrieb:
> Ok. Da ist wohl mein Buch nicht mehr ganz auf dem neusten Stand.
Ja, das ist schade, was da so alles an Literatur herumgrukt.
Und auch was an manchen Hochschulen so gelehrt wird...

Florentin S. schrieb:
> Dazu ein paar Fragen. Muss ich für jedes entity samt architecture eine
> eigene Datei anlegen?
Nein, du kannst das alles
(jeweils ab library IEEE; use IEEE.STD_LOGIC_1164.ALL; ...)
in eine einzige Datei packen. Aber idR. ist es sinnvoller, genau das 
nicht zu tun. Denn die Dateien werden doch sowieso von der IDE 
verwaltet...

BTW:
    AN0,AN1,AN2,AN3: inout std_logic;
Es ist nur Faulheit ein inout oder einen buffer zu verwenden, 
damit sich das Signal zurücklesen lässt. Aber (!) inout und buffer 
haben eigentlich eine gänzlich andere Funktion!!! Du wirst damit früher 
oder später auf die Nase fallen...

Besser wäre es, ein internes Signal zu definieren, und an den Ports nur 
in und out zu verwenden!

Hier mal dein Code überarbeitet:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity twoseven is
6
  port(
7
    CLOCK: in std_logic;
8
    AN0,AN1,AN2,AN3: out std_logic;
9
    inp0,inp1,inp2,inp3: in std_logic_vector(3 downto 0);
10
    LED: out std_logic_vector(6 downto 0));
11
end twoseven;
12
13
architecture Anzeige of twoseven is
14
signal stelle : integer range 0 to 3;
15
signal counter : integer range 0 to 50000; --- anpassen
16
signal code: std_logic_vector(3 downto 0);
17
begin
18
  Multiplex: process(CLOCK)
19
  begin
20
    if rising_edge(CLOCK) then
21
      if(counter < 500000) then
22
        counter<=counter+1;
23
      else
24
        counter<=0;
25
        if (stelle<3) then
26
           stelle <= stelle+1;
27
        else
28
           stelle <= 0;
29
        end if;
30
      end if;
31
    end if;
32
  end process;
33
  
34
  Stellenauswahl: process(code)
35
  begin
36
    AN0<='1'; -- erst mal alle deaktivieren
37
    AN1<='1';
38
    AN2<='1';
39
    AN3<='1';
40
    case Stelle is
41
      when 0 => AN0<='0';
42
                code<=inp0;
43
      when 1 => AN1<='0';
44
                code<=inp1;
45
      when 2 => AN2<='0';
46
                code<=inp2;
47
      when 3 => AN3<='0';
48
                code<=inp3;
49
    end case;
50
  end process;
51
52
  Anzeigen: process(code)
53
  begin
54
    case code is
55
      when "0000" => LED <="1000000"; --0
56
      when "0001" => LED <="1111001"; --1
57
      when "0010" => LED <="0100100"; --2
58
      when "0011" => LED <="0110000"; --3
59
      when "0100" => LED <="0011001"; --4
60
      when "0101" => LED <="0010010"; --5
61
      when "0110" => LED <="0000010"; --6
62
      when "0111" => LED <="1111000"; --7
63
      when "1000" => LED <="0000000"; --8
64
      when "1001" => LED <="0010000"; --9
65
      when others => LED <="0000110"; -- Error
66
    end case;
67
  end process;
68
    
69
end Anzeige;

von Flo S. (tuxianer)


Lesenswert?

Lothar Miller schrieb:
> Hier mal dein Code überarbeitet:

Danke ich arbeite den gerade mal durch. Nur eine kurze Frage schon mal:
1
  Stellenauswahl: process(code)

Wieso ist hier code in der sensitivity list? Müsste da nicht Stelle und 
die inpx rein?

von D. I. (Gast)


Lesenswert?

Florentin S. schrieb:
> Lothar Miller schrieb:
>> Hier mal dein Code überarbeitet:
>
> Danke ich arbeite den gerade mal durch. Nur eine kurze Frage schon mal:
>
>
1
  Stellenauswahl: process(code)
>
> Wieso ist hier code in der sensitivity list? Müsste da nicht Stelle und
> die inpx rein?

ja

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florentin S. schrieb:
> Müsste da nicht Stelle und die inpx rein?
Ja. Sch3155 Copy&Paste... ;-)

von Flo S. (tuxianer)


Lesenswert?

So jetzt scheitert es an der vernetzung der Module und deren 
Organisation im ISE.

Also ich habe jetzt eine Anzeige.vhd. Die kennt ihr ja schon. Dann eine 
Zeitgeber.vhd. Ausschnitt:
1
entity timer is
2
  Port(
3
    CLOCK: in std_logic;
4
    out0,out1,out2,out3: out std_logic_vector(3 downto 0)
5
    );
6
end timer;
7
8
architecture Zeitgeber of timer is
9
begin
10
  Refresh: process (CLOCK)
11
  begin
12
    out0<="0000";
13
    out1<="0001";
14
    out2<="0010";
15
    out3<="0011";
16
  end process;
17
18
end Zeitgeber;

Dann die Uhr.vhd:
1
entity struktur is
2
  port(
3
    CLOCK: in std_logic
4
  );
5
end struktur;
6
7
architecture Uhr of struktur is
8
9
component timer
10
  Port(
11
    CLOCK: in std_logic;
12
    out0,out1,out2,out3: out std_logic_vector(3 downto 0)
13
  );
14
end component;
15
16
component twoseven
17
  port(
18
    CLOCK: in std_logic;
19
    AN0,AN1,AN2,AN3: out std_logic;
20
    inp0,inp1,inp2,inp3: in std_logic_vector(3 downto 0);
21
    LED: out std_logic_vector(6 downto 0));
22
end component;
23
Signal con0,con1,con2,con3: std_logic_vector(3 downto 0);
24
begin
25
  Geber : timer
26
  port map(CLOCK,con0,con1,con2,con3);
27
  Anzeiger : twoseven
28
  port map(CLOCK=>CLOCK,inp0=>con0,inp1=>con1,inp2=>con2,inp3=>con3);
29
end Uhr;

Und eine Constraints.ucf (war bisher der Anzeige zugeordnet):
1
NET "AN0"  LOC = "D14"  ;
2
NET "AN1"  LOC = "G14"  ;
3
NET "AN2"  LOC = "F14"  ;
4
NET "AN3"  LOC = "E13"  ;
5
NET "CLOCK"  LOC = "T9"  ;
6
NET "LED<0>"  LOC = "E14"  ;
7
NET "LED<1>"  LOC = "G13"  ;
8
NET "LED<2>"  LOC = "N15"  ;
9
NET "LED<3>"  LOC = "P15"  ;
10
NET "LED<4>"  LOC = "R16"  ;
11
NET "LED<5>"  LOC = "F13"  ;
12
NET "LED<6>"  LOC = "N16"  ;

Wie organisiere ich diese jetzt am besten? Anscheinend ist eine *.ucf 
immer nur einem Modul zugeordnet. Die Definitionen hier sind ja bis auf 
den CLOCK alle für die Anzeige gedacht. Aber wo bringe ich dann den 
Clock unter?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florentin S. schrieb:
> Anscheinend ist eine *.ucf immer nur einem Modul zugeordnet.
Machs dir am Anfang einfach und verwende nur 1 ucf-Datei. Diese word dem 
"obersten" Modul zugeorndet, das alle Anschlüsse zur Aussenwelt hat.

Dieser Top-Level dürfte die UHR sein, denn dort geht ja der Takt rein. 
Also müssen dort auch die LEDs rausgehen:
1
entity struktur is
2
  port(
3
    CLOCK: in std_logic;
4
    AN0,AN1,AN2,AN3: out std_logic;
5
    LED: out std_logic_vector(6 downto 0))
6
  );
7
end struktur;
8
:
Und diesem Modul wird die UCF-Datei zugeordnet, denn genau dort hast du 
ja die Portnamen wie auch in der UCF-Datei...

Und auf einmal kannst du die bisher unverdrahteten Ports deines Anzeige 
auch noch verdrahten:
  Anzeiger : twoseven
  port map(CLOCK=>CLOCK,inp0=>con0,inp1=>con1,inp2=>con2,inp3=>con3,
           AN0=>AN0,AN1=>AN1,AN2...,LED=>LED);

BTW:
  Geber : timer
  port map(CLOCK,con0,con1,con2,con3);
Mach das besser wie in der anderen Port-Liste nicht nach Position, 
sondern mit expliziten Namen (wie im Anzeiger:twoseven auch).

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

Ok danke. Das habe ich jetzt mal gemacht, und jetzt meckert die IDE zu
mindestens nicht mehr herum. Allerdings wird jetzt auf der Anzeige
irgendwas ausgegeben, was sich ändert, wenn ich die Buttons auf dem
Board betätige.
Folglich scheint es irgendwo noch ein Problem zu geben, und die
Anschlüsse "hängen scheinbar in der Luft".
Hast du eine Idee, woran das liegen kann? Funktioniert der Zeitgeber so,
wie ich mir das gedacht habe? Eigentlich müssten da ja konstante Werte
auf den Ports liegen.
Die aktuelle Uhr.vhd ist im Anhang.

von Flo S. (tuxianer)


Lesenswert?

Ok. Jetzt scheint alles zu funktionieren. Anscheinend war irgendetwas in 
der IDE faul. Nach einem Project Clean funktioniert alles wie gewollt.

Jetzt würde mich noch interessieren, wie man einen möglichst genauen 1Hz 
Takt erzeugt. Hat dafür jemand Tipps? Nimmt man dafür auch einfach einen 
Zähler, und zählt diesen bis 50*10^6 hoch (Mein Board arbeitet mit 50 
MHz), oder gibt es da elegantere Varianten?

von Flo S. (tuxianer)


Angehängte Dateien:

Lesenswert?

Hier die aktuelle Zeitgeber.vhd. Es werden die Sekunden und die Minuten 
auf der Anzeige ausgegeben(besser zum testen :-)).
Als nächstes werde ich versuchen die Sekunden binär über ein paar LEDs 
ausgeben zu lassen, und im Takt dazu den Trennpunkt der Anzeige blinken 
zu lassen.
Als nächstes geht es dann an die Benutzereingabe, damit man die Uhr auch 
stellen kann.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florentin S. schrieb:
> Nimmt man dafür auch einfach einen Zähler, und zählt diesen
> bis 50*10^6 hoch (Mein Board arbeitet mit 50 MHz),
Jain...
Korrekt wäre: man zählt 50000000 Takte. Das sind von 0...49999999
1
:
2
signal counter : integer range 0 to 50000000-1;
3
:
4
      if (counter<50000000-1) then
5
        counter<=counter+1;
6
      else
7
        counter<=0;
8
   :
Übrigens ein immer wieder gern gemachter Fehler....   ;-)

von Flo S. (tuxianer)


Lesenswert?

Lothar Miller schrieb:
> Übrigens ein immer wieder gern gemachter Fehler....   ;-)

Oh ja ich vergaß. Die Informatiker fangen ja bei 0 an mit zählen :-).

Beim einbauen des blinkenden Punktes sind mir gleich noch ein paar 
Sachen aufgefallen.
Wenn man die Schnittelle im entity verändert muss man diese ja auch in 
allen Architekturen ändern, in denen das entity über ein component 
eingebunden ist. Das ist ja nicht gerade wartungsfreundlich. Gibt es da 
einen Trick, oder muss man das einfach hinnehmen?
Des Weiteren hat mein Geber als Output nur einen Punkt. In das Interface 
der Anzeige habe ich jedoch alle 4 Punkte eingebaut, da man die Anzeige 
so ja auch für evtl. andere Projekte nutzen kann. Wie handhabt man am 
elegantesten die nicht genutzten Ports(also die am Eingang der Anzeige). 
Im Moment habe ich in der Anzeigen Schnittstelle, und auch beim 
einbinden via component, die Ports mit einem Standard Wert belegt. Beim 
Port Map habe ich diese Ports auf open gelegt. Trotzdem zeigt die IDE 
noch Warnungen an. Also kann das scheinbar noch nciht ganz optimal sein.

von D. I. (Gast)


Lesenswert?

Florentin S. schrieb:
> Wenn man die Schnittelle im entity verändert muss man diese ja auch in
> allen Architekturen ändern, in denen das entity über ein component
> eingebunden ist. Das ist ja nicht gerade wartungsfreundlich. Gibt es da
> einen Trick, oder muss man das einfach hinnehmen?

Sigasi VHDL Eclipse Plugin, dann geht das über Refactoring.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florentin S. schrieb:
> Wenn man die Schnittelle im entity verändert muss man diese ja auch in
> allen Architekturen ändern, in denen das entity über ein component
> eingebunden ist. Das ist ja nicht gerade wartungsfreundlich.
Abgesehen von irgendwelchen Managementsystemen ist das wie in einem 
C-Programm: wenn du dort z.B. eine Funktionsdeklaration änderst, mußt du 
auch an jeder betroffenen Stelle nachbessern.

> Beim Port Map habe ich diese Ports auf open gelegt. Trotzdem zeigt
> die IDE noch Warnungen an.
Sind das tatsächlich Warnungen oder nur Infos?
In welchem Prozessschritt?

von Duke Scarring (Gast)


Lesenswert?

Florentin S. schrieb:
> Beim
> Port Map habe ich diese Ports auf open gelegt. Trotzdem zeigt die IDE
> noch Warnungen an. Also kann das scheinbar noch nciht ganz optimal sein.

Doch, das passt schon. Irgendwann wird man von ISE bzw. XST so mit 
Warnungen zugemüllt, so das die nicht mehr richtig hilfreich sind :-(
Leider hilft da der Message Filter auch nur bedingt.

Ich guck immer nach, ob folgende Warnungen auftauchen:
1
WARNING:Xst:737 --> unwanted Latches
2
WARNING:Xst:653 --> nicht zugewiesene (aber verwendete) Signale

Duke

von Flo S. (tuxianer)


Lesenswert?

Es sind Warnungen:
1
Xst:752[...]Unconnected input port 'p0i' of component 'twoseven' is tied to default value

Ich werde mich jetzt als nächstes an die Benutzerschnittstelle, sprich 
tasten zum Zeit stellen machen. Die Taster müssen ja vermutlich noch 
entprellt werden. Was ist denn dafür die effektivste Methode?

von Duke Scarring (Gast)


Lesenswert?

Florentin S. schrieb:
> Die Taster müssen ja vermutlich noch
> entprellt werden. Was ist denn dafür die effektivste Methode?

Alle x Millisekunden den Wert einlesen (x = 10...100) und nach dem 
Muster "001" suchen.

Duke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Florentin S. schrieb:
>> Die Taster müssen ja vermutlich noch
>> entprellt werden. Was ist denn dafür die effektivste Methode?
> Alle x Millisekunden den Wert einlesen (x = 10...100) und nach dem
> Muster "001" suchen.
So etwa:
http://www.lothar-miller.de/s9y/categories/5-Entprellung

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.