Abtastung PWM Signal mit VHDL

Gast #940612
Lesenswert?

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 --
#940622
Lesenswert?

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.
#940629
Lesenswert?

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.
Moderator (Firma: Titel) Persönliche Seite #940638
Lesenswert?

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.
#940805
Lesenswert?

@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.
Gast #945803
Lesenswert?

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
Gast #945995
Lesenswert?

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
Moderator (Firma: Titel) Persönliche Seite #946761
Lesenswert?

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....
1
:
2
signal dsr: std_logic_vector(3 downto 9);   -- fuer Flankenauswertung
3
signal count: integer range 0 to 2**12-1:= 0;
4
:
5
PROCESS (glb_clk)
6
BEGIN
7
    IF rising_edge(glb_clk) THEN
8
       IF (en = '1') THEN              -- 1MHz
9
          dsr <= dsr(2 downto 0) & data_in;  -- Schieberegister
10
          IF (data_in='1') THEN        -- zaehlen solange High
11
             count <= count + 1;
12
          END IF;
13
          IF (dsr="1100") THEN         -- fallende Flanke
14
             wide_out <= count;        -- Ausgabewert aktualisieren
15
             count <= 0;               -- und Zähler löschen
16
          END IF;
17
       END IF;
18
    END IF;
19
END PROCESS;
20
:

> 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.
Moderator (Firma: Titel) Persönliche Seite #946775
Lesenswert?

>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.
Gast #946792
Lesenswert?

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
Moderator (Firma: Titel) Persönliche Seite #946909
Lesenswert?

>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.
Gast #946944
Lesenswert?

>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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren