Forum: FPGA, VHDL & Co. vhdl Encoder


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Dan (Gast)


Bewertung
0 lesenswert
nicht 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.
begin
process 
begin 
  wait until rising_edge(Pulse);
  Toggle <= not Toggle;
end process;

process 
variable cnt1 : integer range 0 to 65535 := 0;
variable cnt2 : integer range 0 to 65535 := 0;
begin 
  wait until rising_edge(clk);
  If (Toggle = '1') then 
    cnt1 := cnt1 +1;
    cnt2 := 0;
  else
    cnt2 := cnt2 +1;
    cnt1 := 0;
  end if;
end process;

von -gb- (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Ich will dies dann als UART auf die serielle Schnittstelle ausgeben.

von Gustl B. (-gb-)


Bewertung
0 lesenswert
nicht 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:

signal cnt1 : integer range 0 to 65535 := 0;
signal cnt2 : integer range 0 to 65535 := 0;

begin
process 
begin 
  wait until rising_edge(Pulse);
  Toggle <= not Toggle;
end process;

process begin 
  wait until rising_edge(clk);
  uart_start <= '0';
  If (Toggle = '1') then 
    cnt1 <= cnt1 +1;
    uart_data <= cnt2;
    uart_start <= '1';
    cnt2 <= 0;
  else
    uart_data <= cnt1;
    uart_start <= '1';
    cnt2 <= cnt2 +1;
    cnt1 <= 0;
  end if;
end process;

von Dan (Gast)


Bewertung
0 lesenswert
nicht 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-)


Bewertung
0 lesenswert
nicht 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. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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:
process begin 
  wait until rising_edge(clk);
  uart_start <= '0';
  If (Toggle = '1') then 
    cnt1 <= cnt1 +1;
    if cnt2>0 then
       uart_data <= cnt2;
       uart_start <= '1';
    end if;
    cnt2 <= 0;
  else
    cnt2 <= cnt2 +1;
    if cnt1>0 then
       uart_data <= cnt1;
       uart_start <= '1';
    end if;
    cnt1 <= 0;
  end if;
end process;
Aber sowas lässt sich ja ratzfatz simulieren...   ;-)

: Bearbeitet durch Moderator

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.