专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

verilog实现任意位二进制转换BCD

作者:kb129   来源:kb129   点击数:  更新时间:2014年06月08日   【字体:
    一直感觉这是个很简单的问题,直到突然自己连BCD都不太清楚的时候,才发现这没有看起来那么简单,这里介绍里任意位二进制转为BCD的verilog代码,这个转换方法也可以用在C上面,此为原创,转载请注明,谢谢。

基础知识:

      BCD:BCD码又称为8421码,

      意义:之所以有时候需要将binary转换为BCD,一般是用在本科的实验中,为了将binary显示在数码管中,当然还有很多应用,只是目前我还没有用到。

转换算法:左移加3法

      移位加3法的具体原理,在网上感觉也没有人能够说的清楚,以后找到书籍再说吧。下面解释下左移加三算法。这里以8bit二进制数FF做例子。

该算法的操作为上图。下面对上图的操作进行详细的解释:

      由于8bit的二进制最大为FF,转换为十进制为255。所以需要使用三个BCD码来表示所有的8bit二进制数。上图的hundreds表示百位的BCD,tens表示十位的BCD,Units表示个位的BCD。算法的操作为一直将binary数据左移,移出的数据按顺序存在hundreds,tens,Units。例如上面的shift1,shift2,shift3操作后,Units变为了0111,至于为何在shift3后进行add3操作,是因为在算法中每一次左移,都要对hundreds,tens和Units进行判断,如果hundreds,tens和Units里面的值大于或等于5,就将hundreds,tens和Units自加3.所以shift3后,Units里面为0111,表示为7,此时不能左移,而是对Units加三操作,所以Units的值从0111变为了1010.值得注意的是,只要hundreds,tens和Units中任意一个的值大于或等于5(0101),就要先进行一次自加三的操作,然后才能继续左移,后面的操作同上。

注意2:n位的binary就需要进行n次左移

注意3:最后一次左移不需要进行add3操作

注意4 :  亲自推导16位的,和24位的binary转换,结果正确,所以该算法适用于任意位binary

to  BCD,当然这种论断没有足够的理论依据。

verilog代码:

说明:对于8bit及以下的binary,可以使用case语句实现移位加三算法。由于这里说明的是任意位的二进制数,转为BCD,所以我的代码中设计了一个状态机,来控制移位,加三和结束操作。由于代码编写时间仓促,其中或许有些bug。

//name: 二进制转BCD
//data: 2014-04-17 at kb129
//info: as 2**8=255  change to BCD then this need 3 times of “8421”
module b_to_bcd(
      clk,
      rst_n,
      binary,
      state_en,
     BCD
);
parameter   b_length      = 8;
parameter   bcd_len       = 12;
parameter   idle              = 5'b00001;
parameter   shift             = 5'b00010;
parameter   wait_judge   = 5'b00100;
parameter   judge           = 5'b01000;
parameter   add_3          = 5'b10000;

input       clk;
input       rst_n;
input    [b_length-1:0]  binary;
input      state_en;
output reg [bcd_len-1:0]  BCD;

reg  [b_length-1:0]  reg_binary;     
reg  [3:0]    bcd_b, bcd_t, bcd_h;
reg  [3:0]    shift_time;                    
reg   [5:0]    c_state, n_state;
reg      add3_en;
reg      change_done;
//this is a three section kind of state code style
always@(posedge clk or negedge rst_n)

begin
        if(!rst_n)
              c_state <= idle;
       else
             c_state <= n_state;
end
//the second section
always@(posedge clk or negedge rst_n)
begin
       if(!rst_n)
                  c_state <= idle;
       else
                 case(n_state)
                 idle:begin
                               if((binary!=0)&&(state_en==1'b1)&&(change_done==0'b0))
                                       n_state <= shift;
                              else
                                      n_state <= idle;
                          end
                 shift: n_state <= wait_judge;
       wait_judge: begin
                               if(change_done==1'b1)
                                      n_state <= idle;
                               else
                                      n_state <= judge;
                          end
                judge:begin   
                                if(add3_en)
                                       n_state <= add_3;
                               else
                                       n_state <= shift;
                          end
                add_3:begin
                                 n_state <= shift;
                           end
               default: n_state <= idle;  
              endcase
end
//the third section
always@(posedge clk or negedge rst_n)
begin
         if(!rst_n)
                  begin
                          shift_time  <= 4'b0;
                          change_done <= 1'b0;
                          add3_en  <= 1'b0;
                 end
         else
           case(n_state)
           idle:begin
                          shift_time <= b_length;
                          reg_binary <= binary;
                          bcd_h     <= 4'b0;
                          bcd_t     <= 4'b0;
                          bcd_b     <= 4'b0;      
                  end
          shift:begin 
                      {bcd_h,bcd_t,bcd_b,reg_binary} <= {bcd_h,bcd_t,bcd_b,reg_binary}<<1;
                      shift_time <= shift_time-1;
                      if(shift_time==1)     change_done <= 1'b1;
                      else                       change_done <= 1'b0;    
                 end
  wait_judge:begin
                       if((bcd_h>=4'd5)||(bcd_t>=4'd5)||(bcd_b>=4'd5))
                               add3_en <= 1;
                       else
                               add3_en <= 0;
                      if(change_done==1)   BCD <= {bcd_h,bcd_t,bcd_b};
                    end
        judge:  add3_en <= 0;
       add_3: begin
                       if(bcd_h>=4'd5) bcd_h <= bcd_h + 4'b0011; else bcd_h <= bcd_h;
                       if(bcd_t>=4'd5) bcd_t <= bcd_t + 4'b0011; else bcd_t <= bcd_t;
                       if(bcd_b>=4'd5) bcd_b <= bcd_b + 4'b0011; else bcd_b <= bcd_b;
                   end
      default: begin
                           change_done <= 1'b0;
                           add3_en  <= 1'b0;
                  end
           endcase
        end
endmodule

代码的仿真:这里对上面的代码进行了仿真,仿真结果显示上面代码可以实现8bitbinary的BCD转换。

testbench:

module  filter_tb;
reg clk;
reg rst_n;
reg state_en;
reg  [7:0] binary;
wire [11:0] BCD;

initial
       begin
                clk=0;
                rst_n=0; 
                state_en = 0;
     #100   binary = 8'h3f;
     #150   rst_n=1;
     #200     state_en =1;
end
always  #10  clk=~clk;
b_to_bcd u_b_to_bcd
(
 .clk(clk),
 .rst_n(rst_n),
 .binary(binary),
 .state_en(state_en),
 .BCD(BCD)
);
endmodule

仿真结果:二进制的3f=十进制的63



关闭窗口

相关文章