二進位制轉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) |
=() |
由於我們要轉換成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