• 基于Verilog HDL的二进制转BCD码实现


           在项目设计中,经常需要显示一些数值,比如温湿度,时间等等。在数字电路中数据都是用二进制的形式存储,要想显示就需要进行转换,对于一个两位的数值,对10取除可以得到其十位的数值,对10取余可以得到个位的数值。对于Verilog来说它的标准是支持除法和取余运算的,综合器也会有IP可以进行除法运算。但是这样未免会耗费太多资源,使用移位加3算法就可以实现二进制到BCD码之间的转换。

           BCD码(Binary-Coded Decimal‎)亦称二进码十进数或二-十进制代码。用4位二进制数来表示1位十进制数中的0~9这10个数码。

           移位加3算法简单来说就是,有多少位二进制说,就进行多少次移位,以八位的二进制为例,其数值最高可为三位十进制数,进行如下表左移,在移位的过程中,如果移位出的数值大于4,则将改为的数值加3后再进行移位。

    这里为什么大于四,BCD码是四位二进制数表示一个十进制数的一位,如果这以为大于4,比如5,4’b0101,下一次移位后变成了4’b1010,BCD码中是没有4’b1010的,所以要加6,向高位进位。这里就是移位后加6和移位前加3,两种方法修正,我这里选择了移位前加3。(4’b0011左移后也是4’b0110,移位前和移位后都是一样的对BCD码的位数进行修正)。

    为什么用左移的方法呢?这是因为二进制数和十进制数之间的位权的关系。所以二进数和十进制数之间的转化是乘以2,也就是左移一位。转换公式大概就是这个样子。

    公式编辑采用Markdown编辑器Typora完成,Typora支持LaTex语法,编写公式真是爽。

           代码实现起来不是很复杂,博主在网上搜索到有些代码使用纯组合逻辑实现的,用了一个for循环,我个人认为这种写法不是很好,所以自己用状态机写了一个。模块设计如下,tran_en是转换使能信号,可以使电平使能也可以是脉冲使能,作为脉冲使能使用的时候,需要在数据来临之后的一个时钟周期给出使能(我的模块是这样的特点),电平使能有效时,需要18个时钟周期完成转换,输入二进制位16bit,输出为四组千百十个位。转换完成后输出一个转换完成标志tran_done。

     

           内部的时序我采用了三段式状态机来完成。IDLE状态接收到使能信号,调到移位状态,经过16次移位。在shift_cnt为17时(这里是因为我状态机的原理所以shift_cnt会计数到17,但移位次数为16),数据转换完成。跳到DONE状态,输出转换完成标志。

     

           采用组合逻辑来实现,移位后的数据值的判断,大于4加3后再进行移位。最后将转换完成后的结果输出。

    代码如下:

      1 `timescale      1ns/1ps
      2 // *********************************************************************************
      3 // Project Name :       
      4 // Author       : NingHeChuan
      5 // Email        : ninghechuan@foxmail.com
      6 // Blogs        : http://www.cnblogs.com/ninghechuan/
      7 // File Name    : Bin_BCD.v
      8 // Module Name  :
      9 // Called By    :
     10 // Abstract     :
     11 //
     12 // CopyRight(c) 2018, NingHeChuan Studio.. 
     13 // All Rights Reserved
     14 //
     15 // *********************************************************************************
     16 // Modification History:
     17 // Date         By              Version                 Change Description
     18 // -----------------------------------------------------------------------
     19 // 2018/8/12    NingHeChuan       1.0                     Original
     20 //  
     21 // *********************************************************************************
     22 
     23 module Bin_BCD
     24 #(
     25     parameter       DATA_WIDTH  =   16,
     26     parameter       SHIFT_WIDTH =   5,
     27     parameter       SHIFT_DEPTH =   16
     28     
     29 )
     30 (
     31     input               clk,
     32     input               rst_n,
     33     input               tran_en,
     34     input       [DATA_WIDTH - 1:0]  data_in,
     35     output   reg        tran_done,
     36     output      [3:0]   thou_data,      //千位
     37     output        [3:0]    hund_data,      //百位
     38     output        [3:0]    tens_data,      //十位
     39     output        [3:0]    unit_data       //个位
     40 
     41 );
     42 //-------------------------------------------------------
     43 localparam  IDLE    =   3'b001;
     44 localparam   SHIFT   =   3'b010;
     45 localparam   DONE    =   3'b100;
     46 
     47 //-------------------------------------------------------
     48 reg     [2:0]   pre_state;
     49 reg     [2:0]   next_state;
     50 //
     51 reg     [SHIFT_DEPTH-1:0]   shift_cnt;
     52 //
     53 reg     [DATA_WIDTH:0]  data_reg;
     54 reg     [3:0]   thou_reg;
     55 reg        [3:0]    hund_reg;
     56 reg        [3:0]    tens_reg;
     57 reg        [3:0]    unit_reg; 
     58 reg     [3:0]   thou_out;
     59 reg        [3:0]    hund_out;
     60 reg        [3:0]    tens_out;
     61 reg        [3:0]    unit_out; 
     62 wire    [3:0]   thou_tmp;
     63 wire    [3:0]    hund_tmp;
     64 wire    [3:0]    tens_tmp;
     65 wire    [3:0]    unit_tmp;
     66 
     67 //-------------------------------------------------------
     68 //FSM step1
     69 always  @(posedge clk or negedge rst_n)begin
     70     if(rst_n == 1'b0)begin
     71         pre_state <= IDLE;
     72     end
     73     else begin
     74         pre_state <= next_state;
     75     end
     76 end
     77 
     78 //FSM step2
     79 always  @(*)begin
     80     case(pre_state)
     81     IDLE:begin
     82         if(tran_en == 1'b1)
     83             next_state = SHIFT;
     84         else 
     85             next_state = IDLE;
     86     end
     87     SHIFT:begin
     88         if(shift_cnt == SHIFT_DEPTH + 1)
     89             next_state = DONE;
     90         else 
     91             next_state = SHIFT;
     92     end
     93     DONE:begin
     94         next_state = IDLE;
     95     end
     96     default:next_state = IDLE;
     97     endcase
     98 end
     99 
    100 //FSM step3
    101 always  @(posedge clk or negedge rst_n)begin
    102     if(rst_n == 1'b0)begin
    103         thou_reg <= 4'b0; 
    104         hund_reg <= 4'b0; 
    105         tens_reg <= 4'b0; 
    106         unit_reg <= 4'b0; 
    107         tran_done <= 1'b0;
    108         shift_cnt <= 'd0; 
    109         data_reg <= 'd0;
    110     end
    111     else begin
    112         case(next_state)
    113         IDLE:begin
    114             thou_reg <= 4'b0; 
    115             hund_reg <= 4'b0; 
    116             tens_reg <= 4'b0; 
    117             unit_reg <= 4'b0; 
    118             tran_done <= 1'b0;
    119             shift_cnt <= 'd0; 
    120             data_reg <= data_in;
    121         end
    122         SHIFT:begin
    123             if(shift_cnt == SHIFT_DEPTH + 1)
    124                 shift_cnt <= 'd0;
    125             else begin
    126                 shift_cnt <= shift_cnt + 1'b1;
    127                 data_reg <= data_reg << 1;
    128                 unit_reg <= {unit_tmp[2:0], data_reg[16]};
    129                 tens_reg <= {tens_tmp[2:0], unit_tmp[3]};
    130                 hund_reg <= {hund_tmp[2:0], tens_tmp[3]};
    131                 thou_reg <= {thou_tmp[2:0], hund_tmp[3]};
    132             end
    133         end
    134         DONE:begin
    135             tran_done <= 1'b1;
    136         end
    137         default:begin
    138             thou_reg <= thou_reg; 
    139             hund_reg <= hund_reg; 
    140             tens_reg <= tens_reg; 
    141             unit_reg <= unit_reg; 
    142             tran_done <= tran_done;
    143             shift_cnt <= shift_cnt; 
    144         end
    145         endcase
    146     end
    147 end
    148 //-------------------------------------------------------
    149 always  @(posedge clk or negedge rst_n)begin
    150     if(rst_n == 1'b0)begin
    151         thou_out <= 'd0;
    152         hund_out <= 'd0;
    153         tens_out <= 'd0;
    154         unit_out <= 'd0; 
    155     end
    156     else if(tran_done == 1'b1)begin
    157         thou_out <= thou_reg;
    158         hund_out <= hund_reg;
    159         tens_out <= tens_reg;
    160         unit_out <= unit_reg;
    161     end
    162     else begin
    163         thou_out <= thou_out;
    164         hund_out <= hund_out;
    165         tens_out <= tens_out;
    166         unit_out <= unit_out;
    167     end
    168 end
    169 
    170 
    171 //-------------------------------------------------------
    172 assign  thou_tmp = (thou_reg > 4'd4)?  (thou_reg + 2'd3) : thou_reg;
    173 assign  hund_tmp = (hund_reg > 4'd4)?  (hund_reg + 2'd3) : hund_reg;
    174 assign  tens_tmp = (tens_reg > 4'd4)?  (tens_reg + 2'd3) : tens_reg; 
    175 assign  unit_tmp = (unit_reg > 4'd4)?  (unit_reg + 2'd3) : unit_reg; 
    176 
    177 assign thou_data = thou_out;
    178 assign hund_data = hund_out;
    179 assign tens_data = tens_out;
    180 assign unit_data = unit_out;
    181 
    182 
    183 endmodule 
    Bin_BCD

    转载请注明出处:NingHeChuan(宁河川)

    个人微信订阅号:开源FPGA

    如果你想及时收到个人撰写的博文推送,可以扫描左边二维码(或者长按识别二维码)关注个人微信订阅号

    知乎ID:NingHeChuan

    微博ID:NingHeChuan

    原文地址:https://www.cnblogs.com/ninghechuan/p/9464037.html

  • 相关阅读:
    iOS 基础类解析
    冒泡排序Vs直接选择排序
    【HDOJ 5419】 Victor and Toys (排列组合)
    我的互联网安全观
    Linux进程间通信-信号量
    AFNetworking 3.0携带參数上传文件Demo
    ANDROID窗体管理服务实现机制和架构分析
    【ODPS】阿里云ODPS中带分区的表操作
    Android自定义组件系列【13】——Android自定义对话框如此简单
    微信支付开发(2) 静态链接Native支付
  • 原文地址:https://www.cnblogs.com/ninghechuan/p/9464037.html
Copyright © 2020-2023  润新知