Forum: FPGA, VHDL & Co. vhdl Encoder


von Dan (Gast)


Lesenswert?

Hallo zusammen,
ich habe eine Frage. Ich würde gerne die Geschwindigkeit mit Hilfe eines 
Encoder herausfinden. Dies würde ich machen, indem ich die Pulsperiode 
zwischen den Pulsen vom Encoder messe. Ich habe jetzt folgenden Code 
geschrieben, jedoch weiß ich jetzt nicht, wo ich den cnt1 und cnt2 
ausgeben soll. Es wäre echt nett, wenn mir jemand weiterhelfen kann.
1
begin
2
process 
3
begin 
4
  wait until rising_edge(Pulse);
5
  Toggle <= not Toggle;
6
end process;
7
8
process 
9
variable cnt1 : integer range 0 to 65535 := 0;
10
variable cnt2 : integer range 0 to 65535 := 0;
11
begin 
12
  wait until rising_edge(clk);
13
  If (Toggle = '1') then 
14
    cnt1 := cnt1 +1;
15
    cnt2 := 0;
16
  else
17
    cnt2 := cnt2 +1;
18
    cnt1 := 0;
19
  end if;
20
end process;

von -gb- (Gast)


Lesenswert?

Ja ähm äh. Was willst du denn machen? Eigentlich solltest du doch wissen 
was du mit den Messwerten anstellen willst? Über UART ausgeben, auf ein 
Display schreiben, weiterverarbeiten, ...

von Dan (Gast)


Lesenswert?

Ich will dies dann als UART auf die serielle Schnittstelle ausgeben.

von Gustl B. (-gb-)


Lesenswert?

Sehr fein. Hast du dir schon einen UART in VHDL geschrieben? Oder willst 
du einen fertigen UART verwenden?
Ich würde da eine einfache Handshakelogik bauen die dem UART Daten 
übergibt und dem dann sagt, dass neue Daten da sind. In etwa so, wobei 
du da noch deine Integer auf zwei 8 Bit Werte aufteilen müsstest:

1
signal cnt1 : integer range 0 to 65535 := 0;
2
signal cnt2 : integer range 0 to 65535 := 0;
3
4
begin
5
process 
6
begin 
7
  wait until rising_edge(Pulse);
8
  Toggle <= not Toggle;
9
end process;
10
11
process begin 
12
  wait until rising_edge(clk);
13
  uart_start <= '0';
14
  If (Toggle = '1') then 
15
    cnt1 <= cnt1 +1;
16
    uart_data <= cnt2;
17
    uart_start <= '1';
18
    cnt2 <= 0;
19
  else
20
    uart_data <= cnt1;
21
    uart_start <= '1';
22
    cnt2 <= cnt2 +1;
23
    cnt1 <= 0;
24
  end if;
25
end process;

von Dan (Gast)


Lesenswert?

Ja das habe ich. Mir stellt sich nur die Frage, ob es dann nicht immer 0 
übertragen wird, da ja der cnt1 bzw. 2 auf 0 gesetzt wird. Oder habe ich 
einen Denkfehler?

von Gustl B. (-gb-)


Lesenswert?

So wie in dem Code den ich angepasst habe.

uart_data <= cnt1;
uart_start <= '1';
cnt2 <= cnt2 +1;
cnt1 <= 0;

Das passiert alles im gleichen Takt. cnt1 hat also noch den alten Wert 
und erst im nächsten Wert ist cnt1 dann 0. Und im nächsten Takt hat 
uart_data den Wert den cnt1 in diesem Takt hat.

Aber simuliere das doch mal, da sieht man sehr schön wann wo welcher 
Wert gespeichert ist.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Dan schrieb:
> wait until rising_edge(Pulse);
Ganz, ganz üble Sache.
Der Encoder ist kein Taktgeber, der für einen Takt im FPGA verwendet 
werden kann. Sondern die Encodersignale sind simple asynchrone Signale, 
die auf den einen einzigen FPGA-Takt synchronisiert werden müssen, bevor 
sie im FPGA weiter verarbeitet werden können.
Mit deinem Ansatz und der Verwendung von asynchronen Signalen wird dein 
Design meistens (oder oft oder fast immer) das tun, was du willst, aber 
manchmal (oder immer mal wieder oder dann und wann) wird es seltsame 
Werte liefern.
Der Grund ist dort beschrieben:
http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren

Nach dem Einsynchronisieren kommt dann die das Entprellen (Stichworte 
dazu: Kontaktprellen und EMV-Störungen), dann die Flankenerkennung, dann 
die Auswertung mit den Zählern und dann kann man diese Zählerstände mit 
der seriellen Schnitte versenden.

Dan schrieb:
> Ich will dies dann als UART auf die serielle Schnittstelle ausgeben.
Ist dein UART prinzipiell schnell genug, die Zählerstände zwischen zwei 
Encoderflanken zu versenden? Oder brauchst du da noch einen Fifo zum 
Puffern? Und ist die Schnittstelle schnell genug, dass sie bei höchster 
Drehfrequenz die Daten langfristig übertragen bekommt?

Dan schrieb:
> jedoch weiß ich jetzt nicht, wo ich den cnt1 und cnt2 ausgeben soll.
Sinnvoll wäre das wohl an der Stelle bevor der jeweilige Zähler auf 0 
gesetzt wird und damit den erreichten Zählerstand verliert.

Dan schrieb:
> Mir stellt sich nur die Frage, ob es dann nicht immer 0
> übertragen wird, da ja der cnt1 bzw. 2 auf 0 gesetzt wird.
Nein, das stimmt. Ich würde das in den vorgeschlagenen Code mal so 
reinbasteln:
1
process begin 
2
  wait until rising_edge(clk);
3
  uart_start <= '0';
4
  If (Toggle = '1') then 
5
    cnt1 <= cnt1 +1;
6
    if cnt2>0 then
7
       uart_data <= cnt2;
8
       uart_start <= '1';
9
    end if;
10
    cnt2 <= 0;
11
  else
12
    cnt2 <= cnt2 +1;
13
    if cnt1>0 then
14
       uart_data <= cnt1;
15
       uart_start <= '1';
16
    end if;
17
    cnt1 <= 0;
18
  end if;
19
end process;
Aber sowas lässt sich ja ratzfatz simulieren...   ;-)

: Bearbeitet durch Moderator
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.