1、verilog 实现任意位二进制转换 BCD作者:kb129 来源:kb129 点击数:1372 更新时间:2014 年 06 月 08 日 【字体:大 中 小】 一直感觉这是个很简单的问题,直到突然自己连 BCD 都不太清楚的时候,才发现这没有看起来那么简单,这里介绍里任意位二进制转为 BCD 的 verilog 代码,这个转换方法也可以用在 C 上面,此为原创,转载请注明,谢谢。 基础知识:BCD:BCD 码又称为 8421 码,意义:之所以有时候需要将 binary 转换为 BCD,一般是用在本科的实验中,为了将 binary 显示在数码管中,当然还有很多应用,只是目前我还没有用到。转换
2、算法:左移加 3 法移位加 3 法的具体原理,在网上感觉也没有人能够说的清楚,以后找到书籍再说吧。下面解释下左移加三算法。这里以 8bit 二进制数 FF 做例子。该算法的操作为上图。下面对上图的操作进行详细的解释:由于 8bit 的二进制最大为 FF,转换为十进制为 255。所以需要使用三个 BCD 码来表示所有的 8bit 二进制数。上图的 hundreds 表示百位的 BCD,tens 表示十位的 BCD,Units 表示个位的 BCD。算法的操作为一直将 binary 数据左移,移出的数据按顺序存在 hundreds,tens,Units 。例如上面的shift1,shift2,shi
3、ft3 操作后,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),就要先进行一次
4、自加三的操作,然后才能继续左移,后面的操作同上。注意 2:n 位的 binary 就需要进行 n 次左移注意 3:最后一次左移不需要进行 add3 操作注意 4 : 亲自推导 16 位的,和 24 位的 binary 转换,结果正确,所以该算法适用于任意位 binaryto BCD,当然这种论断没有足够的理论依据。verilog 代码:说明:对于 8bit 及以下的 binary,可以使用 case 语句实现移位加三算法。由于这里说明的是任意位的二进制数,转为 BCD,所以我的代码中设计了一个状态机,来控制移位,加三和结束操作。由于代码编写时间仓促,其中或许有些 bug。/name: 二进制转
5、 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 = 5b00001;parameter shift = 5b00010;parameter wait_judge = 5b00100;parameter judge = 5b01000;param
6、eter add_3 = 5b10000;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 stylealways(pos
7、edge clk or negedge rst_n)beginif(!rst_n)c_state =4d5)|(bcd_t=4d5)|(bcd_b=4d5)add3_en =4d5) bcd_h =4d5) bcd_t =4d5) bcd_b =5) /判断个位是否5,如果是则+3 begin if(shift_reg15:12=5) /判断十位是否5,如果是则+3 begin shift_reg15:12=shift_reg15:12+2b11; shift_reg11:8=shift_reg11:8+2b11; shift_reg=shift_reg=5) begin shift_reg1
8、5:12=shift_reg15:12+2b11; shift_reg11:8=shift_reg11:8;shift_reg=shift_reg9 对结果加 6,19 对结果加 12,29 对结果加 18 类推,当然高一级的 bcd 码要加上低一级的进位,也就是高出 4 位的部分,最后把结果拼接 给你一个 16 位有符号的例子module bcd(clk,hex,dec);input clk;input 16:0 hex;output 19:0 dec;wire 15:0 rrhex;reg 3:0 rhex3:0;reg 17:0 rhexd;reg 13:0 rhexc;reg 9:0
9、rhexb;reg 3:0 rhexa;reg 5:0 resa,resb,resc,resd;reg 3:0 rese;assign rrhex = hex16 ? hex15:0+1b1 : hex15:0; /去符号assign dec = rese,resd3:0,resc3:0,resb3:0,resa3:0;always(posedge clk) /第一级寄存器beginrhex3 6h1d) /29 最低有一个可能出现 0xf,但由二进制转换而来的数在这里不会出现大于 40 的情况addbcd4 = addbcd4 + 5h12;else if(addbcd4 5h13) /19
10、addbcd4 = addbcd4 + 4hc;else if(addbcd4 4h9) /9addbcd4 = addbcd4 + 4h6;endendfunctionendmodule利用 verilog 将二进制码转换为十进制 BCD 码 分类: FPGA verilog 2014-02-20 10:54 2359 人阅读 评论(7) 收藏 举报 二进制十进制 BCDverilog小序 :先说一个 bear 的亲身体会,bear 在做一些 fpga 小设计时经常会用到数据显示功能,比如数字时钟,数字频率计,温度计,跑表等等,往往我们会选用led 数码管来做显示, 因为它驱动起来比 lcd
11、 液晶要简单的很多,我们知道 fpga 中寄存器在定义和储存的数据都是采用二进制的格式 ,而 fpga 输出给数码管做显示的数据必须是十进制的格式 , 之前 bear 经常会选择把一个寄存器的个位和十位分开定义 ,比如在做数字时钟时 ,就会吧 时,分,秒的各位和十位都分别定义成一个变量 ,无疑这种方法会增加代码的复杂度 ,所以考虑需要一个专门把 二进制 的数据转换成 十进制 BCD 码的模块 ,在网上有一些,但是好像都不太完整 , 所以 bear 花了一下午写了一个 ,亲测效果不错 ,希望对朋友们有所帮助,下面开始正文。首先给出二进制码转换为十进制 BCD 码的几个步骤(以 8bit 二进制码
12、为例):1.将二进制码左移一位(或者乘 2)2.找到左移后的码所对应的个,十,百位。3.判断在个位和百位的码是否大于 5,如果是则该段码加 3。4.继续重复以上三步直到移位 8 次后停止。下面是一个例子 ,将 1111_1111 转换为 BCD 码 ,如果 8bit 数据最终移位得到 18bit 数据 ,那么个位,十位,百位分别对应 129,1613,1817 位。 之前写的代码在转换完之后没有对 count 清零,所以在仿真时候需要用 rst_n 清零,感谢博友 onlytime417 的提示,经过修改之后可以对不同的输入值连续转换,而不需要 rst_n的复位,下面是修改后的代码以及仿真结果
13、,(该转换模块已经在实际项目中应用)。CODE: timescale 1ns / 1psmodule bin_dec(clk,bin,rst_n,one,ten,hun,count,shift_reg);input 7:0 bin;input clk,rst_n;output 3:0 one,ten;output 3:0 count;output 1:0 hun;output 17:0shift_reg;reg 3:0 one,ten;reg 1:0 hun;reg 3:0 count;reg 17:0shift_reg=18b000000000000000000;/ 计数部分 /always
14、 ( posedge clk or negedge rst_n )beginif( !rst_n ) count=5) /判断个位是否5,如果是则+3 beginif(shift_reg15:12=5) /判断十位是否5,如果是则+3 beginshift_reg15:12=shift_reg15:12+2b11; shift_reg11:8=shift_reg11:8+2b11;shift_reg=shift_reg=5)beginshift_reg15:12=shift_reg15:12+2b11;shift_reg11:8=shift_reg11:8;shift_reg=shift_re
15、g7?3.1 0000 1010 ;大于 7,加 3 进行调整4 0001 0101 ;左移四次, 检查低四位+37?4.1 0001 1000 ;大于 7,加 3 进行调整5 0011 0001 ;左移五次6 0110 0011 ;左移六次, 检查高四位+37?6.1 1001 0011 ;大于 7,加 3 进行调整7 1 0010 0111 ;左移七次 ,检查低四位+37?7.1 1 0010 1010 ;大于 7,加 3 进行调整8 10 0101 0101 ;左移八次 (得到 BCD 码 255)附上 Verilog 代码:/17 位二进制数转 BCD 码(基本思想是逢十进 1)mod
16、ule BIN_BCD_4 (CLK, A, BW, BQ, BB, BS, BG);input CLK;input 16:0A; /二进制输入数据output 3:0BW, BQ, BB, BS, BG;/BCD 数据输出寄存器reg 3:0BW, BQ, BB, BS, BG;integer I;reg 19:0TEMP;reg 16:0C;always (posedge CLK)beginC=A;TEMP=0;for (I=1; I4b0100)beginTEMP3:0=TEMP3:0+3; / 4 则加 3end if (TEMP7:44b0100)beginTEMP7:4=TEMP7:4+3;end if (TEMP11:84b0100)beginTEMP11:8=TEMP11:8+3;end if (TEMP15:124b0100)beginTEMP15:12=TEMP15:12+3;end if (TEMP19:164b0100)beginTEMP19:16=TEMP19:16+3;end BW, BQ, BB, BS, BG=TEMP18:0, A0;endendendmodule