Tach zusammen, habe ein Frequenzteiler-Problem: Wie man einen ungenauen Teiler konstruiert, weiß ich, aber ich komme einfach nicht dahinter, wie man eine exakte (gewünschte) Frequenz heraus bekommt. Gestern ist mir der folgende kleine Auszug (siehe unten) eingefallen, aber es tut schon, wie bei all den anderen, ergebnislosen Versuchen, in der Richtung, nicht das, was es tun soll. Bräuchte eine Frequenz von 12Mhz auf 9600, für serielle Schnittstelle, da ich nicht weiter gekommen bin und ich glaube, es liegt bei meinem Teiler, hab ich einmal folgendes, zu Testzwecken probiert (im sichtbaren Bereich: von 12MHz auf 1Hz), doch leider blinkt es nicht. Nach der Programmierung geht die LED, die eigentlich blinken sollte, einmal, zeitverzögernd an und bleibt dann eingeschaltet. Bitte, um Hilfe, Danke, michael Auszug aus meinem Testbeispiel takt=12MHz std_logic-Eingang, zaehler: Signal, std_logic(21 downto 0) if rising_edge(takt) zaehler<=zaehler+1; end if if zaehler=12000000 then ausgang<='0'; else ausgang<='1'; end if;
Hallo michael, warum schreibst du das nicht so: IF rising_edge(takt) zaehler <= zaehler + 1; CASE zaehler IS WHEN 12000000 => ausgang <= '0'; zaehler <= 0; -- Zähler zurücksetzen WHEN OTHERS => ausgang <= '1'; END CASE END IF; Das Zählersignal muss dann aber anders definiert werden: SIGNAL zaehler: INTEGER RANGE 0 TO 12000000:=0; Gruß, Marcus
Leider arbeitet die Sache, trotz deines Änderungsvorschlages, gleich wie vor der Verbesserung. Folgendes, in beiden Varianten: Die Led würde eigentlich nur dann leuchten, in dem Moment, indem die 12000000Hz erreicht sind und bei allen anderen Werten ist sie dunkel. Nachdem sie schwach leuchtet, wird wahrscheinlich nur dieser kurze Impuls erscheinen oder nicht??? michael
port (clk : in std_logic; clk_out : buffer std_logic := 0); clockdivider: process (clk) variable counter : integer range 0 to 15 := 0; constant delay : integer := 12000000; begin if (counter < clk_divider) then counter := counter + 1; else clk_out <= not clk_out; counter:=0; end if; end process; Das sollte funktionieren, jedoch kann es passieren dass der Takt invertiert wird, wenn man das nicht möchtet, sollte man wohl den pegel von clk mit abfragen, und z. b. nur auf falling edgezählen, dafür nur halb so lang. Das wäre sowieso empfehlenswert, da das ganz gut Hardware fressen dürfte, 6*10^6 in binär braucht ein paar Register. Da könnte es fast billiger sein, den Takt extern zu teilen, statt viel vom teuren CPLD zu verbauen.
Danke, für deine Idee Thomas, funktioniert aber, leider immer noch nicht! Zu clk_divider: Nachdem nirgends definiert, gehört "delay" vielleicht durch den "clk_divider" ersetzt? Gibts vielleicht andere Vorschläge, ausser das mit dem ext. Takt, um einen genauen Frequenzteiler zu konstruieren, welcher nicht auf meiner Theorie basiert? Vielleicht einen einfachen, sodaß ich ihn auch verstehe und meine 9600Hz, nach dem Austesten des Teilers, erzeugen kann! Danke, michael
Also so wie das oben steht kann das natürlich nicht funktionieren.... clk_divider sollte durch delay ersetzt werden, und counter sollte natürlich so groß sein, dass er auch zu Ende zählen kann (also range 0 to 12000000). Ansonsten sollte das eigentlich funktionieren, zumindest hab ich den code aus einer Datei kopiert (und modifiziert, bei mir zählt er nur bis 15), und da sah das in Modelsim eigentlich ganz ordentlich aus.
Hier mal ein anderer Vorschlag Ich hoffe, das dieser recht nützlich ist library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; library unisim; use unisim.all; entity TaktTeiler is generic( Faktor : Integer := 500000); port( clk_i : in std_logic; clk_o : out std_logic; reset_i : in std_logic ); end TaktTeiler; architecture verh_TaktTeiler of TaktTeiler is signal sp,next_sp : std_logic; signal Counter : integer range 0 to Faktor/2; begin process (clk_i,reset_i,sp,next_sp) is begin if(reset_i = '1') then sp <= '0'; elsif rising_edge(clk_i) then sp <= next_sp; end if; end process; clk_o <= sp; process (clk_i,sp,Counter,next_sp) is begin if reset_i = '1' then Counter <= 0; next_sp <= '0'; elsif rising_edge(clk_i) then Counter <= 0; if (Counter < Faktor/2 ) then Counter <= Counter + 1; else Counter <= 0; next_sp <= not sp; end if; end if; end process; end verh_TaktTeiler;
Ich will ja nicht besserwisserisch sein, aber durch eure Integer definition im Range von 0 bis 12000000 könnt ihr nie einen Takt von 1Hz erhalten, sondern maximal von 12000000/12000001. Somit kleiner als 1. probiers mal damit signal count : integer range 0 to (12000000/2-1); signal output : std_logic; counter:process(reset,clk) begin if (reset = '1') then count <= 0; output <= '0'; elsif( rising_edge(clk)) if ( count < (12000000/2-1) then count <= count +1; output <= output; else count <= 0; output <= not output; endif; endif end process counter; Jetzt solltest du am Anfang natürlich auch noch einmal kurz reset auf 1 und wieder auf 0 setzten, damit alles korrekt initalisiert ist. Dann sollte alles klappen. Falls nicht, poste mal deinen kompletten Code, da bestimmt dort beim Einbinden unserer Lösungen dein Fehler liegt. Gruß Max
Danke für deinen Hinweis, ich habe mein Modul durch den Simulator laufen lassen mit einem kleinen Teilerfaktor und nachgezählt, es muss heißen: signal Counter : integer range 0 to Faktor/2 + 1; if (Counter < Faktor/2 + 1) then , dann stimmt das Ergebniss. G. Tobi
Danke für eure guten Tipps!:-) Hab mich über die Osterferien meine eigenen Theorien zusammen gebastelt und eine hat sogar funktioniert! Hoffe, ich hab es jetzt richtig im Kopf (könnten Syntaxfehler dabei sein!), habe den Quellkode jetzt nicht parat:-( if rising_edge(takt) then baudgen<=baudgen+1; if baudgen=625 then baudgen=0;
Danke für eure guten Tipps!:-) Hab mir über die Osterferien meine eigenen Theorien zusammen gebastelt und eine hat sogar funktioniert, von zweien! Hoffe, ich hab es jetzt richtig im Kopf (könnten Syntaxfehler dabei sein!), habe den Quellkode jetzt nicht parat:-( -- takt=12.000.000 Hz; gewünschte Freuquenz 9600Hz, für Baudraten -- Erzeugung: 12.000.000/ 9600 = 1250, also auf diesen Wert den -- baudgen hochzählen lassen! signal baudgen : integer range 0 to 1250; signal baud : std_logic_vector; if rising_edge(takt) then baudgen<=baudgen+1; if baudgen=625 then baudgen=0; baud<=not baud; end if; end if; Theorie: Funktioniert mit jeder gewünschten Frequenz:-) 1.) Wenn ich auf 1250, ohne "baud <= not baud", hochzählen lasse, komme ich auf die 9600Hz, jedoch kommt keine gleichmäßige Impuls-Pausendauer heraus, Impuls kürzer als Pause. 2.) Abhilfe: Wenn ich aber auf die Hälfte 625 hinaufzählen lasse und anschließend, die Zeile "baud <= not baud" implementiere, komme ich auch auf die 9600Hz und zusätzlich gleichgroße Impulse wie Pausen. Am Oszilloskope verifiziert. (exakt 9593Hz) Hoffe, ihr kennt euch aus:-) michael:-)
Noch ein Hinweis. Du brauchst die 9600 Baud für die serielle Schnittstelle, wenn ich oben richtig gelesen habe. Ich kenne es so, dass das zu empfangene Signal 16fach überabgetastet wird. Mein UART mit 115200 Baud wird mit einer Frequenz von etwa 1,8 Mhz @ 50Mhz Systemtakt betrieben. Bei Interesse kann ich das UART Modul geben. Es ist frei verfügbar von Xilinx. Gruß Jörn
Senden kann ich schon, vom Xilinx-Board, kommuniziere mit einem 8051-Übungsboard. Habe 16 Tasten auf dem Xilinx-Board, die alle "Tastaturkodiert" sind, d.h. Taste 0 liefert den Wert 0 bis Taste 15 liefert den Wert 15. Ich drücke eine Taste am Xilinx-Board und via RS232 erscheint dann der Tastenwert auf dem LCD, des 8051-Boards. Beim Empfänger, am Xilinx-Board, habe ich noch keinen Durchblick, deshalb würde ich gerne auf dein Angebot zurückkommen! Habe es mir so ähnlich vorgestellt, wie beim Senden vom Xilinx-Board, nachdem auch ein (derselbe) Tastaturdekoder auf dem 8051-Board ist, den Tastenwert via RS232 aufs Xilinx-Board zu schicken und diesen dann auf einer zweistelligen Siebensegmentanzeige auszugeben. Danke Jörn, Interesse besteht!:-) Gruß michael:-)
@toddoy Dann schau mal deine Beschreibung genau an. Das + muss ein - sein. Warum: Ganz einfach, da du sonst um eins zuviel hochzählst. Machen wir mal einen Teiler /4, der symmetrische puls/pausenzeiten hat. Nehmen wir mal einfachhalber an, das wir aktuell mit 4 Hz takten und 1 Hz rausbekommen wollen. Zähler steht nach dem Start auf 0 und es erfolgt die erste steigende Flanke vom Clock nach 0,25s und so weiter. 0 nach 0,25s=1 nach 0,5s=2 nach 0,75s=3 nach 1S=4oderauch 0 nach 1,25=1 usw. Bei meiner Lösung würde der nächsten Flanke nachdem der Counter=1 ist (da 4/2-1=>1) der Ausgang getoggelt. Somit nach immer 2 Takten, was bei 4 Takte für steigende Flanke zur steigenden Flanke des Ausgangs bedeutet. Bei deiner Lösung sind es 4/2+1=>3. Somit würde bei dir eine Frequenz von 0,5Hz rauskommen. Bei /8 kommt bei dir statt 0,5Hz nur 0,4Hz raus. Glaubs mir ich weis, was ich sage. Gruß Max
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.