ungeradzahlig teilen

OP #1152720
Lesenswert?
• ▲
▼
Hallo,
ich stehe vor dem Problem, dass ich von einem Drehgeber 2,671875 Pulse 
pro mm bekomme aber möglichst genau alle mm einen Zähler erhöhen will. 2 
ist falsch, 3 aber auch. Abwechselnd 2 und 3 in geschicktem Wechsel wäre 
am genauesten.. Hat sowas schonmal jemand gemacht? Vielen Dank im 
voraus!
Gruß Haegar
Gast #1152860
Lesenswert?
• ▲
▼
> Abwechselnd 2 und 3 in geschicktem Wechsel wäre am genauesten.. Hat
> sowas schonmal jemand gemacht?

Nein, hätte aber trotzdem einen Vorschlag:
1
#define ZAEHLER 171
2
#define NENNER   64
3

4
unsigned int zaehl(void) {
5
  static unsigned int mm, summe/*=ZAEHLER/2*/;
6

7
  if((summe+=NENNER) >= ZAEHLER) {
8
    summe -= ZAEHLER;
9
    mm++;
10
  }
11
  return mm;
12
}

Die Funktion zaehl wird für jeden Puls aufgerufen und liefert die
ganzzahlige Wegstrecke in mm zurück, wobei weder Multiplikationen noch
Divisionen benötigt werden. Der Umrechnungsfaktor muss als Bruch >1
vorliegen (2,671875=171/64). Je nach Startbedingung und gewünschtem
Rundungsverfahren kann es sinnvoll sein, summe mit ZAEHLER/2 statt mit
0 zu initialisieren.

Das Verfahren entspricht dem Bresenham-Algorithmus zum Zeichnen von
Geraden auf Rasterausgabegeräten:

  http://de.wikipedia.org/wiki/Bresenham-Algorithmus
Gast #1152862
Lesenswert?
• ▲
▼
Ach, ich sehe jetzt erst, dass das das Forum "FPGA, VHDL & Co." ist. Da
hat natürlich C nichts zu suchen. Betrachte den Code also als Pseudocode
und setze ihn in VHDL oder Verilog um. Das Verfahren ist gerade auch für
die Implementierung in Hardware gut geeignet,das es keine komplizierten
Rechenoperationen benötigt.
Moderator (Firma: Titel) Persönliche Seite #1152979
Lesenswert?
• ▲
▼
Durch 2**n Zahlen kann problemlos geteilt werden. Und weil sich der 
Bruch 171/64 als 171/(2**6) schreiben lässt, kann man das auch so 
machen:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4

5
entity EncScale is
6
    Port ( posin  : in  STD_LOGIC_VECTOR (31 downto 0);
7
           posout : out STD_LOGIC_VECTOR (31 downto 0));
8
end EncScale;
9

10
architecture Behavioral of EncScale is
11
  signal poscnt : integer;
12
  signal posmm  : integer;
13
begin
14
  poscnt <= to_integer(signed(posin));
15
  posmm  <= (poscnt*171)/64; -- 171/64 = 2,671875
16
  posout <= std_logic_vector(to_signed(posmm,32));
17
end Behavioral;
posin enthält die Zählimpulse vom Geber, nur auf diesem Wert wirkt sich 
der Encoder unmittelbar aus. In der Hardware wird nicht geteilt, sondern 
nach der Multiplikation einfach die unteren 6 Bits abgeschnitten. Und 
weil der Multiplizierer ein kombinatrisches Element ist, muß das ganze 
nicht mal getaktet sein ;-)
Gast #1153181
Lesenswert?
• ▲
▼
Das ist so wunderam nicht wenn man bedenkt, dass da Patente im Spiel 
waren. Ist so änhlich wie das dem Sigma-Delta-Prinzip hinterliegende 
Single-Slopw-Verfahren, welches es kurz nach der Patentierung auch als 
Dual- und Quadro-Verfahren gab.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.