基于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        : [email protected]
  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

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

时间: 2024-10-11 23:12:32

基于Verilog HDL的二进制转BCD码实现的相关文章

【FPGA】【verilog代码】二进制转BCD [转]

BCD:Binary Coded Decimal 即用4位二进制编码表示1位的十进制数. 定义:BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行.这种编码技巧,最常用于会计系统的设计里,因为会计制度经常需要对很长的数字串作准确的计算.相对于一般的浮点式记数法,采用BCD码,既可保存数值的精确度,又可免却使电脑作浮点运算时所耗费的时间.此外,对于其他需要高精确度的计算,BCD编码亦很常用. 参考百度百科对BCD码的解释:http://baike.b

基于Verilog HDL整数乘法器设计与仿真验证

基于Verilog HDL整数乘法器设计与仿真验证 1.预备知识 整数分为短整数,中整数,长整数,本文只涉及到短整数.短整数:占用一个字节空间,8位,其中最高位为符号位(最高位为1表示为负数,最高位为0表示为正数),取值范围为-127~127. 负数的表示方法为正值的求反又加1.例如: 8’b0000_0100; //表示值:4,正值求反为:8’b1111_1011:再加1表示为:8’b1111_1100,这样便得到了-4的表示方法为:8’b1111_1100. 同理,负值变成正值的方法为:负值

二进制转BCD码

应用: 用fpga实现对数码管显示,以前通常的方法是进行整除和取余进行运算,但是fpga并不擅长乘法除法运算,所以可以用BCD码来转换. BCD码:通俗的可以理解为用四位二进制数表示一位十进制数字.例如,256就可以用bcd码表示为:0010_1001_0110 因此在数码管显示中,也就是把256各位分出来,就可以用bcd码来表示,下面说一种二进制转换bcd码的方法. 加3移位法: bcd码中只有0~9十进制数,但是在四位二进制中是16进制进1,因此在移位过程中要对二进制进行判断,当在移位之后的

paper:基于verilog HDL 的高速可综合FSM设计

1.寄存器输出型状态机 VS 组合逻辑输出型状态机 2.状态编码方法 这块讲的不好,也比较少. 3.系统设计中模块划分的指导性原则

二进制转BCD

什么是BCD码? BCD码称为二进码十进数或BCD码(Binary-Coded Decimal‎)亦称二进码十进数或二-十进制代码.用4位二进制数来表示1位十进制数中的0~9这10个数码. BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行.这种编码技巧,最常用于会计系统的设计里,因为 会计制度经常需要对很长的数字串作准确的计算.相对于一般的浮点式记数法,采用BCD码,既可保存数值的精确度,又可免却使电脑作浮点运算时所耗费的时 间.此外,对于其他需

8421BCD转余3码Verilog HDL的设计(2)

接着上节8421BCD转余3码Verilog HDL的设计(1),分析另一条路径A-C分支 (1)在C状态,t1时刻Bin输入的值可能为0或者1:当bin输入0时,进入F状态:当bin输入1时,进入G状态,比特流Bin二进制为t3t2t1t0的可能性如下: C状态(t1时刻,Bin=0),Bout=0 C状态(t1时刻,Bin=1),Bout=1 t3t2t1t0 T3T2T1T0 下一状态为F状态 t3t2t1t0 T3T2T1T0 下一状态为G状态 0001 0100 0011 0110 0

BCD码转换成二进制和ASCII码

首先得知道什么是BCD码,可以看下百度,基本定义已经讲清楚了,百度链接:BCD码--百度百科:这里要说的也是最常用的一种BCD码:8421码.本文规定若没有特殊说明时,各个数值只会是十进制数.二进制数.ASCII值其中的一种进制数. BCD码是用4位二进制数(各个位的权重分别为:8421,所以叫8421码)来表示一位十进制数.这里的一位十进制数要特别说明下,一位十进制数只能是 0-9之间的一个数值.比如:6 就是表示一位十进制数6:66则是表示两位十进制数:666则是表示三位十进制数:(好像有点

BCD码

BCD码(Binary-Coded Decimal‎)亦称二进码十进数或二-十进制代码,是用4位二进制数来表示1位十进制数中的0~9这10个数码,用一种使用二进制编码十进制的数字编码形式.BCD码这种编码形式利用四个位元来储存一个十进制的数码,从而使二进制和十进制之间的转换得以更加快捷地进行.相对于一般的浮点式记数法,采用BCD码,既可保存数值的精确度,又可免去使计算机作浮点运算时所耗费的时间.此外,对于其他需要高精确度的计算,BCD编码亦很常用. 由于十进制数共有0.1.2.…….9十个数码,

十六进制和BCD码的区别

十六进制转二进制: 将每一位十六进制转化为4为二进制位即可. BCD码: 将十进制的每一位转化为4位二进制位即可. 方法都是将每一位转为4位二进制位,但是区别是一个对应的是十六进制,一个对应的是十进制.比如给出二进制数0101 0101 如果对应十六进制,则是0x55 如果对应BCD码,则是55(注意这里是十进制的55,上面是十六进制的55)