Verilog應用範例 : 二進制轉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,也就是左移一位。轉換公式大概就是這個樣子。
代碼實現起來不是很復雜,在網上搜索到有些代碼使用純組合邏輯實現的,用了一個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 : ninghechuan@foxmail.com
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 endmodule
//適用於DE2-115
module Binary_BCD(
input CLOCK_50, // 50 MHz clock
input [3:0] KEY, // Pushbutton[3:0]
input [17:0] SW, // Toggle Switch[17:0]
output [6:0] HEX0,HEX1,HEX2,HEX3,HEX4,HEX5,HEX6,HEX7, // Seven Segment Digits
output [8:0] LEDG, // LED Green
output [17:0] LEDR, // LED Red
inout [35:0] GPIO_0,GPIO_1, // GPIO Connections
// LCD Module 16X2
output LCD_ON, // LCD Power ON/OFF
output LCD_BLON, // LCD Back Light ON/OFF
output LCD_RW, // LCD Read/Write Select, 0 = Write, 1 = Read
output LCD_EN, // LCD Enable
output LCD_RS, // LCD Command/Data Select, 0 = Command, 1 = Data
inout [7:0] LCD_DATA, // LCD Data bus 8 bits
input [2:0] mess, // MESSAGE STATUS (see lcd_test)
input [1:0] isServer // SERVER STATUS (see lcd_test)
);
// All inout port turn to tri-state
assign GPIO_0 = 36'hzzzzzzzzz;
assign GPIO_1 = 36'hzzzzzzzzz;
// blank unused 7-segment digits
// blank unused 7-segment digits
//assign HEX0 = 7'b111_1111;
//assign HEX1 = 7'b111_1111;
//assign HEX2 = 7'b111_1111;
//assign HEX3 = 7'b111_1111;
assign HEX4 = 7'b111_1111;
assign HEX5 = 7'b111_1111;
assign HEX6 = 7'b111_1111;
assign HEX7 = 7'b111_1111;
wire [7:0] segout0; //HEX 0
wire [7:0] segout1; //HEX 1
wire [7:0] segout2; //HEX 2
wire [7:0] segout3; //HEX 3
wire [3:0] othou_data; //千位
wire [3:0] ohund_data; //百位
wire [3:0] otens_data; //十位
wire [3:0] ounit_data; //個位
assign LEDR =SW ;
Bin_BCD
(
CLOCK_50,
KEY[0],
SW[17],
SW[15:0],
LEDG[0],
othou_data, //千位
ohund_data, //百位
otens_data, //十位
ounit_data //個位
);
_7seg UUT0(.hex(ounit_data),
.seg(segout0));
_7seg UUT1(.hex(otens_data),
.seg(segout1));
_7seg UUT2(.hex(ohund_data),
.seg(segout2));
_7seg UUT3(.hex(othou_data),
.seg(segout3));
assign HEX0=segout0[6:0];
assign HEX1=segout1[6:0];
assign HEX2=segout2[6:0];
assign HEX3=segout3[6:0];
endmodule
module Bin_BCD
#(
parameter DATA_WIDTH = 16,
parameter SHIFT_WIDTH = 5,
parameter SHIFT_DEPTH = 16
)
(
input clk,
input rst_n,
input tran_en,
input [DATA_WIDTH - 1:0] data_in,
output reg tran_done,
output [3:0] thou_data, //千位
output [3:0] hund_data, //百位
output [3:0] tens_data, //十位
output [3:0] unit_data //個位
);
//-------------------------------------------------------
localparam IDLE = 3'b001;
localparam SHIFT = 3'b010;
localparam DONE = 3'b100;
//-------------------------------------------------------
reg [2:0] pre_state;
reg [2:0] next_state;
//
reg [SHIFT_DEPTH-1:0] shift_cnt;
//
reg [DATA_WIDTH:0] data_reg;
reg [3:0] thou_reg;
reg [3:0] hund_reg;
reg [3:0] tens_reg;
reg [3:0] unit_reg;
reg [3:0] thou_out;
reg [3:0] hund_out;
reg [3:0] tens_out;
reg [3:0] unit_out;
wire [3:0] thou_tmp;
wire [3:0] hund_tmp;
wire [3:0] tens_tmp;
wire [3:0] unit_tmp;
//-------------------------------------------------------
//FSM step1
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
pre_state <= IDLE;
end
else begin
pre_state <= next_state;
end
end
//FSM step2
always @(*)begin
case(pre_state)
IDLE:begin
if(tran_en == 1'b1)
next_state = SHIFT;
else
next_state = IDLE;
end
SHIFT:begin
if(shift_cnt == SHIFT_DEPTH + 1)
next_state = DONE;
else
next_state = SHIFT;
end
DONE:begin
next_state = IDLE;
end
default:next_state = IDLE;
endcase
end
//FSM step3
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
thou_reg <= 4'b0;
hund_reg <= 4'b0;
tens_reg <= 4'b0;
unit_reg <= 4'b0;
tran_done <= 1'b0;
shift_cnt <= 'd0;
data_reg <= 'd0;
end
else begin
case(next_state)
IDLE:begin
thou_reg <= 4'b0;
hund_reg <= 4'b0;
tens_reg <= 4'b0;
unit_reg <= 4'b0;
tran_done <= 1'b0;
shift_cnt <= 'd0;
data_reg <= data_in;
end
SHIFT:begin
if(shift_cnt == SHIFT_DEPTH + 1)
shift_cnt <= 'd0;
else begin
shift_cnt <= shift_cnt + 1'b1;
data_reg <= data_reg << 1;
unit_reg <= {unit_tmp[2:0], data_reg[16]};
tens_reg <= {tens_tmp[2:0], unit_tmp[3]};
hund_reg <= {hund_tmp[2:0], tens_tmp[3]};
thou_reg <= {thou_tmp[2:0], hund_tmp[3]};
end
end
DONE:begin
tran_done <= 1'b1;
end
default:begin
thou_reg <= thou_reg;
hund_reg <= hund_reg;
tens_reg <= tens_reg;
unit_reg <= unit_reg;
tran_done <= tran_done;
shift_cnt <= shift_cnt;
end
endcase
end
end
//-------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
thou_out <= 'd0;
hund_out <= 'd0;
tens_out <= 'd0;
unit_out <= 'd0;
end
else if(tran_done == 1'b1)begin
thou_out <= thou_reg;
hund_out <= hund_reg;
tens_out <= tens_reg;
unit_out <= unit_reg;
end
else begin
thou_out <= thou_out;
hund_out <= hund_out;
tens_out <= tens_out;
unit_out <= unit_out;
end
end
//-------------------------------------------------------
assign thou_tmp = (thou_reg > 4'd4)? (thou_reg + 2'd3) : thou_reg;
assign hund_tmp = (hund_reg > 4'd4)? (hund_reg + 2'd3) : hund_reg;
assign tens_tmp = (tens_reg > 4'd4)? (tens_reg + 2'd3) : tens_reg;
assign unit_tmp = (unit_reg > 4'd4)? (unit_reg + 2'd3) : unit_reg;
assign thou_data = thou_out;
assign hund_data = hund_out;
assign tens_data = tens_out;
assign unit_data = unit_out;
endmodule
//-----------------------------------------
//Common-cathod seven segment display
//using case.....endcase statement
//Filename : sevenseg_case.v
//-----------------------------------------
module _7seg(hex , seg);
input [3:0] hex;
output [7:0] seg;
reg [7:0] seg;
// segment encoding
// 0
// ---
// 5 | | 1
// --- <- 6
// 4 | | 2
// ---
// 3
always @(hex)
begin
case (hex)
// Dot point is always disable
4'b0001 : seg = 8'b11111001; //1 = F9H
4'b0010 : seg = 8'b10100100; //2 = A4H
4'b0011 : seg = 8'b10110000; //3 = B0H
4'b0100 : seg = 8'b10011001; //4 = 99H
4'b0101 : seg = 8'b10010010; //5 = 92H
4'b0110 : seg = 8'b10000010; //6 = 82H
4'b0111 : seg = 8'b11111000; //7 = F8H
4'b1000 : seg = 8'b10000000; //8 = 80H
4'b1001 : seg = 8'b10010000; //9 = 90H
4'b1010 : seg = 8'b10001000; //A = 88H
4'b1011 : seg = 8'b10000011; //b = 83H
4'b1100 : seg = 8'b11000110; //C = C6H
4'b1101 : seg = 8'b10100001; //d = A1H
4'b1110 : seg = 8'b10000110; //E = 86H
4'b1111 : seg = 8'b10001110; //F = 8EH
default : seg = 8'b11000000; //0 = C0H
endcase
end
endmodule
沒有留言:
張貼留言