Forum: FPGA, VHDL & Co. exakter Frequenzteiler


von michael (Gast)


Lesenswert?

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;

von Marcus (Gast)


Lesenswert?

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

von michael (Gast)


Lesenswert?

Vielen Dank, Marcus, werde es gleich einmal ausprobieren!

Gruß michael

von michael (Gast)


Lesenswert?

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

von Thomas Faust (Gast)


Lesenswert?

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.

von michael (Gast)


Lesenswert?

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

von Thomas Faust (Gast)


Lesenswert?

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.

von toddoy (Gast)


Lesenswert?

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;

von Max Müller (Gast)


Lesenswert?

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

von toddoy (Gast)


Lesenswert?

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

von michael (Gast)


Lesenswert?

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;

von michael (Gast)


Lesenswert?

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:-)

von Jörn (Gast)


Lesenswert?

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

von michael (Gast)


Lesenswert?

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:-)

von Max Müller (Gast)


Lesenswert?

@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
Noch kein Account? Hier anmelden.