Hallo...
Habe eine Frage zur Weiterverarbeitung eines PWM-Signals.
Habe einen Sensor der ein PWM Signal ausgibt. Dieses möchte ich mit
einer bestimmten Frequenz abtasten, um somit einen Wert zuerhalten den
ich weiterverarbeiten kann. Derzeit habe ich ein PWM-Signal mit einer
Pulsbreite von 1ms und einer Periodendauer von 20ms.
Ich habe mir gedacht ich lasse einen Zähler mit einer Frequenz von 1MHz
hochzählen solange der Puls anliegt. Und kann somit weiterarbeiten.
Allerdings habe ich noch keine Möglichkeit gefunden wie ich den Wert
speichern kann, da ja vom Sensor gleich wieder eine Veränderung
übermittelt werden kann.
Vielleicht kann mir jemand einen guten ratschlag geben.
Hänge meine Idee einfach mal mit dazu.
Gruß Ronny
-- STANDARD LIBRARIES --
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
-- BEGIN OF ENTITY --
ENTITY Sensor_REG IS
-- GLOBAL VARIABLE MAX-COUNT (Periodendauer 20 ms) --
PORT (
-- GLOBAL CLOCK OF MAX II ALTERA --
glb_clk: IN BIT;
-- CLOCK FOR DISTANCE MEASUREMENT 1 MHz --
en: IN STD_LOGIC;
-- GLOBAL RESET USER PUSH BUTTON S1 --
nReset: IN BIT;
-- RESULT works --
--readyREG: IN BIT;
-- PULS WIDE --
data_in: IN BIT;
-- DATA OUT --
wide_out: OUT INTEGER range 0 to 2**12-1
);
END Sensor_REG;
-- END OF ENTITY --
-- BEGIN OF ARCHITECTURE --
ARCHITECTURE Result OF Sensor_REG IS
TYPE STATE_TYPE IS (POWER_ON_DELAY, INITIALIZE);
SIGNAL state: STATE_TYPE;
BEGIN
PROCESS (glb_clk, nReset, en, data_in)
variable count: integer range 0 to 2**12-1:= 0;
BEGIN
IF (nReset = '0') THEN
count := 0;
state <= POWER_ON_DELAY;
-- GENERATING NEW CLOCK --
ELSIF (glb_clk'EVENT AND glb_clk='1') THEN
-- START OF INITIALIZATION --
IF en = '1' THEN
CASE state IS
-- BEGINNING OF INITIALIZATION --
WHEN POWER_ON_DELAY=>
IF data_in = '1' THEN
count := count + 1;
ELSE
wide_out <= save;
state<=INITIALIZE;
END IF;
WHEN INITIALIZE=>
wide_out <= count;
count := 0;
state <= POWER_ON_DELAY;
END case;
ELSE
count := count;
END IF;
END IF;
END PROCESS;
END Result;
-- END OF ARCHITECTURE --
Naja, prinzipiell würde ich dein PWM Signal als Trigger nehmen und deine
Speicheroperation darauf synchronisieren.
Bei positiver PWM Flanke resettest du deinen 1 MHz Zähler, bei negativer
Flange nimmst du den aktuellen Zählerwert und machst deine
Speicheroperation (wohin auch immer...)
So hast du immer die aktuelle Pulsbreite verarbeitet.
Da ich vhdl nicht mag, weil ich es nicht lesen kann, hier mein Ansatz in
verilog:
input clk_1mhz;
input pwm_in;
output [13:0] data_out;
reg [13:0] data_out_reg;
reg [13:0] counter;
reg pwm_in_buf;
always @ (negedge clk_1mhz)
begin
pwm_in_buf <= pwm_in;
end
always @ (posedge clk_1mhz)
begin
// reset counter at pwm_in negedge else increment
counter <= (pwm_in & ~pwm_in_buf) ? 0 : counter + 1;
end
always @ (negedge pwm_in)
begin
data_out_reg <= counter;
end
assign data_out = data_out_reg;
Wenn deine Pulsbreite doch mal breiter sein sollte als 1ms, muss dein
Zähler übrigens 14 Bit breit werden, da 1 MHz / 50 einen Maximalwert von
20000 ergibt, und das passt in 12 Bit ja nicht rein.
Zu deinem Code::
Statt PROCESS (glb_clk, nReset, en, data_in)
reicht PROCESS (glb_clk, nReset)
Ich würde es so machen:
PROCESS (glb_clk)
variable datainlast: bit; -- fuer Flankenauswertung
variable count2: integer range 0 to 2**12-1:= 0;
BEGIN
IF rising_edge(glb_clk) THEN
IF (nReset = '0') THEN -- synchroner Reset (wenn schon)
count := 0;
ELSIF (en = '1') THEN
datainlast <= data_in;
IF data_in = '1' THEN -- zaehlen solange High
count1 := count1 + 1;
ELSIF datainlast = '1' THEN -- fallende Flanke
wide_out <= count1;
END IF;
END IF;
END IF;
END PROCESS;
@Tim R.
>always @ (negedge pwm_in)
ist eine zweite Taktdomäne.
Macht bei FPGAs fast ausschliesslich Probleme.
Das Zurücksetzen vom Counter hat noch gefehlt.
Und dann ersetzen wir sämtliche count1 und count2 durch count,
dann gehts ;-)
:
ELSIF datainlast = '1' THEN -- fallende Flanke
wide_out <= count;
count <= 0; -- zurücksetzen
END IF;
:
>>Macht bei FPGAs fast ausschliesslich Probleme.>stimmt. kein guter ansatz.
Bei der Beachtung rudimentärer Designrichtlinien macht das gar keine
Probleme.
>Bei der Beachtung rudimentärer Designrichtlinien>macht das gar keine Probleme.
pwm_in ist asynchron zu glb_clk.
So definiere ich ein Problem.
Wenn für dich "rudimentäre Designrichtlinien" so definiert sind, dass
pwm_in vorher auf glb_clk synchronisiert wurde, dann gebe ich dir Recht.
@Harald:
Ne, Lothar hat da schon ganz recht.
Es ist nicht sichergestellt, dass pwm_in nicht gleichzeitig mit einem
counter increment eine negative flanke hat, und in dem Fall ist unklar,
in welchem Zustand der counter ist.
= Problem.
Man kann das natürlich lösen, aber da ja bereits eine funktionierende
VHDL Lösung da steht, verzichte ich darauf.
Hey Lothar Miller (lkmiller)...
Habe deinen Code probiert, und der funktioniert sehr gut. Danke nochmal.
Hat mir sehr weiter geholfen. HAbe dabei auch meinen eigenen Fehler
erkannt. So hatte ich es mir gedacht. In der Simulation zählt der
wunderbar hoch und ich könnte mit dem Zählerstand weiter arbeiten.
Allerdings wenn ich mein weiteres Programm, zum Beispiel die LCD anzeige
mit einbinde, kann ich die Ausgabedaten nicht nutzen (wide_out). Kann
das sein das diese Daten nicht lange genug anliegen, zur Verfügung
stehen, und ich diese vielleicht nochmal speichern muss. Ciao
Hey Lothar Miller (lkmiller)...
Ich habe da nochmal eine Frage zu deinem Syntax.
Du nutzt ja "datainlast", wo du nochmal eine Flanke abfragst, mit
welchem Hintergrund benötige ich die genau. Ciao
Ronny wrote:
> Habe deinen Code probiert, und der funktioniert sehr gut.
Das wundert mich fast etwas...
Der ist ja ko***bel...
Wieso hatte ich bei meinem ersten Post eigentlich variable drin?
Das müssen signale sein, ich hasse variable...
Da kam sicher vom copy&paste :-(
Und den reset habe ich jetzt auch pensioniert, das geht auch ohne.
Jetzt gefällt mir der code besser....
> Ich habe da nochmal eine Frage zu deinem Syntax.> Du nutzt ja "datainlast", wo du nochmal eine Flanke abfragst, mit> welchem Hintergrund benötige ich die genau. Ciao
Die Idee ist, nur bei der fallenden Flanke den Ausgabewert
abzuspeichern.
>um Beispiel die LCD anzeige mit einbinde,>kann ich die Ausgabedaten nicht nutzen (wide_out).>Kann das sein das diese Daten nicht lange genug anliegen,>und ich diese vielleicht nochmal speichern muss.
Klar: das Display weiß nichts von der PWM und andersrum genauso. Die
beiden laufen einfach nur irgendwie vor sich hin.
Deshalb musst du die Daten für die Ausgabe noch einmal
zwischenspeichern, oder das Abspeichern nach wide_out anderweitig mit
der Ausgabe synchronisieren.
Hi.....
Bei dieser Zeile: "dsr <= dsr(2 downto 0) & data_in;" kommt folgende
Meldung:
Error (10327): VHDL error at Sensor_Reg.vhd(82): can't determine
definition of operator ""&"" -- found 0 possible definitions
Kann das daran liegen das da versucht wird einen Std_Logic_Vector mit
einer Bit Variable zu verknüpfen?
Wenn ich das & durch ein AND ersetze. Dabei bin total überfordert :)
Error (10476): VHDL error at Sensor_Reg.vhd(82): type of identifier
"data_in" does not agree with its usage as std_logic_vector type
Wenn ich die & Operation herausnehme, kann ich compilieren allerdings
bekomme ich noch ein Warning:
Bei dieser Zeile " IF (dsr="1100") THEN " kommt diese Meldung:
Warning (10620): VHDL warning at Sensor_Reg.vhd(86): comparison between
unequal length operands always returns FALSE
Total unverständlich. Vielleicht sagt es dir etwas.
Ciao
>Kann das daran liegen das da versucht wird einen Std_Logic_Vector mit>einer Bit Variable zu verknüpfen?
Ja, du mußt data_in noch konvertieren/casten.
>Lösung: erst data_in nach std_logic konvertieren:
Oder noch besser:
verwende nur std_logic(_vector) und integer, und das Leben wird einfach.
Gut, das wird nicht immer klappen, aber den Versuch ist es wert...
Der &-Operator ist (wie von Joko schon gesagt) eine Concatenation, keine
logische Operation.
>Wenn ich die & Operation herausnehme, kann ich compilieren allerdings>bekomme ich noch ein Warning:>Bei dieser Zeile " IF (dsr="1100") THEN " kommt diese Meldung:>Warning (10620): VHDL warning at Sensor_Reg.vhd(86): comparison between>unequal length operands always returns FALSE
Im Code von Lothar hat sich ein kleiner Tippfehler eingeschlichen
>signal dsr: std_logic_vector(3 downto 9);
müsste heissen: signal dsr: std_logic_vector(3 downto 0);
dann müsste die Warnung verschwinden
Gruß Chris