二进制转BCD码(8421)

       在显示温度、电压、电流等数据时,通常需要将二进制数据转成十进制进行显示。最常用的方法是将二进制码转换成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)

=()1101

由于我们要转换成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

猜你喜欢

转载自blog.csdn.net/xs20180801/article/details/84716098