基於FPGA的二進制轉BCD


BCD碼(nary-Coded Decimal‎)又稱二-十進制代碼,亦稱二進碼十進數。是一種二進制的數字編碼形式,用二進制編碼的十進制代碼。這種編碼形式利用了四個位元來儲存一個十進制的數碼。

 

在數字電路中,沒有特殊說明的數碼都是順序編碼的二進制。轉換為BCD碼,也就是將順序編碼的二進制數字的個位、十位、百位等計算出來,用四位二進制表示,組合到一起就是BCD碼。

 

將一個數字對10求余將得到個位。

 

將一個數字減去個位后,除以10,然后在對10求余將得到十位。由於在FPGA內部,正數除法不會保留小數,所以可以直接除以10,而不用減去個位。

 

將一個數字除以100,然后對10求余得到百位。

 

首先設計一個8位的二進制轉成BCD碼。8位的二進制能夠表示最大的數字為255,共有三個BCD碼,輸出共有12位。

 

此模塊命名為bin2bcd,bin為二進制輸入,bcd為BCD碼輸出。

 

 設計代碼如下:

module bin2bcd (

 

  input   wire    [7:0]     bin,

 

  output  wire    [11:0]    bcd

);

 

  assign bcd[3:0] = bin%10;

  assign bcd[7:4] = (bin/10)%10;

  assign bcd[11:8] = (bin/100)%10;

 

endmodule

 

在testbench中,可以利用隨機數給出幾個數值。

`timescale 1ns/1ps

 

module bin2bcd_tb;

 

  reg     [7:0]     bin;

 

  wire    [11:0]    bcd;

 

  bin2bcd bin2bcd_inst(

 

      .bin        (bin),

     

      .bcd        (bcd)

    );

 

  initial begin

    repeat (10) begin

      bin = {$random} % 256;

      # 20;

    end

  end

 

endmodule

在modelsim中,將bin設置為符號位,將bcd設置為十六進制。十六進制也是4個二進制碼組成一個,只不過BCD碼中只有0到9,而十六進制中還有A到F。

 

 

通過RTL仿真圖可以看出,bin和bcd的數字是相同的。

 

在此設計代碼中只有三行,但是涉及到了除法器和求余器(也可以認為是除法器),利用了較多的資源。

 

 

為了減少資源使用,使得延遲更小,二進制轉BCD還有其他的辦法。

首先分析兩個BCD數碼的相加。

 

      0101  0010

+    0010  0110

      0111  1000

在上述BCD碼加法中,52+26最終結果等於78,結果沒有任何錯誤。

         0101  1001

    +   0010  0010

         0111  1011

在上述BCD碼加法中,59+22最終結果等於7B,很明顯出現了不屬於BCD碼中的數字。BCD碼是用來表示十進制數字的,順序編碼時表示二進制的,當四個組到一起時,變為十六進制,當BCD碼算完的結果中有大於9的數碼,可以進行加六調整。加上六后,就會得到正確的進位和本位值。

當結果為1011(B)時,加上0110(6),本位結果為0001,進位為0001。

0111 1011(7B)調整后,為1000 0001(81),結果正確。

上面是分析的是兩個不同的BCD碼相加,下面分析兩個相同的BCD碼相加(最終結果不用調整時),相同的兩個數字相加,可以用左移表示。

            0010   0011

     +    0010   0011

           0100   0110

兩個相同的BCD碼相加(最終結果需要調整時),就需要加六調整了。

 

  

      0010   0111

+    0010   0111

      0100   1110

上述結果就需要加六調整了,因為最終結果中出現了比9大的數字。因為是兩個相同的數字相加,當數字大於4后,兩個相同的數字相加就會大於9,此時就需要加6調整。

當數字大於4,先加上3,此時把兩個相同的結果進行相加,就實現了加之后的結果大於9,然后再加六。這兩種方法是一樣的。

當數字大於4,先加上3,然后進行移位。和先加,判斷結果是不是大於9,然后再加6是相等的。

由於是相等的兩個數字相加,末位肯定為0 。那么兩個相同的BCD相加,再和一個1bit的數字相加,就可以認為是當數字大於4,先加上3,然后進行移位,把最后移位出來的0直接換成最后加的1bit數字即可,將上述操作定義為操作X。

當了解了上述結論后,下面分析,利用上述結論實現二進制轉BCD。

任何一個二進制碼都可以寫成本位的數字乘以本位的權重的累加和。

將一個7位的二進制數據轉為BCD,首先認為是兩個都為0的bcd碼相加,然后加上7位數據的最高位。

上述的結果就是最高位轉換為BCD碼的結果,它的權重應該是2的6次冪,但是現在是2的0次冪。

然后將上述的結果和數據的次高位進行操作X,那么此時數據的最高位的權重變為2的1次冪,次高位的權重變為2的0次冪,結果為最高位和次高位的BCD碼。

依次類推,將八位數據全部進行操作X后,各個數據位都是自己的權重,並且結果就是BCD碼。

在操作X中,為了方便將1bit的數據去替換結果的最后一位,可以將1bit放在調整好的數據的后面,直接移位進去即可。

 

 

在圖中,經歷了7 次的操作X。如果我們可以把操作X設計出來,然后級聯7個即可得到正確結果。

操作X的輸入為前面的BCD碼和后面的二進制(可以將這兩組合到一起)。

操作X為調整和移位,后面用調整和移位來表示。

為了能夠對比兩種二進制轉BCD(除法求余和調整移位),下面利用調整和移位的方法實現8位二進制轉BCD。

 

 

輸入是八位,就需要進行八次的調整和移位。由於每次調整和移位的操作是完全相同的,所以將調整和移位做成一個模塊。

該模塊命名為adjust_shift,輸入為BCD碼的位數加上二進制的位數等於20位,輸出也是20位。

module adjust_shift (

    

     input       wire        [19:0]      idata,

    

     output         wire  [19:0]      odata     

);

 

     wire                  [19:0]      adjust_data;

    

     assign adjust_data[19:16] = idata[19:16] > 4'd4 ? idata[19:16] + 4'd3 : idata[19:16];

     assign adjust_data[15:12] = idata[15:12] > 4'd4 ? idata[15:12] + 4'd3 : idata[15:12];

     assign adjust_data[11:8] = idata[11:8] > 4'd4 ? idata[11:8] + 4'd3 : idata[11:8];

     assign adjust_data[7:0] = idata[7:0];

 

     assign odata = adjust_data << 1'b1;

 

endmodule

當調整移位設計做完之后,我們只需要級聯八個就可以得到結果。第一個輸入時,高位(BCD)要輸入為0;最后一個輸出時,高位(BCD)才是輸出。

 

module bintobcd (

    

     input       wire                  [7:0]       bin,

    

     output       wire                 [11:0] bcd

);

 

     wire             [19:0] adjust_shift_data_0;

     wire             [19:0] adjust_shift_data_1;

     wire             [19:0] adjust_shift_data_2;

     wire             [19:0] adjust_shift_data_3;

     wire             [19:0] adjust_shift_data_4;

     wire             [19:0] adjust_shift_data_5;

     wire             [19:0] adjust_shift_data_6;

     wire             [19:0] adjust_shift_data_7;

    

     adjust_shift  adjust_shift_inst0 (.idata({12’d0,bin}),.odata(adjust_shift_data_0));

     adjust_shift  adjust_shift_inst1 (.idata(adjust_shift_data_0),.odata(adjust_shift_data_1));

     adjust_shift  adjust_shift_inst2 (.idata(adjust_shift_data_1),.odata(adjust_shift_data_2));

     adjust_shift  adjust_shift_inst3 (.idata(adjust_shift_data_2),.odata(adjust_shift_data_3));

     adjust_shift  adjust_shift_inst4 (.idata(adjust_shift_data_3),.odata(adjust_shift_data_4));

     adjust_shift  adjust_shift_inst5 (.idata(adjust_shift_data_4),.odata(adjust_shift_data_5));

     adjust_shift  adjust_shift_inst6 (.idata(adjust_shift_data_5),.odata(adjust_shift_data_6));

     adjust_shift  adjust_shift_inst7 (.idata(adjust_shift_data_6),.odata(adjust_shift_data_7));

    

     assign bcd = adjust_shift_data_7[19:8];

 

endmodule

第一級輸入時,采用位拼接的方式。

 

 

 

編寫testbench后,經過RTL仿真驗證,結果都是正確的。 在達到相同功能的前提下,調整和移位的方式實現的設計,資源利用如下:

 

 

在達到相同的功能下,一個是164,一個是29,對比結果很明顯。

 

設計者:郝旭帥         QQ:746833924     QQ交流群: 173560979 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM