FPGA实现bin转BCD码

文章介绍了在FPGA实现数码管显示数据时,如何将二进制转换为BCD码以节省资源。文章提供了三种常见的实现方式:小梅哥的方法,利用循环的维基百科实现,以及使用状态机的方法。每种方法都包含详细的Verilog代码示例,展示了如何处理数字的每一位并确保不超过4的BCD限制。
摘要由CSDN通过智能技术生成


前言

在用FPGA实现数码管显示数据时,要用到二进制转BCD码,显示数据

一、为什么要这样做?

如果对于一个十进制的数字123,要想将其每一位分别提取出来,那么我们通常用这个算法


百位 = 123 / 100;
十位 = 123%100/10;
个位 = 123%10。

 但是在FPGA里面这样时浪费资源的(虽然我没试过)。
 

二、常见的实现方式

1.小梅哥

module bcd_single_modify(bcd_in, bcd_out);

        input [3:0] bcd_in;
        output [3:0] bcd_out;

        reg [3:0] bcd_out;
        
        always @ (bcd_in)
        begin
                if (bcd_in > 4)
                        bcd_out = bcd_in + 2'd3;
                else
                        bcd_out = bcd_in;
        end

endmodule


module bcd_modify(data_in, data_out);

        input [59:0] data_in;
        output [59:0] data_out;
        
        bcd_single_modify bcd9(.bcd_in(data_in[59:56]), .bcd_out(data_out[59:56]));
        bcd_single_modify bcd8(.bcd_in(data_in[55:52]), .bcd_out(data_out[55:52]));
        bcd_single_modify bcd7(.bcd_in(data_in[51:48]), .bcd_out(data_out[51:48]));
        
        bcd_single_modify bcd6(.bcd_in(data_in[47:44]), .bcd_out(data_out[47:44]));
        bcd_single_modify bcd5(.bcd_in(data_in[43:40]), .bcd_out(data_out[43:40]));
        bcd_single_modify bcd4(.bcd_in(data_in[39:36]), .bcd_out(data_out[39:36]));
        bcd_single_modify bcd3(.bcd_in(data_in[35:32]), .bcd_out(data_out[35:32]));
        bcd_single_modify bcd2(.bcd_in(data_in[31:28]), .bcd_out(data_out[31:28]));
        assign data_out[27:0] = data_in[27:0];

endmodule



module bin_to_BCD(bin, bcd);

        input [27:0] bin;
        output [31:0] bcd;
        
        wire [59:0] shift_reg [28:0];
        
        assign shift_reg[28] = {32'b0, bin};
        
        bcd_modify b27(.data_in(shift_reg[28]<<1), .data_out(shift_reg[27]));
        bcd_modify b26(.data_in(shift_reg[27]<<1), .data_out(shift_reg[26]));
        bcd_modify b25(.data_in(shift_reg[26]<<1), .data_out(shift_reg[25]));
        bcd_modify b24(.data_in(shift_reg[25]<<1), .data_out(shift_reg[24]));
        bcd_modify b23(.data_in(shift_reg[24]<<1), .data_out(shift_reg[23]));
        bcd_modify b22(.data_in(shift_reg[23]<<1), .data_out(shift_reg[22]));
        bcd_modify b21(.data_in(shift_reg[22]<<1), .data_out(shift_reg[21]));
        bcd_modify b20(.data_in(shift_reg[21]<<1), .data_out(shift_reg[20]));        
        
        bcd_modify b19(.data_in(shift_reg[20]<<1), .data_out(shift_reg[19]));
        bcd_modify b18(.data_in(shift_reg[19]<<1), .data_out(shift_reg[18]));
        bcd_modify b17(.data_in(shift_reg[18]<<1), .data_out(shift_reg[17]));
        bcd_modify b16(.data_in(shift_reg[17]<<1), .data_out(shift_reg[16]));
        bcd_modify b15(.data_in(shift_reg[16]<<1), .data_out(shift_reg[15]));
        
        bcd_modify b14(.data_in(shift_reg[15]<<1), .data_out(shift_reg[14]));
        bcd_modify b13(.data_in(shift_reg[14]<<1), .data_out(shift_reg[13]));
        bcd_modify b12(.data_in(shift_reg[13]<<1), .data_out(shift_reg[12]));
        bcd_modify b11(.data_in(shift_reg[12]<<1), .data_out(shift_reg[11]));
        bcd_modify b10(.data_in(shift_reg[11]<<1), .data_out(shift_reg[10]));
        bcd_modify b9(.data_in(shift_reg[10]<<1), .data_out(shift_reg[9]));
        bcd_modify b8(.data_in(shift_reg[9]<<1), .data_out(shift_reg[8]));
        
        bcd_modify b7(.data_in(shift_reg[8]<<1), .data_out(shift_reg[7]));
        bcd_modify b6(.data_in(shift_reg[7]<<1), .data_out(shift_reg[6]));
        bcd_modify b5(.data_in(shift_reg[6]<<1), .data_out(shift_reg[5]));
        bcd_modify b4(.data_in(shift_reg[5]<<1), .data_out(shift_reg[4]));
        bcd_modify b3(.data_in(shift_reg[4]<<1), .data_out(shift_reg[3]));
        bcd_modify b2(.data_in(shift_reg[3]<<1), .data_out(shift_reg[2]));
        bcd_modify b1(.data_in(shift_reg[2]<<1), .data_out(shift_reg[1]));
        assign shift_reg[0] = shift_reg[1]<<1;

        assign bcd = shift_reg[0][59:28];

endmodule

 这是在小梅哥的频率计里面写的,实现的电路

总览

 

 局部

 

2.利用循环写的( 来自维基百科的实现???)

 可以看出,二进制位宽为W,则BCD位宽只需要(W + (W - 4) / 3+1)位。如W=8,只需要10位,范围0-255,百位只需要两位就可以表示。

为了和小梅哥的类比,使用28位bin

`timescale 1ns / 1ps
module binTobcd #( 
    parameter W = 28
)  // input width
( 
    //Inputs
    input [W - 1 : 0] bin ,   // binary
    //Outputs
    output reg [W + (W - 4) / 3: 0] bcd 
); // bcd {...,thousands,hundreds,tens,ones}

integer i, j;

always @(bin) begin
    for (i = 0; i <= W + (W - 4) / 3; i = i + 1)
        bcd[i] = 0;     // initialize with zeros
    bcd[W - 1: 0] = bin;                                   // initialize with input vector
    for (i = 0; i <= W - 4; i = i + 1)                       // iterate on structure depth
        for (j = 0; j <= i / 3; j = j + 1)                     // iterate on structure width
            if (bcd[W - i + 4 * j - : 4] > 4)                      // if > 4
                bcd[W - i + 4 * j - : 4] = bcd[W - i + 4 * j - : 4] + 4'd3; // add 3
end

endmodule

实现的电路

 相当的炸裂!!!

局部

 

3.使用状态机

实现 输入位宽输出位宽 可变

module Binary_to_BCD(
    
    //Inputs
    i_Clock,
    i_Rst_n,
    i_Binary,
    i_Start,
    
    //Outputs
     o_BCD,
     o_DV
);

    parameter INPUT_WIDTH = 28;
    parameter DECIMAL_DIGITS = 32;

    input i_Clock;
    input i_Rst_n;
    input [INPUT_WIDTH - 1 : 0] i_Binary;
    input i_Start;
    
    //Outputs
    output [DECIMAL_DIGITS * 4 - 1 : 0] o_BCD;
    output o_DV;

localparam s_IDLE = 3'b000;
localparam s_SHIFT = 3'b001;
localparam s_CHECK_SHIFT_INDEX = 3'b010;
localparam s_ADD = 3'b011;
localparam s_CHECK_DIGIT_INDEX = 3'b100;
localparam s_BCD_DONE = 3'b101;

reg [2 : 0] r_SM_Main = s_IDLE;
reg [DECIMAL_DIGITS * 4 - 1 : 0] r_BCD = 0;
reg [INPUT_WIDTH - 1 : 0] r_Binary = 0;
reg [DECIMAL_DIGITS - 1 : 0] r_Digit_Index = 0;
reg [7 : 0] r_Loop_Count = 0;
reg r_DV = 1'b0;

wire [3 : 0] w_BCD_Digit = r_BCD[r_Digit_Index * 4 + : 4];

assign o_BCD = r_BCD;
assign o_DV = r_DV;

always @(posedge i_Clock) begin
    if(!i_Rst_n) begin
        r_BCD <= 'h0;
        r_Binary <= 'h0;
        r_DV <= 'h0;
        r_SM_Main <= 'h0;
        r_Loop_Count <= 'h0;
        r_Digit_Index <= 'h0;
    end
    else begin
        case (r_SM_Main)
            // Stay in this state until i_Start comes along
            s_IDLE : begin
                r_DV <= 1'b0;
                if (i_Start == 1'b1) begin
                    r_Binary <= i_Binary;
                    r_SM_Main <= s_SHIFT;
                    r_BCD <= 0;
                end
                else
                    r_SM_Main <= s_IDLE;
            end
            
            // Always shift the BCD Vector until we have shifted all bits through
            // Shift the most significant bit of r_Binary into r_BCD lowest bit.
            s_SHIFT : begin
                r_BCD <= r_BCD << 1;
                r_BCD[0] <= r_Binary[INPUT_WIDTH - 1];
                r_Binary <= r_Binary << 1;
                r_SM_Main <= s_CHECK_SHIFT_INDEX;
            end
            
            // Check if we are done with shifting in r_Binary vector
            s_CHECK_SHIFT_INDEX : begin
                if (r_Loop_Count == INPUT_WIDTH - 1) begin
                    r_Loop_Count <= 0;
                    r_SM_Main <= s_BCD_DONE;
                end
                else begin
                    r_Loop_Count <= r_Loop_Count + 1;
                    r_SM_Main <= s_ADD;
                end
            end
            
            // Break down each BCD Digit individually.? Check them one-by-one to
            // see if they are greater than 4.? If they are, increment by 3.
            // Put the result back into r_BCD Vector.?
            s_ADD : begin
                if (w_BCD_Digit > 4) begin
                    r_BCD[(r_Digit_Index * 4) + : 4] <= w_BCD_Digit + 3;
                end
                r_SM_Main <= s_CHECK_DIGIT_INDEX;
            end
            
            // Check if we are done incrementing all of the BCD Digits
            s_CHECK_DIGIT_INDEX : begin
                if (r_Digit_Index == DECIMAL_DIGITS - 1) begin
                    r_Digit_Index <= 0;
                    r_SM_Main <= s_SHIFT;
                end
                else begin
                    r_Digit_Index <= r_Digit_Index + 1;
                    r_SM_Main <= s_ADD;
                end
            end
            
            s_BCD_DONE : begin
                r_DV <= 1'b1;
                r_SM_Main <= s_IDLE;
            end
            default :
                r_SM_Main <= s_IDLE;
        endcase
    end
end // always @ (posedge i_Clock)?

endmodule // Binary_to_BCD

 实现的电路


总结

实现功能进行了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值