Guten Vormittag, ich habe versucht, einen Impulszähler zu realisieren, sprich: Man drückt einen Taster, dann soll sich der Wert auf insg. zwei 7-Segment-Anzeigen um 1 erhöhen. Wow, das muss echt einfach sein -dachte ich. Jetzt hab ich jedoch das Problem, dass beim Drücken des Tasters der Zähler immer woanders landet , d.h. mal wird "07". mal "23" usw. angezeigt, obwohl von "00" gestartet wurde. Ich will aber, dass der Wert sich immer nur um 1 erhöht. Wieso es nicht so passiert, weiß ich nicht genau aber ich habe eine Vermutung: Ich habe einen 50Mhz Takt, d.h. der Prozess wahrscheinlich wird viel zu oft aufgerufen. Der Taster bleibt ja paar Millisekunden oder so gedrückt, deswegen wird zu oft hochgezählt. Ist das richtig so? Kann ich das Problem lösen, indem ich den Takt von 50Mhz auf zb 2Hz reduziere?
Maximilian L. schrieb: > Ich habe einen 50Mhz Takt, d.h. der Prozess wahrscheinlich wird viel zu > oft aufgerufen. Der Taster bleibt ja paar Millisekunden oder so > gedrückt, deswegen wird zu oft hochgezählt. Kommt drauf an, wie deine Beschreibung aussieht... > Ist das richtig so? Kann ich das Problem lösen, indem ich den Takt von > 50Mhz auf zb 2Hz reduziere? Vermutlich ja, das ist aber völliger Murks. Der richtige Weg ist es, den Taster zu entprellen und eine Flankenerkennung drauf zu setzen. Es gibt hier im Forum zig Diskussionen dazu. > Ich habe einen 50Mhz Takt, d.h. der Prozess wahrscheinlich wird viel zu > oft aufgerufen. In der Hardware wird da nirgends irgendein "Prozess aufgerufen". Sondern es wird deine Hardwarebeschreibung vom Synthesizer in Flipflops und LUTs übersetzt, dann vom Placer platziert, vom Router verdrahtet und vom BitGen in einen Bitstrom umgewandelt, der dann ins FPGA geladen wird. Sieh dir also mal den RTL-Schaltplan an, dann siehst du, was der Synthesizer gemacht hat und kannst kontrollieren, ob das dem entspricht, was du eigentlich beschreiben wollstest.
:
Bearbeitet durch Moderator
Da fehlen wohl zwei Vorgänge in deinem unbekannten VHDL-Code: 1. Signal vom Taster entprellen z.B. mit einem Zähler, der losläuft, sobald der Taster gedrückt ist und zurückgesetzt wird, sobald der Taster nicht gedrückt ist. Bei einem bestimmten Zählerstand (höchstwertiges Bit nehmen!) stoppt der Zähler und dieses Stop-Signal ist das entprellte. 2. Entprelltes Signal differenzieren mit Gatter über ein FlipFlop, so daß 1 geliefert wird, solange am FF Input das Signal 1 ist, am FF Output aber noch 0. Dieses Signal als CE für deinen Zähler und das funktioniert.
Danke soweit. Ich denke ich mache es folgendermaßen: Ich werde einfach die vier möglichen Tasterzustände abfragen. Diese Lösung scheint mir am einfachsten. Orientiert habe ich mich hier https://www.mikrocontroller.net/articles/Entprellung ab "Flankenerkennung".
:
Bearbeitet durch User
Maximilian L. schrieb: > Ich werde einfach die vier möglichen Tasterzustände abfragen. Du solltest dabei übrigens beachten, dass asynchrone Eingänge erst mal eingetaktet werden müssen: http://www.lothar-miller.de/s9y/archives/41-Einsynchronisieren-von-asynchronen-Signalen.html Sonst passiert dir schnell mal das da: http://www.lothar-miller.de/s9y/archives/64-State-Machine-mit-asynchronem-Eingang.html > Ich denke ich mache es folgendermaßen: > Ich werde einfach die vier möglichen Tasterzustände abfragen. Ein Tipp aus der Praxis: verwende von Anderen nur solchen Code, den du auch selbst zu 100% verstanden hast. Im Zweifelfall suchst du nämlich auch selbst nach dem Problem. > Diese Lösung scheint mir am einfachsten. Die Sache mit Google ist dir schon mal zu Ohren gekommen? https://www.google.com/search?q=taster+entprellen+vhdl Und von dort aus dann z.B. das http://www.lothar-miller.de/s9y/categories/5-Entprellung
:
Bearbeitet durch Moderator
Alles klar, haben Sie noch einen Tipp wie weit der Verzögerungszähler bei 50MHz zählen sollte? Ich schätze einfach mal aus dem Bauch: bis 25.000.000 -> dann sollte ein Drücken jede halbe Sekunde funktionieren, oder?
Maximilian L. schrieb: > Ich schätze einfach mal aus dem Bauch: bis 25.000.000 -> dann sollte > ein Drücken jede halbe Sekunde funktionieren, oder? Ein Taster, der eine halbe Sekunde braucht, "fühlt" sich nicht gut an. Er lässt sich nur sehr holprig bedienen. Und zudem prellt kein halbwegs funktionierender Taster für eine halbe Sekunde. Ich würde da bestenfalls 50ms ansetzen. > wie weit der Verzögerungszähler bei 50MHz zählen sollte? Also muss der Zähler 50ms/20ns = 2_500_000 Schritte zählen und somit von 0 bis 2499999 laufen.
Ich bin leider gescheitert das richtig umzusetzen. Vielleicht hat jemand Lust sich den Code mal anzusehen und den Fehler zu finden. Der Impulszähler springt weiterhin um zu viele Schritte nach vorne...
Jetzt wäre der richtige Zeitpunkt eine Testbench aufzusetzen und sich das Verhalten des Codes mal im Simulator anzuschauen.
Die beigefügte Beschreibung dürfte sich überhaupt nicht synthetisieren lassen, da das Signal V_BT überhaupt nicht existiert. Zudem wurde auch nicht Lothars Hinweis beachtet, dass Eingangssignale einsynchronisiert werden müssen; dies ist um so wichtiger, weil der Wert von BT(1) an mehreren Stellen verwendet wird.
Duke Scarring schrieb: > Jetzt wäre der richtige Zeitpunkt eine Testbench aufzusetzen und sich > das Verhalten des Codes mal im Simulator anzuschauen. Wobei sich da natürlich sofort die Frage stellt: hat jemand mal paar schöne Modelle von prellenden Tastern zur Hand, mit der man die Testbench bestücken kann? Ist das irgendwie sowas?
1 | process
|
2 | is begin |
3 | taster(0) <= '0'; |
4 | wait for .5 ms; |
5 | taster(1) <= '1'; |
6 | wait for .3 ms; |
7 | taster(0) <= '0'; |
8 | wait for 3 ms; |
9 | taster(0) <= '1'; |
10 | wait for .4 ms; |
11 | taster(0) <= '0'; |
12 | wait for length_of_this_keypress; |
13 | taster(0) <= '1'; |
14 | wait for .5 ms; |
15 | taster(0) <= '0'; |
16 | wait for .3 ms; |
17 | taster(0) <= '1'; |
18 | wait; |
19 | end process; |
:
Bearbeitet durch Moderator
Andreas S. schrieb: > Die beigefügte Beschreibung dürfte sich überhaupt nicht synthetisieren > lassen, da das Signal V_BT überhaupt nicht existiert. Zudem wurde auch > nicht Lothars Hinweis beachtet, dass Eingangssignale einsynchronisiert > werden müssen; dies ist um so wichtiger, weil der Wert von BT(1) an > mehreren Stellen verwendet wird. Stimmt, dieses "V_" gehört da nicht hin. Beim Testlauf hatte ich das da noch nicht stehen. Mein Fehler
Maximilian L. schrieb: > Ich hab sowas leider nicht Deswegen musst Du Testbench ja auch selbst erstellen. Möglicherweise besitzt Dein FPGA-Entwicklungswerkzeug sogar die Möglichkeit, zu einem HDL-Quelltext auf Knopfdruck den Rumpf der zugehörigen Testbench zu erstellen.
Danke euch, ich bin jetzt soweit, dass ich den Taster einsynchronisiert habe , und zwar durch 2 Flip Flops. Jetzt sollte es sehr unwahrscheinlich zum metastabilen Zustand kommen
Jörg W. schrieb: > Ist das irgendwie sowas? Ich habe gerade kein Bild von 'echtem' Prellen da, das sieht i.d.R. noch viel wilder aus, aber für die Simulation kann man das gelten lassen.
Maximilian L. schrieb: > ich bin jetzt soweit, dass ich den Taster einsynchronisiert habe , und > zwar durch 2 Flip Flops. Jetzt sollte es sehr unwahrscheinlich zum > metastabilen Zustand kommen In Deinem Quellcode hast Du nach wie vor einen nicht einsynchronisierten Reset, den Du zudem noch als asynchronen Reset eines getakteten Prozesses verwendest. Schlimmer geht es kaum. Zwar werden in Deinem konkreten Projekt mögliche Probleme nur sehr, sehr selten auftreten, und wenn sie auftreten, dass nur so kurzzeitig, dass Du sie vermutlich nicht einmal bemerken könntest, aber trotzdem ist das ganze nicht sauber.
Vielen Dank, das habe ich außer Acht gelassen. Da der Reset hier nicht wirklich notwendig ist, werde ich ihn ganz weglassen. Im Anhang der verbesserte Code ohne den Reset
:
Bearbeitet durch User
Duke Scarring schrieb: > Jörg W. schrieb: >> Ist das irgendwie sowas? > Ich habe gerade kein Bild von 'echtem' Prellen da, das sieht i.d.R. noch > viel wilder aus, aber für die Simulation kann man das gelten lassen. Da fällt mir doch gerade ein: habe vor längerer Zeit mal ein paar Dreh-Encoder am Logic Analyzer aufgezeichnet. Habe mal von zweien die Daten in eine VHDL-Testbench umgewandelt. Falls jemand also real prellende Kontakte haben oder seine Encoder-Entprellung mit realen Daten simulieren möchte: hier sind sie. ;-) (Für einen einfachen Kontakt nimmt man einfach eine Spur eines der Encoder, oder schneidet sich nur ein paar Teile aus dem Code aus.)
:
Bearbeitet durch Moderator
Maximilian L. schrieb: > ich bin jetzt soweit, dass ich den Taster einsynchronisiert habe , und > zwar durch 2 Flip Flops. Jetzt sollte es sehr unwahrscheinlich zum > metastabilen Zustand kommen Bei einer Taktfrequenz von 50MHz gibt es absolut keine relevanten metastabilen Zustände. Heutige Flipflops schaffen es locker, sich innerhalb von 2..3ns zu "beruhigen". Deshalb muss das Thema "Metastabilität" bei Taktfrequenzen bis zu 300MHz überhaupt nicht in Betracht gezogen werden. Warum man trotzdem einsynchronisieren muss? Das steht in aller Ausführlichkeit im Link, den ich zum Thema "FSM mit asynchronem Eingang" weiter oben schon gepostet habe. Das, was dort besprochen wird, hat wiederum überhaupt nichts mit Metastabilität zu tun. Und solche Fehler können und werden auch schon bei niedrigsten Taktfrequenzen passieren. Maximilian L. schrieb: > Im Anhang der verbesserte Code ohne den Reset In einem getakteten Prozess kommt nach dem getakteten Block nicht noch irgendwelcher kombinatorischer Klimbim, von dem ohnehin keines der Signale in der Sensitivliste auftaucht. Eine derart unvollständige Sensitivliste sorgt zuverlässig dafür, dass die Simulation nicht zur Hardware passt. Der Synthesizer sagt dir das auch, wenn du die Infos und Warnungen mal genau anschaust. > if ... and taster_old='0' then taster_old ist immer '0'...
:
Bearbeitet durch Moderator
Danke für die Info, dass der kombinatorische Kram vor/nach den Prozess gehört. Ich werde den kombinatorischen Kram wahrscheinlich dann einfach in ein Untermodul packen. Ist das Vorhandensein des kombinatorischen Klimbims denn auch wirklich ein Problem, dass für die Fehlfunktion sorgt? Also ist das der Grund wieso der Zähler beim Drücken des Tasters zu weit hochzählt? Das könnte ich mir nämlich nicht vorstellen. Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."? Sorry für die ganzen Nachfragen, der Einstieg in VHDL fällt mir wegen der ganzen anderen Programmiersprachen etwas schwierig.
Maximilian L. schrieb: > Ich werde den kombinatorischen Kram wahrscheinlich dann einfach in ein > Untermodul packen. Sieh dir an, wie man das nebenläufig (concurrent) beschreibt. Und wenn du einem 7 bit breiten Vektor ein 7 Bit breiten Wert zuweist, dann brauchst du keinen Range angeben:
1 | if (einer=0) then segmentoutput3(6 downto 0) <= "1000000"; |
2 | elsif (einer=1) then segmentoutput3(6 downto 0) <= "1111001"; |
3 | elsif (einer=2) then segmentoutput3(6 downto 0) <= "0100100"; |
kann so abgekürzt werden:
1 | if (einer=0) then segmentoutput3 <= "1000000"; |
2 | elsif (einer=1) then segmentoutput3 <= "1111001"; |
3 | elsif (einer=2) then segmentoutput3 <= "0100100"; |
Und wenn du nicht jedem Signal noch den Namen "out" oder "output" gibst, obwohl es kein FPGA-Ausgang ist und unnötige Zwischensignale weglässt, dann wird das Ganze noch lesbarer.
1 | seg4 <= "1000000" when einer=0 else |
2 | "1111001" when einer=1 else |
3 | :
|
4 | "0000000" when digit=8 else |
5 | "0010000"; |
6 | |
7 | seg5 <= "1000000" when zehner=0 else |
8 | "1111001" when zehner=1 else |
9 | :
|
10 | "0000000" when zehner=8 else |
11 | "0010000"; |
> Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."? Mit einer Simulation findest du das in kurzer Zeit heraus. > Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."? So hast du es geschrieben:
1 | if rising_edge(clk) then |
2 | if taster_deb='1' and taster_old='0' then |
3 | impulscounter <= impulscounter + 1; |
Weil hier aber taster_old mit '0' initialisiert ist und niemals geändert wird, zählt der Zähler alle 20ns hoch, so lange der Taster gedrückt ist. Du kannst es z.B. so machen:
1 | process
|
2 | begin
|
3 | wait until rising_edge(clk); |
4 | ff1_out <= BT(1); |
5 | ff2_out <= ff1_out; --ff2_out ist nun zu verwenden |
6 | taster_old <= taster_deb; |
7 | end process; |
Allerdings könnte man den ganzen Zirkus ohne Prozesse auch wesentlich kompakter schreiben:
1 | signal btsr: std_logic_vector[1 downto 0] := "00"; -- Schieberegister für BT(1) |
2 | :
|
3 | :
|
4 | stsr <= btsr(0) & BT(1) when rising_edge(clk); -- Einsynchronisierung |
5 | taster_old <= taster_deb when rising_edge(clk); -- für Flankenerkennung |
6 | :
|
7 | :
|
8 | --Entprellen
|
9 | process begin |
10 | wait until rising_edge(clk); |
11 | if btsr(1)= taster_deb then debcnt <= 0; |
12 | else debcnt <= debcnt + 1; |
13 | end if; |
14 | |
15 | if (debcnt=2499999) then taster_deb <= btsr(1); |
16 | end if; |
17 | end process; |
> Ist das Vorhandensein des kombinatorischen Klimbims denn auch wirklich > ein Problem, dass für die Fehlfunktion sorgt? Also ist das der Grund > wieso der Zähler beim Drücken des Tasters zu weit hochzählt? Nein. Allerdings ist deine Simulation falsch und passt nicht zur Hardware. Sowas bringt dich jetzt schon (zeig mal deine Simulation) und später bei größeren Designs erst recht in ernstliche Schwierigkeiten.
Lothar M. schrieb:
1 | stsr <= btsr(0) & BT(1) when rising_edge(clk); -- Einsynchronisierung |
Korrekt wäre eher:
1 | btsr <= btsr(0) & BT(1) when rising_edge(clk); -- Einsynchronisierung |
:
Bearbeitet durch User
Ja, tatsächlich. Sehen wir es als kleinen Aufmerksamkeitstest für die Überallherkopierer... ;-)
> Oder liegt das ernsthafte Problem hier "taster_old ist immer '0'..."?
Mit einer Simulation findest du das in kurzer Zeit heraus.
--> Genau darin lag das Problem. Danke für die ganzen Tipps, ich werde
mal meinen Code schöner gestalten.
Maximilian L. schrieb: > Danke für die ganzen Tipps, ich werde > mal meinen Code schöner gestalten. Das ist auch wichtig, aber vorher kommt die Testbench. Im Anhang mal ein Gerüst, wie das auschauen könnte. Duke
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.