在显示温度、电压、电流等数据时,通常需要将二进制数据转成十进制进行显示。最常用的方法是将二进制码转换成BCD码(8421)。
8421码:它只选用了四位二进制码中前10组代码,即用0000~1001分别代表它所对应的十进制数,余下的六组代码不用。
我们将二进制数(1101_0101)转换成十进制数(27+26+24+22+20),对于硬件来说,我们用乘方描述会浪费很多资源。于是,我们迫切寻找一个优化方案。
当我们将乘方通过二项式定理展开((((((2+1)*2+0)*2+1)*2+0)*2+1)*2+0)*2+1)之后,我们好像去掉了乘方。((((((2+1)*2+0)*2+1)*2+0)*2+1)*2+0)*2+1)=(((((((0+1)2+1)*2+0)*2+1)*2+0)*2+1)*2+0)*2+1)
我们发现,二项式乘的系数是2。在编程中,乘2可以用移位来代替。通过一系列优化之后发现,二进制数转换成十进制数就只需要移位和加法运算。
由于BCD码是4个位宽,所以我们在判断时以4个位宽进行判断。将满16进1调整为满10进1。
二项式 | (BCD)BIN |
(0+1) | =(1)0001 |
((0+1)2+1) | =(3)0011 |
(((0+1)2+1)*2+0) | =(6)0110 |
((((0+1)2+1)*2+0)*2+1) | =() |
由于我们要转换成BCD码,不可能出现1101的情况,所以当上一个值大于等于5时,就先要进行加3,再移位。很多人不明白为什么是加3?其实,当上一个值大于等于5时,说明我们移位后的值会大于等于10,所以我们需要向前进一位,而4位二进制是满16才进一位。这时候我们就需要将数值中的10变成16,可以将该数值加6。对上一个值来说,就是加3。
二项式 | (BCD)BIN |
(0+1) | =(1)0001 |
((0+1)2+1) | =(3)0011 |
(((0+1)2+1)*2+0) | =(6)0110 |
((((0+1)2+1)*2+0)*2+1) | =(13)1_0011 |
(((((0+1)2+1)*2+0)*2+1)*2+0) | =(26)10_0110 |
((((((0+1)2+1)*2+0)*2+1)*2+0)*2+1) | =(53)101_0011 |
(((((((0+1)2+1)*2+0)*2+1)*2+0)*2+1)*2+0) | =(106)1_0000_0110 |
((((((((0+1)2+1)*2+0)*2+1)*2+0)*2+1)*2+0)*2+1) | =(213)10_0001_0011 |
由于转换是串行执行,二进制数的位宽为多少就有几个时钟周期的延时。例如 :1MHz的时钟周期,二进制数的位宽为1000位,延迟时间为1ms,对于人眼来说,不过一眨眼而已。
下面是我一起将AD_TCL549数据经过该模块转换后在数码管显示时所使用的代码,有点缺陷,但能使用。具体的代码说明会在写AD_TCL549时描述
module BCD (
input wire clk ,
input wire rst_n ,
input wire data_flag,
input wire [11:0] din ,
output reg dout_en,
output reg [15:0] dout
);
//cnt_12
reg [3:0] cnt_12;
parameter CNT_12_MAX = 12;
always@(posedge clk or negedge rst_n)
if(!rst_n)
cnt_12 <= 0;
else if(cnt_12==CNT_12_MAX)
cnt_12 <= 0;
else if(data_flag || cnt_12)
cnt_12 <= cnt_12 +1'b1;
//dout
always@(posedge clk or negedge rst_n)
if(!rst_n)
dout = 0;
else if(data_flag)
dout = 0;
else if(cnt_12)
begin
if(dout[3:0]>=5)
dout[3:0] = dout[3:0] +3;
if(dout[7:4]>=5)
dout[7:4] = dout[7:4] +3;
if(dout[11:8]>=5)
dout[11:8] = dout[11:8] +3;
if(dout[15:12]>=5)
dout[15:12] = dout[15:12] +3;
dout = {dout[14:0],din[12-cnt_12]};
end
//dout_en
always@(posedge clk or negedge rst_n)
if(!rst_n)
dout_en <= 0;
else if(cnt_12==CNT_12_MAX)
dout_en <= 1;
else
dout_en <= 0;
endmodule