Forum: FPGA, VHDL & Co. BCD zu Binär Konverter 74er Reihe?


von Harald G. (hallo_s)


Lesenswert?

weiß jemand ob es ein TTL IC der 74er Reihe gibt, womit man BCD zu Binär 
konvertieren kann?
Der 74184 kann das zwar, jedoch ist der BCD Code als 5-4-2-1. Ich brauch 
jedoch als Eingang den üblicheren Code 8-4-2-1.

Ich möchte mit dem in Altera Quartus ein 12 Bit BCD-Binär Converter 
erstellen.
Da ich in VHDL noch nichts gemacht habe, möchte ich das im 
Blockschaltbild umsetzten.

von Helmut K. (hk_book)


Lesenswert?

wenn es unbedingt "old school" sein soll: nehme ein Eprom, lege den 
BCD-Code als Adressen an und hinterlege an den (wenigen) benutzten 
Speicherzellen den dazugehörenden Binär-Code. Programmieren kann man das 
im HEX-Editor des Programmiergerätes, ist nichts großes (wenn man noch 
eines auftreibt...).

Aha, habe gerade gesehen, dass du das als Harware wohl garnicht brauchst 
(?), sondern nur die Funktion kopieren willst.

: Bearbeitet durch User
von Mario M. (thelonging)


Lesenswert?

Na ja, das läuft wahrscheinlich auf eine Multiplikation der 
höherwertigen Digits mit 10 und 100 und Addition der 3 Werte hinaus. 
Google nach "BCD to binary VHDL".

von pegel (Gast)


Lesenswert?

Wenn es nicht super schnell sein muss, geht vielleicht diese serielle 
Variante 12bit BCD<>BIN:
https://www.edn.com/design/systems-design/4369038/Conversion-circuit-handles-binary-or-BCD

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


Lesenswert?

pegel schrieb:
> diese serielle Variante 12bit BCD<>BIN
Ich bevorzuge zeitlich deterministischere Versionen:
http://www.lothar-miller.de/s9y/categories/44-BCD-Umwandlung

Harald G. schrieb:
> Da ich in VHDL noch nichts gemacht habe, möchte ich das im
> Blockschaltbild umsetzten.
Ich sag da jetzt mal besser nix zu diesem eigenartigen logischen 
Kurzschluss, sondern verweise nur auf den 
Beitrag "kruder Fehler bei FPGA-Programmierung (ISE WEBpack-Schematic)"

: Bearbeitet durch Moderator
von Markus F. (mfro)


Lesenswert?

ich mach' das so:
1
    function bcd2bin(bcd_value : unsigned) return natural is
2
        constant v_left : integer := bcd_value'length - 1;
3
        variable bcd : unsigned(v_left downto 0);
4
        variable mul,
5
                 ret : natural;
6
    begin
7
        bcd := bcd_value;
8
        mul := 1;
9
        ret := 0;
10
11
        for i in bcd_value'length / 4 - 1 downto 0 loop
12
            ret := ret +
13
                   to_integer(bcd(3 downto 0)) *
14
                   mul;
15
            bcd := shift_right(bcd, 4);
16
            mul := mul * 10;
17
        end loop;
18
        return ret;
19
    end function bcd2bin;

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


Lesenswert?

Markus F. schrieb:
> ich mach' das so
Und was kommt dabei raus?
Macht der da tatsächlich für jede Stelle einen Multiplizierer?

von Markus F. (mfro)


Lesenswert?

Lothar M. schrieb:
> Markus F. schrieb:
>> ich mach' das so
> Und was kommt dabei raus?
> Macht der da tatsächlich für jede Stelle einen Multiplizierer?

Das Design braucht 37 LUTs und schafft über 100 MHz (Cyclone III). Finde 
ich passend, dafür dass man lesen kann, was gemeint ist.

P.S.: in dem Fall habe ich 16 bit unsigned benutzt.
P.P.S: tatsächlich degeneriert der (ursprünglich eingesetzte) lpm_mult 
zur Lookup-Tabelle.

: Bearbeitet durch User
von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Beitrag "Re: 8-Bit als Dezimalzahlen"
Nostalgie...
mit TTL- oder CMOS-Addierern geht es auch, es muss kein 74184 sein

von Harald G. (hallo_s)


Lesenswert?

Ja der 74184 würde ja funktionieren, wenn er nicht einen BCD im 5421 
Code benötigen würde. Meine Codierschalter 3 x 4bit haben jedoch 8421. 
Somit müsste ich erst von 8421 auf 5421 BCD Code wandeln, um dann mit 
den 74184 von BCD auf Binär zukommen.

Gibt es kein Old School IC der das vom 8421 direkt in Binär wandeln 
kann. Dann würde ich das in Quartus raussuchen und entsprechend 
verschalten.
Ich bin in Quartus noch nicht so geschult, dass ich VHLD Skripte 
einfügen kann, somit programmiere ich noch in old School 
Blockschaltbild.

von Schlumpf (Gast)


Lesenswert?

Harald G. schrieb:
> Da ich in VHDL noch nichts gemacht habe, möchte ich das im
> Blockschaltbild umsetzten.

Harald G. schrieb:
> Ich bin in Quartus noch nicht so geschult, dass ich VHLD Skripte
> einfügen kann, somit programmiere ich noch in old School
> Blockschaltbild.

Und was ist dein mittelfristiges Ziel?
VHDL oder Verilog zu lernen?
Falls ja, dann wäre das doch jetzt der ideale Zeitpunkt, damit 
anzufangen.... oder nicht?
Oder muss das "Projekt" ganz schnell fertig werden?

von pegel (Gast)


Lesenswert?

Ist es in Quartus nicht auch so, dass man ein Symbol für den Schaltplan 
aus einer VHDL Datei erstellen kann?

von Markus F. (mfro)


Lesenswert?

Harald G. schrieb:
> Ja der 74184 würde ja funktionieren, wenn er nicht einen BCD im 5421
> Code benötigen würde. Meine Codierschalter 3 x 4bit haben jedoch 8421.
> Somit müsste ich erst von 8421 auf 5421 BCD Code wandeln, um dann mit
> den 74184 von BCD auf Binär zukommen.
>

Wie kommst Du übrigens da drauf? Schau' dir mal die Wahrheitstabelle 
auf Seite 5 des Datenblatts und die BCD-Binary-Beschaltung auf derselben 
Seite genau an (beachte, dass Bit0 "durchgereicht" wird).

Für mich sieht das jedenfalls nach reinrassigem 8-4-2-1 aus.

von Harald G. (hallo_s)


Lesenswert?

Also der 74184 in Quartus, welchen man als vorprogrammierte Funktionen 
aus der Bibliothek nutzen kann, nutzt doch den Code 8421. Die alte TTL 
Version nutzt, laut Datenblatt, zwar den 5421 Code, aber das hat Altera 
so nicht übernommen. Somit funktioniert meine Umwandelung nun Richtig.

Letztendlich möchte ich mit den MaxV CPLD von Altera ein einstellbaren 
Impulsgenerator bauen. 3 BCD Codierschalter habe ich, welche eine 
Frequenz vom 100Hz (entspricht die einer Stelle) bis 99900Hz einstellbar 
machen soll.
Das Funktioniert auch zwar, aber bei den höheren Frequenzen ist es, 
wegen der Rundungsfehler, ungenau.
Ich nehme ein 20Mhz Oszillator.
100000 teile ich durch den eingestellten Wert. Mit dem Ergebnis lade ich 
ein Zähler und zähle rückwärts auf 0. Dann toggele ich ein FlipFlop, 
damit Impuls und Pausenzeit gleich lang werden, daher die 20Mhz 
Taktfrequenz beim Zähler und keine 10Mhz.

Nun reicht, wie ich rechne, die Auflösung von 10Mhz nicht aus, um einen 
unterschied ersichtlich zu machen, z.B wenn ich 901,902,903,904 
einstelle, ist das Ergebis jedesmal gleich und gibt immer 90900Hz aus.
Wo liegt mein Denkfehler?
Oder muss ich Faktor 10 höher gehen mit meiner Taktfrequenz (100MHz)?

Klar dass man sowas einfacher mit ein Mikroprozessor machen kann, aber 
der CPLD ist gerade in der Schaltung enthalten und noch genug Platz im 
CPLD frei.

@Schlumpf, ja das Projekt soll zeitnah fertig werden, und bisher hat die 
Blockschaltbildmethode immer ausgereicht. Ich habe ja noch in der 
Ausbildung TTL richtig gelernt und da ist dann die 
Blockschaltbildprogrammierung fast 1 zu 1 gleich.
Ich weiß noch nicht was sinniger ist VHDL oder Verilog.
Ich vermute mal, ich werde VHDL mal anschauen.

Q Markus F. -- Laut Datenblatt ist als Input bei BCD als 5 eine 01000 
und nicht 00101. Wenn man die Warheitstabelle weiter sich anschaut, ist 
der Input ein 5421 BCD Code.

: Bearbeitet durch User
von Schlumpf (Gast)


Lesenswert?

Kannst du mal nen Screenshot von deinem Schaltplan posten?

Ganz abgesehen davon klingt das so, als würdest du mit abgeleiteten 
Takten arbeiten. Und da ist weiterer Ärger vorprogrammiert.

von Schlumpf (Gast)


Lesenswert?

Harald G. schrieb:
> Ich habe ja noch in der
> Ausbildung TTL richtig gelernt und da ist dann die
> Blockschaltbildprogrammierung fast 1 zu 1 gleich.

Da hast du Recht.
Aber dann hast du sicher auch gelernt, was Setup- und Hold-Zeiten sind.
Solange du reine kombinatorik zusammenbaust, brauchst du dich darum 
nicht zu kümmern. Aber wenn Takte und Register (FlipFlops) im Spiel 
sind, wird das zum Thema.
Solange in deinem Design alle Register mit dem gleichen Takt arbeiten, 
kann die Synthese das für dich lösen.
Wenn du dir aber Takte kombinatorisch baust und damit Register taktest 
und aus den Ergebnissen vielleicht wieder Takte für andere Register 
generierst, musst du dich selbst darum kümmern, dass es keine 
Timingverletzungen gibt.
Auf einer Leiterplatte macht man das unter anderem über das Layout. In 
einem FPGA sind deine Eingriffsmöglichkeiten aber eingeschränkter.

So eine Schaltung kann funktionieren, kann aber auch immer wieder 
ungewolltes Verhalten zeigen.

von Harald G. (hallo_s)


Lesenswert?

Klar Holdzeiten, Gatterlaufzeiten kennt man.

Also der Systemtakt sind die 20Mhz. Ich löse das Problem so, dass ich 
mit der positiven Flanke zähle und mit der negativen flanke das FF 
Toggele, bzw den Zähler neu vorlade. Somit habe ich immer 1/2 Taktzeit 
von 20Mhz zeit, bis sich alle FlipFlops eingeschwungen haben.

Die Schaltung läuft auch soweit bis halt auf diese Rundungsfehler. Je 
größer der eingestellt Wert ist je mehr machen sich die Rundungsfehler 
bemerkbar.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Harald G. schrieb:
> Q Markus F. -- Laut Datenblatt ist als Input bei BCD als 5 eine 01000
> und nicht 00101. Wenn man die Warheitstabelle weiter sich anschaut, ist
> der Input ein 5421 BCD Code.

Laut Datenblatt ist der Input für 5 (und 4) 10x (Bit 0 wird ja 
"aussenrum" verdrahtet) und der binary output ebenso 10x. Hast Du ein 
anderes Datenblatt als ich?

Ich weiss nicht, wo Du liest, aber ich beziehe mich auf die Tabelle auf 
Seite 5 oben links ("BCD-to-Binary Converter").

von Schlumpf (Gast)


Lesenswert?

Harald G. schrieb:
> Somit habe ich immer 1/2 Taktzeit
> von 20Mhz zeit, bis sich alle FlipFlops eingeschwungen haben.

Ok, das klingt vernünftig.

Nun, wie gesagt, wäre ein Schaltplan hilfreich.

von Harald G. (hallo_s)


Angehängte Dateien:

Lesenswert?

Anbei mal der Schaltplan.

Das Signal intern_clk_enable einfach nicht beachten. Damit wird nur der 
Zähler vorgeladen befor das ganze gestartet wird.

Genauso die Ausgangsbeschaltung. Damit kann ich den erzeugten Takt oder 
ein anderen Takt nach außen leiten.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Das scheint mir an simpler Arithmetik zu hapern ;)

100000 DIV 999 bis runter zu 100000 DIV 991 gibt bei mir immer dasselbe 
Ergebnis, nämlich 100.

von Harald G. (hallo_s)


Lesenswert?

Ja so ist es, je größer der eingestellte Wert ist, je mehr machen sich 
die Rundungsfehler bemerkbar.
Ich habe dazu noch keine Lösung gefunden außer statt 20Mhz auf 200Mhz 
zugehen.

Q Markus F. Ja genau Datenblatt Seite 5 oben links die Tabelle. Ja ich 
habe übersehen wie es gemeint ist. Klar Bit0 wird durchgereicht und 
somit ist die ganze Tabelle verschoben und das Bit 0 muss man sich 
dazudenken. Also Bit 0 vom Eingang kommt sozusagen als Spalte vor dem A 
in der Tabelle.


Hatte ich erst falsch verstanden.
Also doch Code 8421.
http://www.utm.edu/staff/leeb/DM74185.pdf

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Harald G. schrieb:
> Ich habe dazu noch keine Lösung gefunden außer statt 20Mhz auf 200Mhz
> zugehen.

Nimm Excel und rechne dir's aus: 89 MHz würden reichen, damit deine 
Schaltstufen gerade noch auflösen.

von (prx) A. K. (prx)


Lesenswert?

Harald G. schrieb:
> Hatte ich erst falsch verstanden.
> Also doch Code 8421.

Beides, je nach Beschaltung.

von Harald G. (hallo_s)


Lesenswert?

Ja wenn ich 100MHz Oszillator nehme dann sind es effektiv nur 50Mhz zum 
Auflösen, da ich Puls- und Pausenzeit mit den Takt erzeuge.

Somit bin ich etwas bezüglich Auflösung drunter aber evtl. noch 
vertretbar.
200Mhz Oszillator fällt raus da der MaxV 5M570ZT100C5N laut Datenblatt 
bei 152MHz schluss ist.

von Markus F. (mfro)


Lesenswert?

CPLDs haben doch (echte) dual-edge FFs, oder nicht?

von Harald G. (hallo_s)


Lesenswert?

Daran habe ich auch schon gedacht, beide Flanken auszuwerten, so wie 
beim DDR Ram. Nur habe ich solche FlipFlops bei Quartus noch nicht 
gefunden.

von Harald G. (hallo_s)


Lesenswert?

Ich habe nun folgenden VHDL Code gefunden und statt dem gebastelten 
Blöcken, aus den 74184, ersetzt. Verbrauchen tut der VHDL Code auch 
weniger Logikblöcke:

http://vhdlguru.blogspot.com/2015/04/vhdl-code-for-bcd-to-binary-conversion.html


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

--this module is for converting a 4 digit BCD number into binary number.
--the range of the input in decimal is 0 to 9999.
entity bcd_2_bin is
    Port ( bcd_in_0 : in  STD_LOGIC_VECTOR (3 downto 0);
           bcd_in_10 : in  STD_LOGIC_VECTOR (3 downto 0);
           bcd_in_100 : in  STD_LOGIC_VECTOR (3 downto 0);
           bcd_in_1000 : in  STD_LOGIC_VECTOR (3 downto 0);
           bin_out : out  STD_LOGIC_VECTOR (13 downto 0) := (others => 
'0'));
end bcd_2_bin;

architecture Behavioral of bcd_2_bin is

begin

bin_out <= (bcd_in_0 * "01")  --multiply by 1
                + (bcd_in_10 * "1010") --multiply by 10
                + (bcd_in_100 * "1100100") --multiply by 100
                + (bcd_in_1000 * "1111101000"); --multiply by 1000

end Behavioral;

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


Lesenswert?

Harald G. schrieb:
> + (bcd_in_10 * "1010") --multiply by 10
> + (bcd_in_100 * "1100100") --multiply by 100
> + (bcd_in_1000 * "1111101000"); --multiply by 1000
Man kann die Multiplikationen übrigens auch in Multiplikationen mit 
Zweierpotenzen aka "Linksshifts" (--> andere Verdrahtung) und Additionen 
auflösen:
1
bin_out <=
2
  bcd_in_1 -- es gibt keine 0er-Stelle...
3
+ bcd_in_10*8 + bcd_in_10*2
4
+ bcd_in_100*64 + bcd_in_100*32 + bcd_in_100*4
5
+ bcd_in_1000*1024 - bcd_in_1000*16 - bcd_in_1000*8


BTW: das Rechnen mit den std_logic_vector findet man gern in alten 
Büchern oder im amerikanischen Raum. Besser als dieser Stil aus dem 
letzten Jahrtausend ist die Verwendung des numeric_std Package...

: Bearbeitet durch Moderator
von Harald G. (hallo_s)


Lesenswert?

Und wie dieht dann der ganze Code mit numeric_std aus? Würde ich gerne 
mal ausprobieren.

von Markus F. (mfro)


Lesenswert?

Harald G. schrieb:
> Und wie dieht dann der ganze Code mit numeric_std aus? Würde ich gerne
> mal ausprobieren.

der steht oben (Beitrag "Re: BCD zu Binär Konverter 74er Reihe?"). 
Das ist - mehr oder weniger - dasselbe. Bloss dass man bei meinem Code 
gleich sieht, was der tut ;)

von Harald G. (hallo_s)


Lesenswert?

Habe gerade mein Post mal wieder gefunden.
Also ich habe keine dual-edge FFs im MaxV CPLD gefunden. Somit geht bei 
100MHz effektiv nur die 50MHz. Ich nehme zwar den 5M570Z und der kann 
maximal 152MHz. Jedoch habe ich bei 100Mhz schon Probleme mit Laufzeit 
und muss ein paar Takte Pause einbauen bei z.B. mehrbittigen Multiplexer 
(19Bit).

von Michael W. (Gast)


Lesenswert?

Harald G. schrieb:
> Gibt es kein Old School IC der das vom 8421 direkt in Binär wandeln
> kann.

Warum keine Look-up-Tabelle?
Sind doch nur 4 Bits!

von Rudi (Gast)


Lesenswert?

Beitrag "BCD zu Binär Konverter 74er Reihe?"
Lothar M. schrieb:
> bin_out <=
>   bcd_in_1 -- es gibt keine 0er-Stelle...
> + bcd_in_10*8 + bcd_in_10*2
> + bcd_in_100*64 + bcd_in_100*32 + bcd_in_100*4
> + bcd_in_1000*1024 - bcd_in_1000*16 - bcd_in_1000*8
>
> BTW: das Rechnen mit den std_logic_vector findet man gern in alten
> Büchern oder im amerikanischen Raum. Besser als dieser Stil aus dem
> letzten Jahrtausend ist die Verwendung des numeric_std Package...

Dann sind wir aber wieder bei diesem Problem
Beitrag "rechnen mit unsigned"
was die Formulierung aufbläht.

Dann lieber die Shifts mit den &'0'. Finde ich immer noch 
durchsichtiger.

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


Lesenswert?

Rudi schrieb:
> Dann sind wir aber wieder bei diesem Problem
> Beitrag "rechnen mit unsigned"
> was die Formulierung aufbläht.
Kommt drauf an. Wenn man um die unschönen Eigenheiten dieser 
Berechnungen weiß, dann muss man das mit den Bitbreiten der Toolchain 
entsprechend beibiegen und kann die Vektorbreiten schon vor der 
Berechnung passend machen:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity BCD2BIN is
6
    Port ( bcd1      : in  std_logic_vector (3 downto 0);
7
           bcd10     : in  std_logic_vector (3 downto 0);
8
           bcd100    : in  std_logic_vector (3 downto 0);
9
           bcd1000   : in  std_logic_vector (3 downto 0);
10
           result    : out std_logic_vector (15 downto 0));
11
end BCD2BIN;
12
13
architecture Behavioral of BCD2BIN is
14
signal bcd_in_1, bcd_in_10, bcd_in_100, bcd_in_1000, bin_out: unsigned (15 downto 0);
15
begin
16
   bcd_in_1     <= resize(unsigned(bcd1),16);
17
   bcd_in_10    <= resize(unsigned(bcd10),16);
18
   bcd_in_100   <= resize(unsigned(bcd100),16);
19
   bcd_in_1000  <= resize(unsigned(bcd1000),16);
20
21
   bin_out <=  bcd_in_1 -- es gibt keine 0er-Stelle...
22
             + bcd_in_10*8 + bcd_in_10*2
23
             + bcd_in_100*64 + bcd_in_100*32 + bcd_in_100*4
24
             + bcd_in_1000*1024 - bcd_in_1000*16 - bcd_in_1000*8;
25
26
   result <= std_logic_vector(resize(bin_out,16));
27
end Behavioral;
Oder man zwingt das Ergebnis der Multiplikation auf 16 Bit, indem man 
aus der UNSIGNED*INTEGER Operation (die als Ergebnis ja nur 2*UNSIGNED 
als Vektorbreite zurückgibt) eine UNSIGNED*UNSIGNED Operation macht, die 
fürs Ergebnis die beiden Vektorbreiten addiert:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity BCD2BIN is
6
    Port ( bcd_in_1      : in  UNSIGNED (3 downto 0);
7
           bcd_in_10     : in  UNSIGNED (3 downto 0);
8
           bcd_in_100    : in  UNSIGNED (3 downto 0);
9
           bcd_in_1000   : in  UNSIGNED (3 downto 0);
10
           bin_out       : out UNSIGNED (15 downto 0));
11
end BCD2BIN;
12
13
architecture Behavioral of BCD2BIN is
14
begin
15
16
17
  bin_out <=  bcd_in_1 -- es gibt keine 0er-Stelle...
18
            + bcd_in_10*to_unsigned(8,12) + bcd_in_10*to_unsigned(2,12)
19
            + bcd_in_100*to_unsigned(64,12) + bcd_in_100*to_unsigned(32,12) + bcd_in_100*to_unsigned(8,12)
20
            + bcd_in_1000*to_unsigned(1024,12) - bcd_in_1000*to_unsigned(16,12) - bcd_in_1000*to_unsigned(8,12);
21
22
end Behavioral;

Aber richtig: "schön" ist anders...

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.