写在前面的话 我们的数据在运算或者存储的时候,一般都是以二进制的格式存在的。但是在很多情况下,我们需要将运算结果显示到某种显示设备上,如果直接以二进制的形式来显示的话,会非常不便于我们查看。因此,我们需要首先将二进制数转换为十进制数再进行显示。二进制到十进制的转换有很多种方法。本节,梦翼师兄和大家一起学习一种国外目前最为流行的转换方法-逐步移位法。通过这种方式,我们不但可以在没有周期差的情况下实现数据格式的转换,同时我们的资源占用量也是相当小的。 基本概念 BCD码(Binary-Coded Decimal)也称二进码十进数或二-十进制代码。用4位二进制数来表示1位十进制数中的0~9这10个数码。BCD码这种编码形式利用了四个位元来储存一个十进制的数码,使二进制和十进制之间的转换得以快捷的进行。这种编码技巧在FPGA中经常用到,如矩阵键盘输入的数据需要在数码管上显示的时候,矩阵键盘输入的数字是二进制数,而数码管上需要显示的是十进制数,所以需要将二进制数转换成BCD码,这在我们以后的设计中会经常遇到。 7.3.3逐步移位法原理 在本设计中,我们使用逐步移位法来实现二进制数向BCD码的转换,在设计之前,我们先来了解一下二进制数向BCD码转换的原理-逐步移位法: 变量定义: B:需要转换的二进制数位宽 D:转换后的BCD码位宽(其中BCD码的位宽计算如下:根据二进制数的位宽,求出它的无符号数能表示的最大值和最小值,如数据位宽是8位则数据范围大小就是0~255,我们取最大值255,每一个数字对应4位BCD码,三个数字就对应3x4=12位的BCD码) N:需要转换的二进制数位宽加上转换后的BCD码位宽 逐步移位法的规则: - 准备一个N比特的移位寄存器;
- 二进数逐步左移;
- 每次左移之后每个BCD位做大四加三的调整;
- 二进数全部移完,得到结果。
- 设计任务
我们本次的设计任务是将一个8位的二进制数转换成BCD码 分析如下:输入二进制数据的位宽是B=8位,用无符号数来表示的话,输入数据的范围大小就是0~255,我们取最大值255,其中每一个数字需要4位的BCD码来表示,所以BCD码的长度就是D=3x4=12比特。 总结: - 准备一个N=B+D=8+12=20比特的移位寄存器;
- 二进数逐步左移;
- 每次左移之后每个BCD位做大四加三的调整;
- 二进数全部移完,得到结果。
现在,我们列一个表格来说明逐步移位法:
第几次移位 | BCD[11:8] | BCD[7:4] | BCD[3:0] | Bin[7:0] | Start |
|
|
| 10100101 | 1 |
|
| 1 | 01001010 | 2 |
|
| 10 | 10010100 | 3 |
|
| 101 | 00101000 | 3 |
|
| 1000 | 00101000 | 4 |
| 1 | 0000 | 01010000 | 5 |
| 10 | 0000 | 10100000 | 6 |
| 100 | 0001 | 01000000 | 7 |
| 1000 | 0010 | 10000000 | 7 |
| 1011 | 0010 | 10000000 | 8 | 1 | 0110 | 0101 | 00000000 | BCD | 1 | 6 | 5 |
|
由上表知: Bin = 10100101 = 165; BCD = 0001_0110_0101 = 1_6_5 = 165; 由此可知,逐步位移法是可以把二进制数转变成BCD码的。 顶层框图设计 我们掌握了上面的基本概念和明确了设计任务后,就可以开始设计我们的电路了,梦翼师兄的思路是首先建立一个bin_to_bcd的顶层模块,这个模块的主要功能是将输入的二进制数据进行扩展,然后将扩展后的数据输入到下一层的模块进行移位,最后将最后一次移位的结果取高12位输出即可;然后建立一个bcd_modify模块,这个模块的功能是将输入的数据进行移位,并将输入的数据的高12位分成3组分别输入到下一层的比较模块进行比较,每一次比较结束进行一次移位并输出数据;最后建立一个cmp模块,这个模块的主要功能是将输入的数据进行大四加三的调整,然后输出。各个模块的框图设计如下: bin_to_bcd 顶层框架设计
bcd_modify 模块的框架设计:
cmp模块的框架设计:
代码实现 设计好上面的模块框图后,接着我们使用Verilog语言,把上述的电路结构描述出来: bin_to_bcd顶层架构的代码如下: /****************************************************
* Engineer : 梦翼师兄
* QQ : 761664056
* The module function : 二进制数转8421BCD码顶层模块
*****************************************************/
01 module bin_to_bcd(
02 bin, //二进制数输入
03 bcd //BCD码输出
04 );
05
06 input [7:0] bin; //二进制数输入
07 output [11:0] bcd; //BCD码输出
08
09 wire [19:0] bcd_reg_0,bcd_reg_1,bcd_reg_2,bcd_reg_3,bcd_reg_4,
10 bcd_reg_5,bcd_reg_6,bcd_reg_7,bcd_reg_8; //8次移位结果输出
11
12 assign bcd_reg_0={12'b000000000000,bin}; //把输入的8位二进制数转换成20位
13
14 //第一次移位
15 bcd_modify b1(.data_in(bcd_reg_0),.data_out(bcd_reg_1));
16 //第二次移位
17 bcd_modify b2(.data_in(bcd_reg_1),.data_out(bcd_reg_2));
18 //第三次移位
19 bcd_modify b3(.data_in(bcd_reg_2),.data_out(bcd_reg_3));
20 //第四次移位
21 bcd_modify b4(.data_in(bcd_reg_3),.data_out(bcd_reg_4));
22 //第五次移位
23 bcd_modify b5(.data_in(bcd_reg_4),.data_out(bcd_reg_5));
24 //第六次移位
25 bcd_modify b6(.data_in(bcd_reg_5),.data_out(bcd_reg_6));
26 //第七次移位
27 bcd_modify b7(.data_in(bcd_reg_6),.data_out(bcd_reg_7));
28 //第八次移位
29 bcd_modify b8(.data_in(bcd_reg_7),.data_out(bcd_reg_8));
30
31 assign bcd={bcd_reg_8[19:8]}; //取高12位为输出结果
32
33 endmodule
|
第9~10行我们定义了9个位宽是20的寄存器,第一个寄存器bcd_reg_0我们存放的是输入数据扩展之后的数据,也就是在第12行我们把输入的8位二进制数转换成了20位;第15~29行我们把bcd_modify模块例化了8次,前一个例化模块的输出总是当前模块的输入,比如第23行,输入的数据是bcd_reg_4,在进行了一次移位之后,输出的数据是bcd_reg_5,然后bcd_reg5又作为下一个第25行例化模块的输入,依次向下一级一级传递,进行了8次移位之后,第31行直接取第8次移位之后的结果的高12位作为转换后的BCD码输出。 bcd_modify模块的代码如下: /****************************************************
* Engineer : 梦翼师兄
* QQ : 761664056
* The module function : 移位模块
*****************************************************/
01 module bcd_modify(
02 data_in, //需要移位比较数据输入
03 data_out //移位比较完成数据输出
04 );
05
06 input [19:0]data_in; //需要移位比较数据输入
07 output [19:0]data_out; //移位比较完成数据输出
08
09 wire [3:0]bcd_reg2,bcd_reg3,bcd_reg1; //3次移位结果输出
10
11 //data_in[19:16]进行大四加三比较
12 cmp c1(.cmp_in(data_in[19:16]),.cmp_out(bcd_reg1));
13 //data_in[15:12]进行大四加三比较
14 cmp c2(.cmp_in(data_in[15:12]),.cmp_out(bcd_reg2));
15 //data_in[11:8]进行大四加三比较
16 cmp c3(.cmp_in(data_in[11:8]), .cmp_out(bcd_reg3));
17
18 //data_in[19:8]全部比较完之后,左移一位
19 assign data_out={bcd_reg1[2:0],bcd_reg2,bcd_reg3,data_in[7:0],1'b0};
20
21 endmodule
|
第9行我们定义了3个位宽是4的寄存器,作用是存放比较之后的数据;第11~16行把cmp模块例化了3次,我们把输入数据的高12位分成3组分别送进了这3个例化模块的输入端口,作用是进行大四加三的调整;第19行将第12行~16行输出的数据存放到输出寄存器中进行一次左移操作。
cmp模块的代码如下: /****************************************************
* Engineer : 梦翼师兄
* QQ : 761664056
* The module function : 大四加三处理模块
*****************************************************/
01 module cmp(
02 cmp_in, //比较器数据输入
03 cmp_out //比较器数据输出
04 );
05
06 input [3:0]cmp_in; //比较器数据输入
07 output reg [3:0]cmp_out; //比较器数据输出
08
09 always @ (*)
10 begin
11 if (cmp_in > 4)
12 cmp_out = cmp_in + 3; //输入数据大四加三处理
13 else
14 cmp_out = cmp_in; //输入数据小于四不做任何处理
15 end
16
17 endmodule
|
这个模块挺简单的,第9~15行只是将输入的数据和4进行了比较,大于4输出就是输入数据加三,小于4输入数据不做任何处理直接输出即可。 编写的测试代码如下: 01 `timescale 1ns/1ps //仿真时间单位是ns,仿真时间精度是ns
02 module bcd_tb;
03
04 reg [7:0]bin; //仿真激励二进制输入数据
05
06 wire [11:0]bcd; //仿真输出BCD码
07
08 bin_to_bcd u1(.bin(bin),.bcd(bcd)); //把激励信号送进BCD转换器
09
10 initial begin
11 bin=8'b0; //bin信号初始化
12 #100 bin=8'b1010_1101; //输入数据 173
13 #100 bin=8'b0000_1101; //输入数据 13
14 #100 bin=8'b1010_0100; //输入数据 164
15 #100 bin=8'b1000_0000; //输入数据 128
16 #100 bin=8'b1111_1111; //输入数据 255
17 end
18
19 endmodule
|
仿真分析
如图所示,输入数据bin(无符号十进制表达)的值等于bcd(十六进制表达)输出的值,所以本次设计是成功的。
|