1.功能概述
篮球是一种以将篮球投入对方篮框里的对抗性体育运动,与足球、排球一起被称为“三大球”,是当今世界上最为广泛和受到关注的体育运动之一。24秒进攻规则是篮球比赛中非常重要的一项规则,保证了篮球运动的激烈性和观赏性。其主要内容时当某队在比赛中获得新的球权时,或在掷球入界中当球在场上被队员合法触及时,拥有球权的队必须在获得球后的24秒钟内投篮。完成投篮的条件是:(1)在24秒钟结束之前,球必须离开队员的手;(2)球离开队员的手后,球必须与篮圈接触。如果在24秒钟哨响前球出手后未接触篮圈,为24秒钟违例。发球权判给对方。可想而知,倒数计时系统非常适用于这项比赛规则。
篮球24秒倒计时是倒计时系统的一个典型运用。实际上,倒计时系统是一个非常常见的电路系统,生活中我们见到的如香港回归倒计时、某大型活动倒计时、评估倒计时等都属于此类。与单片机等实现模式相比,FPGA倒计时系统大大简化,整体性能和可靠性得到提高。在篮球24秒倒计时的模块架构设计方面,只需要一级架构下的BCD译码模块、倒计时模块和数码管显示模块,即可实现24秒倒计时功能。
具体功能要求:
本项目包含两个按键和4位数码管显示,要求共同实现一个篮球24秒的倒计时,并具有暂停和重新计数复位的功能。具体功能如下:
1. 数码管显示秒十位、秒个位、0.1秒和0.01秒。
2. 上电后,数码管显示2399,表示的时间是23.99秒。
3. 按下按键S0,进入倒计时状态,进行倒计时,一直计到0000后停止。
4. 在倒计时状态时,再次按下按键S0,则暂停计时;再按下按键S0,则继续倒计时。
5. 在任何时刻,按下按键S1,则复位显示为2399。
2.设计思路
我们可以把本项目设计划分成四个模块:顶层模块、倒计时模块、BCD译码模块和数码管显示模块。
1、顶层模块
本模块的信号列表如下:
2、倒计时模块——实现的是24 s倒计时功能,其输出两组计数信号cnt_s和cnt_ms。例如,当时间为23.99时,cnt_s的值为23,cnt_ms的值为99;当时间为08.12时,cnt_s的值为8,cnt_ms的值为12。模块还实现了暂停和重开始功能。
本模块的信号列表如下:
3、 BCD译码模块——将显示的十进制数值转化为数码管的二进制表示值得过程称为BCD译码,其功能会在BCD译码一章介绍。由于秒和毫秒都要译码,所以要例化两个BCD译码模块。
本模块的信号列表如下:
4、数码管显示模块——将二进制数码,转成BCD数码管显示,其功能相对比较简单,这里不详细介绍。
本模块的信号列表如下:
3.程序设计
顶层模块代码
2 clk ,
3 rst_n ,
4 key_vld ,
5 seg_sel ,
6 segment
7 );
8
9 parameter SEG_NUM = 8 ;
10
11 input clk ;
12 input rst_n ;
13 input [1:0] key_vld ;
14 output [7:0] seg_sel ;
15 output [7:0] segment ;
16
17 wire din_vld ;
18 wire [SEG_NUM*4-1:0] din ;
19 wire [7:0] cnt_ms ;
20 wire [7:0] cnt_s ;
21 wire [7:0] bcd_ms ;
22 wire [7:0] bcd_s ;
23
24
25 cnt_down U1(
26 .clk (clk ),
27 .rst_n (rst_n ),
28 .key_vld(key_vld),
29 .cnt_ms (cnt_ms ),
30 .cnt_s (cnt_s ),
31 .din_vld(din_vld)
32 );
33
34 seg_disp #(.SEG_NUM(4)) U2(
35 .clk (clk ),
36 .rst_n (rst_n ),
37 .seg_sel(seg_sel),
38 .segment(segment),
39 .din ({bcd_s,bcd_ms})
40 );
41
42 bcd_water U3(
43 .clk (clk ) ,
44 .rst_n (rst_n ) ,
45 .din (cnt_ms ) ,
46 .din_vld(din_vld) ,
47 .dout (bcd_ms ) ,
48 .dout_vld(dout_vld )
49 );
50
51 bcd_water U4(
52 .clk (clk ) ,
53 .rst_n (rst_n ) ,
54 .din (cnt_s ) ,
55 .din_vld (din_vld) ,
56 .dout (bcd_s ) ,
57 .dout_vld(dout_vld)
58 );
59
60 endmodule
倒计时模块代码
2 clk ,
3 rst_n ,
4 cnt_s ,
5 cnt_ms ,
6 key_vld ,
7 din_vld
8 );
9 parameter TIME_10MS = 20'd500_000 ;
10 parameter TIME_20MS = 500000 ;
11
12 input clk ;
13 input rst_n ;
14 input [ 1: 0] key_vld ;
15
16 output [ 7: 0] cnt_s ;
17 output [ 7: 0] cnt_ms ;
18 output din_vld ;
19
20 reg [ 7: 0] cnt_s ;
21 reg [ 7: 0] cnt_ms ;
22 reg din_vld ;
23 reg [19: 0] cnt_10ms ;
24 reg [25: 0] cnt ;
25 reg flag ;
26 reg flag1 ;
27 reg [19:0] shake_cnt ;
28 reg [1 :0] key ;
29
30 wire add_shake_cnt ;
31 wire end_shake_cnt ;
32 wire add_cnt_s ;
33 wire end_cnt_s ;
34 wire add_cnt_ms ;
35 wire end_cnt_ms ;
36 wire add_cnt_10ms ;
37 wire end_cnt_10ms ;
38
39 always @(posedge clk or negedge rst_n)begin
40 if(rst_n==1'b0)begin
41 cnt_10ms <= 20'b0;
42 end
43 else if(add_cnt_10ms)begin
44 if(end_cnt_10ms)
45 cnt_10ms <= 20'b0;
46 else
47 cnt_10ms <= cnt_10ms + 1'b1;
48 end
49 end
50 assign add_cnt_10ms= flag;
51 assign end_cnt_10ms= (add_cnt_10ms && cnt_10ms == TIME_10MS - 1)||key[1];
52
53 always @(posedge clk or negedge rst_n)begin
54 if(rst_n==1'b0)begin
55 shake_cnt <= 0;
56 end
57 else if(add_shake_cnt)begin
58 if(end_shake_cnt)
59 shake_cnt <= 0;
60 else
61 shake_cnt <= shake_cnt + 1;
62 end
63 else begin
64 shake_cnt <= 0;
65 end
66 end
67 assign add_shake_cnt = key_vld!=0 && flag1==0;
68 assign end_shake_cnt = add_shake_cnt && shake_cnt==TIME_20MS-1;
69
70 always @(posedge clk or negedge rst_n)begin
71 if(rst_n==1'b0)begin
72 flag1 <= 0;
73 end
74 else if(end_shake_cnt)begin
75 flag1 <= 1;
76 end
77 else if(key_vld==0)begin
78 flag1 <= 0;
79 end
80 end
81
82 always @(posedge clk or negedge rst_n)begin
83 if(rst_n==1'b0)begin
84 key <= 0;
85 end
86 else if(end_shake_cnt)begin
87 key <= key_vld;
88 end
89 else begin
90 key <= 0;
91 end
92 end
93
94 always @(posedge clk or negedge rst_n)begin
95 if(rst_n==1'b0)begin
96 flag <= 1'b0;
97 end
98 else if(key[1]||end_cnt_s)begin
99 flag <= 1'b0;
100 end
101 else if(key[0])begin
102 flag <= ~flag;
103 end
104 end
105
106 always @(posedge clk or negedge rst_n)begin
107 if(rst_n==1'b0)begin
108 cnt_ms <= 8'd99;
109 end
110 else if(add_cnt_ms)begin
111 if(end_cnt_ms)
112 cnt_ms <= 8'd99;
113 else
114 cnt_ms <= cnt_ms - 1'b1;
115 end
116 end
117 assign add_cnt_ms = end_cnt_10ms;
118 assign end_cnt_ms = (add_cnt_ms && cnt_ms == 0)||key[1];
119
120 always @(posedge clk or negedge rst_n)begin
121 if(rst_n==1'b0)begin
122 cnt_s <= 8'd23;
123 end
124 else if(add_cnt_s)begin
125 if(end_cnt_s)
126 cnt_s <= 8'd23;
127 else
128 cnt_s <= cnt_s - 1'b1;
129 end
130 end
131 assign add_cnt_s = end_cnt_ms;
132 assign end_cnt_s = (add_cnt_s && cnt_s== 8'd0)||key[1];
133
134 always @(posedge clk or negedge rst_n)begin
135 if(rst_n==1'b0)begin
136 din_vld <= 1'd1;
137 end
138 else if(end_cnt_10ms)begin
139 din_vld <= 1'd1;
140 end
141 else begin
142 din_vld <= 1'd0;
143 end
144 end
145 endmodule
BCD译码模块代码
2 clk ,
3 rst_n ,
4 din ,
5 din_vld ,
6 dout ,
7 dout_vld
8 );
9
10 input clk ;
11 input rst_n ;
12 input [ 7:0] din ;
13 input din_vld ;
14 output [11:0] dout ;
15 wire [11:0] dout ;
16 output dout_vld ;
17 wire dout_vld ;
18 reg [19:0] din_temp ;
19 reg [19:0] din_temp_ff0 ;
20 reg [19:0] din_temp_ff1 ;
21 reg [19:0] din_temp_ff2 ;
22 reg [19:0] din_temp_ff3 ;
23 reg [19:0] din_temp_ff4 ;
24 wire [20:0] din_shift_temp ;
25 wire [20:0] din_shift_temp_ff0 ;
26 wire [20:0] din_shift_temp_ff1 ;
27 wire [20:0] din_shift_temp_ff2 ;
28 wire [20:0] din_shift_temp_ff3 ;
29 wire [ 7:0] din_a_temp ;
30 wire [ 3:0] din_b_temp ;
31 wire [ 3:0] din_c_temp ;
32 wire [ 3:0] din_d_temp ;
33 wire [ 7:0] din_add_a_temp ;
34 wire [ 3:0] din_add_b_temp ;
35 wire [ 3:0] din_add_c_temp ;
36 wire [ 3:0] din_add_d_temp ;
37
38 wire [ 7:0] din_a_temp_ff0 ;
39 wire [ 3:0] din_b_temp_ff0 ;
40 wire [ 3:0] din_c_temp_ff0 ;
41 wire [ 3:0] din_d_temp_ff0 ;
42 wire [ 7:0] din_a_temp_ff1 ;
43 wire [ 3:0] din_b_temp_ff1 ;
44 wire [ 3:0] din_c_temp_ff1 ;
45 wire [ 3:0] din_d_temp_ff1 ;
46 wire [ 7:0] din_a_temp_ff2 ;
47 wire [ 3:0] din_b_temp_ff2 ;
48 wire [ 3:0] din_c_temp_ff2 ;
49 wire [ 3:0] din_d_temp_ff2 ;
50 wire [ 7:0] din_a_temp_ff3 ;
51 wire [ 3:0] din_b_temp_ff3 ;
52 wire [ 3:0] din_c_temp_ff3 ;
53 wire [ 3:0] din_d_temp_ff3 ;
54 wire [ 7:0] din_add_a_temp_ff0 ;
55 wire [ 3:0] din_add_b_temp_ff0 ;
56 wire [ 3:0] din_add_c_temp_ff0 ;
57 wire [ 3:0] din_add_d_temp_ff0 ;
58 wire [ 7:0] din_add_a_temp_ff1 ;
59 wire [ 3:0] din_add_b_temp_ff1 ;
60 wire [ 3:0] din_add_c_temp_ff1 ;
61 wire [ 3:0] din_add_d_temp_ff1 ;
62 wire [ 7:0] din_add_a_temp_ff2 ;
63 wire [ 3:0] din_add_b_temp_ff2 ;
64 wire [ 3:0] din_add_c_temp_ff2 ;
65 wire [ 3:0] din_add_d_temp_ff2 ;
66 wire [ 7:0] din_add_a_temp_ff3 ;
67 wire [ 3:0] din_add_b_temp_ff3 ;
68 wire [ 3:0] din_add_c_temp_ff3 ;
69 wire [ 3:0] din_add_d_temp_ff3 ;
70 reg dout_vld_temp ;
71 reg dout_vld_temp_ff0 ;
72 reg dout_vld_temp_ff1 ;
73 reg dout_vld_temp_ff2 ;
74 reg dout_vld_temp_ff3 ;
75 reg dout_vld_temp_ff4 ;
76
77 always @(posedge clk or negedge rst_n)begin
78 if(rst_n==1'b0)begin
79 din_temp <= 20'b0;
80 end
81 else if(din_vld)begin
82 din_temp <= {9'b0,din,3'b0};
83 end
84 end
85
86 always @(posedge clk or negedge rst_n)begin
87 if(rst_n==1'b0)begin
88 dout_vld_temp <= 1'b0;
89 end
90 else if(din_vld)begin
91 dout_vld_temp <= 1'b1;
92 end
93 else begin
94 dout_vld_temp <= 1'b0;
95 end
96 end
97 assign din_a_temp = din_temp[ 7: 0] ;
98 assign din_b_temp = din_temp[11: 8] ;
99 assign din_c_temp = din_temp[15:12] ;
100 assign din_d_temp = din_temp[19:16] ;
101 assign din_add_a_temp = din_a_temp ;
102 assign din_add_b_temp = din_b_temp + ((din_b_temp>=5)?4'd3:4'd0) ;
103 assign din_add_c_temp = din_c_temp + ((din_c_temp>=5)?4'd3:4'd0) ;
104 assign din_add_d_temp = din_d_temp + ((din_d_temp>=5)?4'd3:4'd0) ;
105 assign din_shift_temp = {din_add_d_temp,din_add_c_temp,din_add_b_temp,din_add_a_temp,1'b0} ;
106
107 always @(posedge clk or negedge rst_n)begin
108 if(rst_n==1'b0)begin
109 din_temp_ff0 <= 20'b0;
110 end
111 else begin
112 din_temp_ff0 <= din_shift_temp[19:0];
113
114 end
115 end
116 always @(posedge clk or negedge rst_n)begin
117 if(rst_n==1'b0)begin
118 dout_vld_temp_ff0 <= 1'b0 ;
119 end
120 else begin
121 dout_vld_temp_ff0 <= dout_vld_temp;
122 end
123 end
124 assign din_a_temp_ff0 = din_temp_ff0[ 7: 0] ;
125 assign din_b_temp_ff0 = din_temp_ff0[11: 8] ;
126 assign din_c_temp_ff0 = din_temp_ff0[15:12] ;
127 assign din_d_temp_ff0 = din_temp_ff0[19:16] ;
128 assign din_add_a_temp_ff0 = din_a_temp_ff0 ;
129 assign din_add_b_temp_ff0 = din_b_temp_ff0 + ((din_b_temp_ff0>=5)?4'd3:4'd0) ;
130 assign din_add_c_temp_ff0 = din_c_temp_ff0 + ((din_c_temp_ff0>=5)?4'd3:4'd0) ;
131 assign din_add_d_temp_ff0 = din_d_temp_ff0 + ((din_d_temp_ff0>=5)?4'd3:4'd0) ;
132 assign din_shift_temp_ff0 = {din_add_d_temp_ff0,din_add_c_temp_ff0,din_add_b_temp_ff0,din_add_a_temp_ff0,1'b0};
133
134 always @(posedge clk or negedge rst_n)begin
135 if(rst_n==1'b0)begin
136 din_temp_ff1 <= 20'b0;
137 end
138 else begin
139 din_temp_ff1 <= din_shift_temp_ff0[19:0];
140 end
141 end
142 always @(posedge clk or negedge rst_n)begin
143 if(rst_n==1'b0)begin
144 dout_vld_temp_ff1 <= 1'b0;
145 end
146 else begin
147 dout_vld_temp_ff1 <= dout_vld_temp_ff0;
148 end
149 end
150 assign din_a_temp_ff1 = din_temp_ff1[ 7: 0] ;
151 assign din_b_temp_ff1 = din_temp_ff1[11: 8] ;
152 assign din_c_temp_ff1 = din_temp_ff1[15:12] ;
153 assign din_d_temp_ff1 = din_temp_ff1[19:16] ;
154 assign din_add_a_temp_ff1 = din_a_temp_ff1 ;
155 assign din_add_b_temp_ff1 = din_b_temp_ff1 + ((din_b_temp_ff1>=5)?4'd3:4'd0) ;
156 assign din_add_c_temp_ff1 = din_c_temp_ff1 + ((din_c_temp_ff1>=5)?4'd3:4'd0) ;
157 assign din_add_d_temp_ff1 = din_d_temp_ff1 + ((din_d_temp_ff1>=5)?4'd3:4'd0) ;
158 assign din_shift_temp_ff1 = {din_add_d_temp_ff1,din_add_c_temp_ff1,din_add_b_temp_ff1,din_add_a_temp_ff1,1'b0};
159
160 always @(posedge clk or negedge rst_n)begin
161 if(rst_n==1'b0)begin
162 din_temp_ff2 <= 20'b0;
163 end
164 else begin
165 din_temp_ff2 <= din_shift_temp_ff1[19:0];
166 end
167 end
168
169 always @(posedge clk or negedge rst_n)begin
170 if(rst_n==1'b0)begin
171 dout_vld_temp_ff2 <= 1'b0;
172 end
173 else begin
174 dout_vld_temp_ff2 <= dout_vld_temp_ff1;
175 end
176 end
177 assign din_a_temp_ff2 = din_temp_ff2[ 7: 0] ;
178 assign din_b_temp_ff2 = din_temp_ff2[11: 8] ;
179 assign din_c_temp_ff2 = din_temp_ff2[15:12] ;
180 assign din_d_temp_ff2 = din_temp_ff2[19:16] ;
181 assign din_add_a_temp_ff2 = din_a_temp_ff2 ;
182 assign din_add_b_temp_ff2 = din_b_temp_ff2 + ((din_b_temp_ff2>=5)?4'd3:4'd0) ;
183 assign din_add_c_temp_ff2 = din_c_temp_ff2 + ((din_c_temp_ff2>=5)?4'd3:4'd0) ;
184 assign din_add_d_temp_ff2 = din_d_temp_ff2 + ((din_d_temp_ff2>=5)?4'd3:4'd0) ;
185 assign din_shift_temp_ff2 = {din_add_d_temp_ff2,din_add_c_temp_ff2,din_add_b_temp_ff2,din_add_a_temp_ff2,1'b0};
186
187 always @(posedge clk or negedge rst_n)begin
188 if(rst_n==1'b0)begin
189 din_temp_ff3 <= 20'b0;
190 end
191 else begin
192 din_temp_ff3 <= din_shift_temp_ff2[19:0];
193 end
194 end
195
196 always @(posedge clk or negedge rst_n)begin
197 if(rst_n==1'b0)begin
198 dout_vld_temp_ff3 <= 1'b0;
199 end
200 else begin
201 dout_vld_temp_ff3 <= dout_vld_temp_ff2;
202 end
203 end
204 assign din_a_temp_ff3 = din_temp_ff3[ 7: 0] ;
205 assign din_b_temp_ff3 = din_temp_ff3[11: 8] ;
206 assign din_c_temp_ff3 = din_temp_ff3[15:12] ;
207 assign din_d_temp_ff3 = din_temp_ff3[19:16] ;
208 assign din_add_a_temp_ff3 = din_a_temp_ff3 ;
209 assign din_add_b_temp_ff3 = din_b_temp_ff3 + ((din_b_temp_ff3>=5)?4'd3:4'd0) ;
210 assign din_add_c_temp_ff3 = din_c_temp_ff3 + ((din_c_temp_ff3>=5)?4'd3:4'd0) ;
211 assign din_add_d_temp_ff3 = din_d_temp_ff3 + ((din_d_temp_ff3>=5)?4'd3:4'd0) ;
212 assign din_shift_temp_ff3 = {din_add_d_temp_ff3,din_add_c_temp_ff3,din_add_b_temp_ff3,din_add_a_temp_ff3,1'b0};
213
214 always @(posedge clk or negedge rst_n)begin
215 if(rst_n==1'b0)begin
216 din_temp_ff4 <= 20'b0;
217 end
218 else begin
219 din_temp_ff4 <= din_shift_temp_ff3[19:0];
220 end
221 end
222
223 always @(posedge clk or negedge rst_n)begin
224 if(rst_n==1'b0)begin
225 dout_vld_temp_ff4 <= 1'b0;
226 end
227 else begin
228 dout_vld_temp_ff4 <= dout_vld_temp_ff3;
229 end
230 end
231 assign dout = din_temp_ff4[19:8];
232 assign dout_vld = dout_vld_temp_ff4 ;
233 endmodule
234
235
236
237
数码管显示模块代码
2 rst_n ,
3 clk ,
4 din ,
5 seg_sel ,
6 segment ,
7 bcd_ms ,
8 bcd_s
9 );
10
11 parameter SEG_WID = 8 ;
12 parameter SEG_NUM = 8 ;
13 parameter CNT_WID = 10 ;
14 parameter TIME_20US = 10'd1000 ;
15 //dp,g,f,e,d,c,b,a,
16 parameter NUM_0 = 8'b1100_0000 ;
17 parameter NUM_1 = 8'b1111_1001 ;
18 parameter NUM_2 = 8'b1010_0100 ;
19 parameter NUM_3 = 8'b1011_0000 ;
20 parameter NUM_4 = 8'b1001_1001 ;
21 parameter NUM_5 = 8'b1001_0010 ;
22 parameter NUM_6 = 8'b1000_0010 ;
23 parameter NUM_7 = 8'b1111_1000 ;
24 parameter NUM_8 = 8'b1000_0000 ;
25 parameter NUM_9 = 8'b1001_0000 ;
26 parameter NUM_ERR = 8'b1111_1111 ;
27
28 input [7:0] bcd_ms ;
29 input [7:0] bcd_s ;
30 input clk ;
31 input rst_n ;
32 input [SEG_NUM*4-1:0] din ;
33 output [SEG_WID - 1:0] seg_sel ;
34 output [SEG_WID - 1:0] segment ;
35
36 reg [SEG_WID - 1:0] seg_sel ;
37 reg [SEG_WID - 1:0] segment ;
38
39 reg [CNT_WID - 1:0] cnt_20us ;
40 reg [SEG_NUM - 1:0] sel_cnt ;
41
42 reg [ 4 - 1 : 0] seg_tmp ;
43
44 wire add_cnt_20us ;
45 wire end_cnt_20us ;
46 wire add_sel_cnt ;
47 wire end_sel_cnt ;
48
49 always @(posedge clk or negedge rst_n)begin
50 if(rst_n==1'b0)begin
51 cnt_20us <= 0;
52 end
53 else if(add_cnt_20us)begin
54 if(end_cnt_20us)
55 cnt_20us <= 0;
56 else
57 cnt_20us <= cnt_20us + 1'b1;
58 end
59 end
60 assign add_cnt_20us = 1;
61 assign end_cnt_20us = add_cnt_20us && cnt_20us == TIME_20US-1;
62
63 always @(posedge clk or negedge rst_n)begin
64 if(rst_n==1'b0)begin
65 sel_cnt <= 0;
66 end
67 else if(add_sel_cnt)begin
68 if(end_sel_cnt)
69 sel_cnt <= 0;
70 else
71 sel_cnt <= sel_cnt + 1'b1;
72 end
73 end
74 assign add_sel_cnt = end_cnt_20us;
75 assign end_sel_cnt = add_sel_cnt && sel_cnt == SEG_NUM-1;
76
77 always @(posedge clk or negedge rst_n)begin
78 if(rst_n==1'b0)begin
79 seg_sel <= {SEG_NUM{1'b1}};
80 end
81 else begin
82 seg_sel <= ~(1'b1 << sel_cnt);
83 end
84 end
85
86 always @(*)begin
87 seg_tmp = din[(sel_cnt+1)*4-1 -:4];
88 end
89
90 always@(posedge clk or negedge rst_n)begin
91 if(rst_n==1'b0)begin
92 segment<=NUM_0;
93 end
94 else begin
95 case (seg_tmp)
96 0 : segment <= NUM_0;
97 1 : segment <= NUM_1;
98 2 : segment <= NUM_2;
99 3 : segment <= NUM_3;
100 4 : segment <= NUM_4;
101 5 : segment <= NUM_5;
102 6 : segment <= NUM_6;
103 7 : segment <= NUM_7;
104 8 : segment <= NUM_8;
105 9 : segment <= NUM_9;
106 default : segment <= NUM_ERR;
107 endcase
108 end
109 end
110 endmodule
技术交流QQ群:544453837
了解>>>至简设计法