ungeradzahlig teilen

#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

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