1. 程式人生 > >二進位制轉BCD碼(8421)

二進位制轉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;
[email protected](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
[email protected](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
[email protected](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