【转载】FPGA Verilog HDL 系列实例-------- 电子琴 电子钟
这是我从论坛上转载过来的,觉得写的还不错,暂时先转载过来,等有空的时候再验证下。
转载地址:http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=1269705&bbs_page_no=12&bbs_id=1029
控制说明:
1、电子琴:程序设计采用八个输入端口,分别与实验箱上的按键8~1引脚相连接,采用一个输出端口,与扬声器的引脚连接,时钟频率采用6MHz和4Hz。按键7~1分别用于中音的七个音符的发音(DO,RE,MI,FA,SO,LA,SI),按键8用于控制乐曲的播放。程序的编写采用状态机的编写方法,对按键的状态进行判断,对应相应的音符或乐曲。
2、电子钟:程序的设计模块有:时钟初始化模块、时钟工作模块、时钟设置模块、闹钟设置模块、闰年的月份天数判断模块、数码管显示模块、闹钟铃声模块及其它的设置模块。程序使用8个输入分别与8个按键连接,用按键8对应时钟工作状态(work_state),当work_state为0时,时钟正常工作,当work_state为1时,进入时钟设置状态。按键7对应输入端口display_set控制时钟显示状态(display_state),每按2次(用于产生上升沿触发)则数码管的输出不同。Display_state与work_state相结合使用,以区分设置的参数。按键6~4对应输入个脚in_set,该参数共有三位,用以表示三个状态:state_yorh (设置年或小时)、state_morm(设置月份或分钟)、 state_dors(设置日期或秒钟)。按键3~2对应数值设置端口up各down。Up用于产生上升沿触发,当down为0时,则每一个上升沿产生时,相应的参数加1,当down为1时,则每一个上升沿产生时,相应的参数减1。按键1与输入端口clock_on相连,用于闹钟的开与关,当 clock_on为1时开闹钟,否则关闹钟。扬声器与输出端口speaker相连,用于输出闹钟铃声。
附录:源程序
1 一、 电子琴:
2 module piano(in,clk_6MHz,clk_4Hz,song,speaker);
3 input in,clk_6MHz,clk_4Hz,song;
4 output speaker;
5 reg speaker;
6 reg[7:0] state;
7 reg song_on;
8 wire[6:0] in;
9
10 reg[3:0] high,med,low;
11 reg[13:0] divider,origin;
12 reg[7:0] counter;
13 reg out;
14 wire carry;
15
16 reg[20:0] i;
17 parameter zero=8'b0000_0000,
18 one=8'b0000_0001,
19 two=8'b0000_0010,
20 three=8'b0000_0100,
21 four=8'b0000_1000,
22 five=8'b0001_0000,
23 six=8'b0010_0000,
24 seven=8'b0100_0000;
25 initial
26 begin
27 song_on<=0;
28 end
29
30
31 always @(posedge song)
32 begin
33 song_on<=~song_on;
34 end
35
36 always @(posedge clk_6MHz)
37
38 begin
39 if(song_on)
40 speaker<=out;
41 else
42 begin
43 case(in)
44 zero:begin
45 speaker<=0;
46 i<=0;
47 end
48 one:begin //do
49 if(i>=11451)
50 begin
51 speaker=!speaker;
52 i<=0;
53 end
54 else
55 i<=i+1;
56 end
57 two:begin //re
58 if(i>=10204)
59 begin
60 speaker=!speaker;
61 i<=0;
62 end
63 else
64 i<=i+1;
65 end
66 three:begin //mi
67 if(i>=9091)
68 begin
69 speaker=!speaker;
70 i<=0;
71 end
72 else
73 i<=i+1;
74 end
75 four:begin // fa
76 if(i>=8596)
77 begin
78 speaker=!speaker;
79 i<=0;
80 end
81 else
82 i<=i+1;
83 end
84 five:begin //so
85 if(i>=7653)
86 begin
87 speaker=!speaker;
88 i<=0;
89 end
90 else
91 i<=i+1;
92 end
93 six:begin //lo
94 if(i>=6818)
95 begin
96 speaker=!speaker;
97 i<=0;
98 end
99 else
100 i<=i+1;
101 end
102 seven:begin //si
103 if(i>=6073)
104 begin
105 speaker=!speaker;
106 i<=0;
107 end
108 else
109 i<=i+1;
110 end
111 default:begin
112 speaker<=0;
113 i<=0;
114 end
115 endcase
116 end
117 end
118
119
120 assign carry=(divider==16383);
121 always @(posedge clk_6MHz)
122 begin
123 if(carry)
124 divider<=origin;
125 else
126 divider<=divider+1;
127 end
128 always @(posedge carry)
129 begin
130 out<=~out; //2 分频产生方波信号
131 end
132 always @(posedge clk_4Hz)
133 begin
134 case({high,med,low}) //分频比预置
135 'b000000000011: origin<=7281;
136 'b000000000101: origin<=8730;
137 'b000000000110: origin<=9565;
138 'b000000000111: origin<=10310;
139 'b000000010000: origin<=10647;
140 'b000000100000: origin<=11272;
141 'b000000110000: origin<=11831;
142 'b000001010000: origin<=12556;
143 'b000001100000: origin<=12974;
144 'b000100000000: origin<=13516;
145 'b000000000000: origin<=16383;
146 endcase
147 end
148 always @(posedge clk_4Hz)
149 begin
150 if(counter==63)
151 counter<=0; //计时,以实现循环演奏
152 else
153 counter<=counter+1;
154 case(counter) //记谱
155 0: {high,med,low}<='b000000000011; //低音“3”
156 1: {high,med,low}<='b000000000011; //持续4 个时钟节拍
157 2: {high,med,low}<='b000000000011;
158 3: {high,med,low}<='b000000000011;
159 4: {high,med,low}<='b000000000101; //低音“5”
160 5: {high,med,low}<='b000000000101; //发3 个时钟节拍
161 6: {high,med,low}<='b000000000101;
162 7: {high,med,low}<='b000000000110; //低音“6”
163 8: {high,med,low}<='b000000010000; //中音“1”
164 9: {high,med,low}<='b000000010000; //发3 个时钟节拍
165 10: {high,med,low}<='b000000010000;
166 11: {high,med,low}<='b000000100000; //中音“2”
167 12: {high,med,low}<='b000000000110; //低音“6”
168 13: {high,med,low}<='b000000010000;
169 14: {high,med,low}<='b000000000101;
170 15: {high,med,low}<='b000000000101;
171 16: {high,med,low}<='b000001010000; //中音“5”
172 17: {high,med,low}<='b000001010000; //发3 个时钟节拍
173 18: {high,med,low}<='b000001010000;
174 19: {high,med,low}<='b000100000000; //高音“1”
175 20: {high,med,low}<='b000001100000;
176 21: {high,med,low}<='b000001010000;
177 22: {high,med,low}<='b000000110000;
178 23: {high,med,low}<='b000001010000;
179 24: {high,med,low}<='b000000100000; //中音“2”
180 25: {high,med,low}<='b000000100000; //持续11 个时钟节拍
181 26: {high,med,low}<='b000000100000;
182 27: {high,med,low}<='b000000100000;
183 28: {high,med,low}<='b000000100000;
184 29: {high,med,low}<='b000000100000;
185 30: {high,med,low}<='b000000100000;
186 31: {high,med,low}<='b000000100000;
187 32: {high,med,low}<='b000000100000;
188 33: {high,med,low}<='b000000100000;
189 34: {high,med,low}<='b000000100000;
190 35: {high,med,low}<='b000000110000; //中音“3”
191 36: {high,med,low}<='b000000000111; //低音“7”
192 37: {high,med,low}<='b000000000111;
193 38: {high,med,low}<='b000000000110; //低音“6”
194 39: {high,med,low}<='b000000000110;
195 40: {high,med,low}<='b000000000101; //低音“5”
196 41: {high,med,low}<='b000000000101;
197 42: {high,med,low}<='b000000000101;
198 43: {high,med,low}<='b000000000110; //低音“6”
199 44: {high,med,low}<='b000000010000; //中音“1”
200 45: {high,med,low}<='b000000010000;
201 46: {high,med,low}<='b000000100000; //中音“2”
202 47: {high,med,low}<='b000000100000;
203 48: {high,med,low}<='b000000000011; //低音“3”
204 49: {high,med,low}<='b000000000011;
205 50: {high,med,low}<='b000000010000; //中音“1”
206 51: {high,med,low}<='b000000010000;
207 52: {high,med,low}<='b000000000110;
208 53: {high,med,low}<='b000000000101; //低音“5”
209 54: {high,med,low}<='b000000000110;
210 55: {high,med,low}<='b000000010000; //中音“1”
211 56: {high,med,low}<='b000000000101; //低音“5”
212 57: {high,med,low}<='b000000000101; //持续8 个时钟节拍
213 58: {high,med,low}<='b000000000101;
214 59: {high,med,low}<='b000000000101;
215 60: {high,med,low}<='b000000000101;
216 61: {high,med,low}<='b000000000101;
217 62: {high,med,low}<='b000000000101;
218 63: {high,med,low}<='b000000000101;
219 endcase
220 end
221 endmodule
1 二、电子钟
2 module clock(work_state,clock_on,clk_6MHz,clk_4Hz,in_set,display_set,clk_1024Hz,up,down,out1,out2,out3,out4,out5,out6,out7,out8,speaker);
3
4 input work_state,clk_1024Hz,up,down,display_set,clk_6MHz,in_set,clock_on,clk_4Hz;
5 output out1,out2,out3,out4,out5,out6,out7,out8,speaker;
6 wire[2:0] in_set;
7 reg[3:0] out1,out2,out3,out4,out5,out6,out7,out8;
8 reg[2:0] display_state;
9 reg[7:0] hour,minute,second,year,month,day,day_max;
10 reg[7:0] hour_set,minute_set,second_set,day_set,month_set,year_set,day_set_max;
11 integer century=20;
12 integer i=0;
13 reg speaker;
14
15 reg[7:0] clock_hour,clock_minute,clock_second;
16
17 reg[3:0] high,med,low;
18 reg[13:0] divider,origin;
19 reg[7:0] counter;
20 reg out;
21 wire carry;
22
23 //*****各初始值设置时对应的状态********//
24 parameter state_yorh=3'b100, //设置年或小时对应的按键状态
25 state_morm=3'b010, //设置月或分对应的按键状态
26 state_dors=3'b001; //设置日或秒对应的按键状态
27
28
29 //***初始化时钟:08年08月08日00:00:00*****//
30 initial
31 begin
32 year<=8;
33 year_set<=8;
34 month<=8;
35 month_set<=8;
36 day<=8;
37 day_set<=8;
38 hour<=0;
39 minute<=0;
40 second<=0;
41 clock_hour<=0;
42 clock_minute<=0;
43 clock_second<=0;
44 display_state<=0;
45 end
46
47
48 //******电子钟正常工作状态下/work_state等于0时,时钟处于工作状态*******//
49 always @(posedge clk_1024Hz) //频率选择1024HZ
50 begin
51 if(i>=1023)
52 begin
53 i<=0;
54 if(work_state)
55 begin
56 second<=second_set;
57 minute<=minute_set;
58 hour<=hour_set;
59 day<=day_set;
60 month<=month_set;
61 year<=year_set;
62 end
63 else
64 begin
65 if(second>=59)
66 begin
67 second<=0;
68 if(minute>=59)
69 begin
70 minute<=0;
71 if(hour>=23)
72 begin
73 hour<=0;
74 if(day>=day_max)
75 begin
76 day<=1;
77 if(month>=12)
78 begin
79 month<=1;
80 if(year>=99)
81 year<=0;
82 else
83 year<=year+1;
84 end
85 else
86 month<=month+1;
87 end
88 else
89 day<=day+1;
90 end
91 else
92 hour<=hour+1;
93 end
94 else
95 minute<=minute+1;
96 end
97 else
98 second<=second+1;
99 end
100 end
101 else
102 i<=i+1;
103 end
104
105 //******数码管显示状态设置*******//
106 always @(posedge display_set)
107 begin
108 if(display_state>=2)
109 display_state<=0;
110 else
111 display_state<=display_state+1;
112 end
113
114 //*闹钟模块设置,用clock_on控制闹钟,闹钟铃声播放时间为一分钟,可手动关闭闹钟**//
115 always @(posedge clk_6MHz)
116 begin
117 if(clock_on)
118 begin
119 if(clock_hour==hour&&clock_minute==minute)
120 speaker<=out;
121 else speaker<=0;
122 end
123 else speaker<=0;
124 end
125
126 //*************设置时钟的初值*************************//
127 /*用up来触发,当down=0时,一个上升沿触发来时加1,否则减1.***/
128 always @( posedge up)
129 begin
130 if(!work_state) //时间处于正常工作状态时,使要设置的初始值保持同步
131 begin
132 second_set<=second;
133 minute_set<=minute;
134 hour_set<=hour;
135 day_set<=day;
136 month_set<=month;
137 year_set<=year;
138 end
139 else
140 begin
141 if(display_state==1)//当display_state==1时,则是设置年月日的初始值,否则是设置时间.
142 begin
143 if(down==0)
144 begin
145 case(in_set)
146 state_yorh:begin
147 if(year_set>=99)
148 year_set<=0;
149 else
150 year_set<=year_set+1;
151 end
152 state_morm:begin
153 if(month_set>=12)
154 month_set<=1;
155 else
156 month_set<=month_set+1;
157 end
158 state_dors:begin
159 if(day_set>=day_set_max)
160 day_set<=1;
161 else
162 day_set<=day_set+1;
163 end
164 endcase
165 end
166 else
167 begin
168 case(in_set)
169
170 state_yorh:begin
171 if(year_set<=0)
172 year_set<=99;
173 else
174 year_set<=year_set-1;
175 end
176 state_morm:begin
177 if(month_set<=1)
178 month_set<=12;
179 else
180 month_set<=month_set-1;
181 end
182 state_dors:begin
183 if(day_set<=1)
184 day_set<=day_set_max;
185 else
186 day_set<=day_set-1;
187 end
188
189 endcase
190 end
191 end
192 else if(display_state==0)
193 begin
194 if(down==0)
195 begin
196 case(in_set)
197
198 state_yorh:begin
199 if(hour_set>=23)
200 hour_set<=0;
201 else
202 hour_set<=hour_set+1;
203 end
204 state_morm:begin
205 if(minute_set>=59)
206 minute_set<=0;
207 else
208 minute_set<=minute_set+1;
209 end
210 state_dors:begin
211 if(second_set>=59)
212 second_set<=0;
213 else
214 second_set<=second_set+1;
215 end
216
217 endcase
218 end
219 else
220 begin
221 case(in_set)
222
223 state_yorh:begin
224 if(hour_set<=0)
225 hour_set<=23;
226 else
227 hour_set<=hour_set-1;
228 end
229 state_morm:begin
230 if(minute_set<=0)
231 minute_set<=59;
232 else
233 minute_set<=minute_set-1;
234 end
235 state_dors:begin
236 if(second_set<=0)
237 second_set<=59;
238 else
239 second_set<=second_set-1;
240 end
241
242 endcase
243 end
244 end
245 else if(display_state==2)
246 begin
247 if(down==0)
248 begin
249 case(in_set)
250
251 state_yorh:begin
252 if(clock_hour>=23)
253 clock_hour<=0;
254 else
255 clock_hour<=clock_hour+1;
256 end
257 state_morm:begin
258 if(clock_minute>=59)
259 clock_minute<=0;
260 else
261 clock_minute=clock_minute+1;
262 end
263 state_dors:begin
264 if(clock_second>=59)
265 clock_second<=0;
266 else
267 clock_second<=clock_second+1;
268 end
269
270 endcase
271 end
272 else
273 begin
274 case(in_set)
275
276 state_yorh:begin
277 if(clock_hour<=0)
278 clock_hour<=23;
279 else
280 clock_hour<=clock_hour-1;
281 end
282 state_morm:begin
283 if(clock_minute<=0)
284 clock_minute<=59;
285 else
286 clock_minute<=clock_minute-1;
287 end
288 state_dors:begin
289 if(clock_second<=0)
290 clock_second<=59;
291 else
292 clock_second<=clock_second-1;
293 end
294
295 endcase
296 end
297
298 end
299 end
300 end
301
302
303 //**********本年度当前月的天数的计算**********//
304 always @(day or day_set)//当日期变化时,则其所处月份的天数;
305 begin
306 if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
307 day_max<=31;
308 else if(month==4||month==6||month==9||month==11)
309 day_max<=30;
310 else
311 begin
312 if(({century,year}%400==0)||(({century,year}%4==0)&&({century,year}%10!=0)))
313 day_max<=29;
314 else day_max<=28;
315 end
316
317 if(month_set==1||month_set==3||month_set==5||month_set==7||month_set==8||month_set==10||month_set==12)
318 day_set_max<=31;
319 else if(month_set==4||month_set==6||month_set==9||month_set==11)
320 day_set_max<=30;
321 else
322 begin
323 if(({century,year_set}%400==0)||(({century,year_set}%4==0)&&({century,year_set}%10!=0)))
324 day_set_max<=29;
325 else day_set_max<=28;
326 end
327 end
328
329 //**********数码管显示模块,display_state=1时,显示年月日,否则显示时间////
330
331 always @(posedge clk_6MHz)
332 begin
333 if(!work_state)
334 begin
335 if(display_state==1)
336 begin
337 out8<=year%10;
338 out7<=year/10;
339 out6<=13;
340 out5<=month%10;
341 out4<=month/10;
342 out3<=13;
343 out2<=day%10;
344 out1<=day/10;
345 end
346 else if(display_state==0)
347 begin
348 out8<=hour%10;
349 out7<=hour/10;
350 out6<=15;
351 out5<=minute%10;
352 out4<=minute/10;
353 out3<=15;
354 out2<=second%10;
355 out1<=second/10;
356 end
357 else if(display_state==2)
358 begin
359 out8<=clock_hour%10;
360 out7<=clock_hour/10;
361 out6<=12;
362 out5<=clock_minute%10;
363 out4<=clock_minute/10;
364 out3<=12;
365 out2<=clock_second%10;
366 out1<=clock_second/10;
367 end
368 end
369 else
370 begin
371 if(display_state==1)
372 begin
373 out8<=year_set%10;
374 out7<=year_set/10;
375 out6<=13;
376 out5<=month_set%10;
377 out4<=month_set/10;
378 out3<=13;
379 out2<=day_set%10;
380 out1<=day_set/10;
381 end
382 else if(display_state==0)
383 begin
384 out8<=hour_set%10;
385 out7<=hour_set/10;
386 out6<=15;
387 out5<=minute_set%10;
388 out4<=minute_set/10;
389 out3<=15;
390 out2<=second_set%10;
391 out1<=second_set/10;
392 end
393 else if(display_state==2)
394 begin
395 out8<=clock_hour%10;
396 out7<=clock_hour/10;
397 out6<=12;
398 out5<=clock_minute%10;
399 out4<=clock_minute/10;
400 out3<=12;
401 out2<=clock_second%10;
402 out1<=clock_second/10;
403 end
404 end
405 end
406
407 //*******用乐曲《梁祝》作为闹钟铃声*************//
408
409 assign carry=(divider==16383);
410 always @(posedge clk_6MHz)
411 begin
412 if(carry)
413 divider<=origin;
414 else
415 divider<=divider+1;
416 end
417 always @(posedge carry)
418 begin
419 out<=~out; //2 分频产生方波信号
420 end
421 always @(posedge clk_4Hz)
422 begin
423 case({high,med,low}) //分频比预置
424 'b000000000011: origin<=7281;
425 'b000000000101: origin<=8730;
426 'b000000000110: origin<=9565;
427 'b000000000111: origin<=10310;
428 'b000000010000: origin<=10647;
429 'b000000100000: origin<=11272;
430 'b000000110000: origin<=11831;
431 'b000001010000: origin<=12556;
432 'b000001100000: origin<=12974;
433 'b000100000000: origin<=13516;
434 'b000000000000: origin<=16383;
435 endcase
436 end
437 always @(posedge clk_4Hz)
438 begin
439 if(counter==63)
440 counter<=0; //计时,以实现循环演奏
441 else
442 counter<=counter+1;
443 case(counter) //记谱
444 0: {high,med,low}<='b000000000011; //低音“3”
445 1: {high,med,low}<='b000000000011; //持续4 个时钟节拍
446 2: {high,med,low}<='b000000000011;
447 3: {high,med,low}<='b000000000011;
448 4: {high,med,low}<='b000000000101; //低音“5”
449 5: {high,med,low}<='b000000000101; //发3 个时钟节拍
450 6: {high,med,low}<='b000000000101;
451 7: {high,med,low}<='b000000000110; //低音“6”
452 8: {high,med,low}<='b000000010000; //中音“1”
453 9: {high,med,low}<='b000000010000; //发3 个时钟节拍
454 10: {high,med,low}<='b000000010000;
455 11: {high,med,low}<='b000000100000; //中音“2”
456 12: {high,med,low}<='b000000000110; //低音“6”
457 13: {high,med,low}<='b000000010000;
458 14: {high,med,low}<='b000000000101;
459 15: {high,med,low}<='b000000000101;
460 16: {high,med,low}<='b000001010000; //中音“5”
461 17: {high,med,low}<='b000001010000; //发3 个时钟节拍
462 18: {high,med,low}<='b000001010000;
463 19: {high,med,low}<='b000100000000; //高音“1”
464 20: {high,med,low}<='b000001100000;
465 21: {high,med,low}<='b000001010000;
466 22: {high,med,low}<='b000000110000;
467 23: {high,med,low}<='b000001010000;
468 24: {high,med,low}<='b000000100000; //中音“2”
469 25: {high,med,low}<='b000000100000; //持续11 个时钟节拍
470 26: {high,med,low}<='b000000100000;
471 27: {high,med,low}<='b000000100000;
472 28: {high,med,low}<='b000000100000;
473 29: {high,med,low}<='b000000100000;
474 30: {high,med,low}<='b000000100000;
475 31: {high,med,low}<='b000000100000;
476 32: {high,med,low}<='b000000100000;
477 33: {high,med,low}<='b000000100000;
478 34: {high,med,low}<='b000000100000;
479 35: {high,med,low}<='b000000110000; //中音“3”
480 36: {high,med,low}<='b000000000111; //低音“7”
481 37: {high,med,low}<='b000000000111;
482 38: {high,med,low}<='b000000000110; //低音“6”
483 39: {high,med,low}<='b000000000110;
484 40: {high,med,low}<='b000000000101; //低音“5”
485 41: {high,med,low}<='b000000000101;
486 42: {high,med,low}<='b000000000101;
487 43: {high,med,low}<='b000000000110; //低音“6”
488 44: {high,med,low}<='b000000010000; //中音“1”
489 45: {high,med,low}<='b000000010000;
490 46: {high,med,low}<='b000000100000; //中音“2”
491 47: {high,med,low}<='b000000100000;
492 48: {high,med,low}<='b000000000011; //低音“3”
493 49: {high,med,low}<='b000000000011;
494 50: {high,med,low}<='b000000010000; //中音“1”
495 51: {high,med,low}<='b000000010000;
496 52: {high,med,low}<='b000000000110;
497 53: {high,med,low}<='b000000000101; //低音“5”
498 54: {high,med,low}<='b000000000110;
499 55: {high,med,low}<='b000000010000; //中音“1”
500 56: {high,med,low}<='b000000000101; //低音“5”
501 57: {high,med,low}<='b000000000101; //持续8 个时钟节拍
502 58: {high,med,low}<='b000000000101;
503 59: {high,med,low}<='b000000000101;
504 60: {high,med,low}<='b000000000101;
505 61: {high,med,low}<='b000000000101;
506 62: {high,med,low}<='b000000000101;
507 63: {high,med,low}<='b000000000101;
508 endcase
509 end
510
511 endmodule