基於Verilog HDL的二進制轉BCD碼實現
在項目設計中,經常需要顯示一些數值,比如溫濕度,時間等等。在數字電路中數據都是用二進制的形式存儲,要想顯示就需要進行轉換,對於一個兩位的數值,對10取除可以得到其十位的數值,對10取余可以得到個位的數值。對於Verilog來說它的標準是支持除法和取余運算的,綜合器也會有IP可以進行除法運算。但是這樣未免會耗費太多資源,使用移位加3算法就可以實現二進制到BCD碼之間的轉換。
BCD碼(Binary-Coded Decimal)亦稱二進碼十進數或二-十進制代碼。用4位二進制數來表示1位十進制數中的0~9這10個數碼。
移位加3算法簡單來說就是,有多少位二進制說,就進行多少次移位,以八位的二進制為例,其數值最高可為三位十進制數,進行如下表左移,在移位的過程中,如果移位出的數值大於4,則將改為的數值加3後再進行移位。
這裏為什麽大於四,BCD碼是四位二進制數表示一個十進制數的一位,如果這以為大於4,比如5,4’b0101,下一次移位後變成了4’b1010,BCD碼中是沒有4’b1010的,所以要加6,向高位進位。這裏就是移位後加6和移位前加3,兩種方法修正,我這裏選擇了移位前加3。(4’b0011左移後也是4’b0110,移位前和移位後都是一樣的對BCD碼的位數進行修正)。
為什麽用左移的方法呢?這是因為二進制數和十進制數之間的位權的關系。所以二進數和十進制數之間的轉化是乘以2,也就是左移一位。轉換公式大概就是這個樣子。
公式編輯采用Markdown編輯器Typora完成,Typora支持LaTex語法,編寫公式真是爽。
代碼實現起來不是很復雜,博主在網上搜索到有些代碼使用純組合邏輯實現的,用了一個for循環,我個人認為這種寫法不是很好,所以自己用狀態機寫了一個。模塊設計如下,tran_en是轉換使能信號,可以使電平使能也可以是脈沖使能,作為脈沖使能使用的時候,需要在數據來臨之後的一個時鐘周期給出使能(我的模塊是這樣的特點),電平使能有效時,需要18個時鐘周期完成轉換,輸入二進制位16bit,輸出為四組千百十個位。轉換完成後輸出一個轉換完成標誌tran_done。
內部的時序我采用了三段式狀態機來完成。IDLE狀態接收到使能信號,調到移位狀態,經過16次移位。在shift_cnt為17時(這裏是因為我狀態機的原理所以shift_cnt會計數到17,但移位次數為16),數據轉換完成。跳到DONE狀態,輸出轉換完成標誌。
采用組合邏輯來實現,移位後的數據值的判斷,大於4加3後再進行移位。最後將轉換完成後的結果輸出。
代碼如下:
1 `timescale 1ns/1ps 2 // ********************************************************************************* 3 // Project Name : 4 // Author : NingHeChuan 5 // Email : [email protected] 6 // Blogs : http://www.cnblogs.com/ninghechuan/ 7 // File Name : Bin_BCD.v 8 // Module Name : 9 // Called By : 10 // Abstract : 11 // 12 // CopyRight(c) 2018, NingHeChuan Studio.. 13 // All Rights Reserved 14 // 15 // ********************************************************************************* 16 // Modification History: 17 // Date By Version Change Description 18 // ----------------------------------------------------------------------- 19 // 2018/8/12 NingHeChuan 1.0 Original 20 // 21 // ********************************************************************************* 22 23 module Bin_BCD 24 #( 25 parameter DATA_WIDTH = 16, 26 parameter SHIFT_WIDTH = 5, 27 parameter SHIFT_DEPTH = 16 28 29 ) 30 ( 31 input clk, 32 input rst_n, 33 input tran_en, 34 input [DATA_WIDTH - 1:0] data_in, 35 output reg tran_done, 36 output [3:0] thou_data, //千位 37 output [3:0] hund_data, //百位 38 output [3:0] tens_data, //十位 39 output [3:0] unit_data //個位 40 41 ); 42 //------------------------------------------------------- 43 localparam IDLE = 3‘b001; 44 localparam SHIFT = 3‘b010; 45 localparam DONE = 3‘b100; 46 47 //------------------------------------------------------- 48 reg [2:0] pre_state; 49 reg [2:0] next_state; 50 // 51 reg [SHIFT_DEPTH-1:0] shift_cnt; 52 // 53 reg [DATA_WIDTH:0] data_reg; 54 reg [3:0] thou_reg; 55 reg [3:0] hund_reg; 56 reg [3:0] tens_reg; 57 reg [3:0] unit_reg; 58 reg [3:0] thou_out; 59 reg [3:0] hund_out; 60 reg [3:0] tens_out; 61 reg [3:0] unit_out; 62 wire [3:0] thou_tmp; 63 wire [3:0] hund_tmp; 64 wire [3:0] tens_tmp; 65 wire [3:0] unit_tmp; 66 67 //------------------------------------------------------- 68 //FSM step1 69 always @(posedge clk or negedge rst_n)begin 70 if(rst_n == 1‘b0)begin 71 pre_state <= IDLE; 72 end 73 else begin 74 pre_state <= next_state; 75 end 76 end 77 78 //FSM step2 79 always @(*)begin 80 case(pre_state) 81 IDLE:begin 82 if(tran_en == 1‘b1) 83 next_state = SHIFT; 84 else 85 next_state = IDLE; 86 end 87 SHIFT:begin 88 if(shift_cnt == SHIFT_DEPTH + 1) 89 next_state = DONE; 90 else 91 next_state = SHIFT; 92 end 93 DONE:begin 94 next_state = IDLE; 95 end 96 default:next_state = IDLE; 97 endcase 98 end 99 100 //FSM step3 101 always @(posedge clk or negedge rst_n)begin 102 if(rst_n == 1‘b0)begin 103 thou_reg <= 4‘b0; 104 hund_reg <= 4‘b0; 105 tens_reg <= 4‘b0; 106 unit_reg <= 4‘b0; 107 tran_done <= 1‘b0; 108 shift_cnt <= ‘d0; 109 data_reg <= ‘d0; 110 end 111 else begin 112 case(next_state) 113 IDLE:begin 114 thou_reg <= 4‘b0; 115 hund_reg <= 4‘b0; 116 tens_reg <= 4‘b0; 117 unit_reg <= 4‘b0; 118 tran_done <= 1‘b0; 119 shift_cnt <= ‘d0; 120 data_reg <= data_in; 121 end 122 SHIFT:begin 123 if(shift_cnt == SHIFT_DEPTH + 1) 124 shift_cnt <= ‘d0; 125 else begin 126 shift_cnt <= shift_cnt + 1‘b1; 127 data_reg <= data_reg << 1; 128 unit_reg <= {unit_tmp[2:0], data_reg[16]}; 129 tens_reg <= {tens_tmp[2:0], unit_tmp[3]}; 130 hund_reg <= {hund_tmp[2:0], tens_tmp[3]}; 131 thou_reg <= {thou_tmp[2:0], hund_tmp[3]}; 132 end 133 end 134 DONE:begin 135 tran_done <= 1‘b1; 136 end 137 default:begin 138 thou_reg <= thou_reg; 139 hund_reg <= hund_reg; 140 tens_reg <= tens_reg; 141 unit_reg <= unit_reg; 142 tran_done <= tran_done; 143 shift_cnt <= shift_cnt; 144 end 145 endcase 146 end 147 end 148 //------------------------------------------------------- 149 always @(posedge clk or negedge rst_n)begin 150 if(rst_n == 1‘b0)begin 151 thou_out <= ‘d0; 152 hund_out <= ‘d0; 153 tens_out <= ‘d0; 154 unit_out <= ‘d0; 155 end 156 else if(tran_done == 1‘b1)begin 157 thou_out <= thou_reg; 158 hund_out <= hund_reg; 159 tens_out <= tens_reg; 160 unit_out <= unit_reg; 161 end 162 else begin 163 thou_out <= thou_out; 164 hund_out <= hund_out; 165 tens_out <= tens_out; 166 unit_out <= unit_out; 167 end 168 end 169 170 171 //------------------------------------------------------- 172 assign thou_tmp = (thou_reg > 4‘d4)? (thou_reg + 2‘d3) : thou_reg; 173 assign hund_tmp = (hund_reg > 4‘d4)? (hund_reg + 2‘d3) : hund_reg; 174 assign tens_tmp = (tens_reg > 4‘d4)? (tens_reg + 2‘d3) : tens_reg; 175 assign unit_tmp = (unit_reg > 4‘d4)? (unit_reg + 2‘d3) : unit_reg; 176 177 assign thou_data = thou_out; 178 assign hund_data = hund_out; 179 assign tens_data = tens_out; 180 assign unit_data = unit_out; 181 182 183 endmoduleBin_BCD
轉載請註明出處:NingHeChuan(寧河川)
個人微信訂閱號:開源FPGA
如果你想及時收到個人撰寫的博文推送,可以掃描左邊二維碼(或者長按識別二維碼)關註個人微信訂閱號
知乎ID:NingHeChuan
微博ID:NingHeChuan
原文地址:https://www.cnblogs.com/ninghechuan/p/9464037.html
基於Verilog HDL的二進制轉BCD碼實現