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
warum nicht den spiess umkehren? Rechne aus welche strecke 1 impuls entspricht und rechne damit. Damit bis Du relativ genau.
> 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
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.
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 ;-)
yalu wrote: > > Das Verfahren entspricht dem Bresenham-Algorithmus zum Zeichnen von > Geraden auf Rasterausgabegeräten: > > http://de.wikipedia.org/wiki/Bresenham-Algorithmus Ein Delta-Sigma-Modulator macht dasselbe. Das interessante daran ist, dass beide Verfahren zu Beginn der 1960er Jahre entstanden sind. Tom
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.