99在线精品免费视频九九视-99在线精品视频-99在线精品视频免费观里-99在线精品视频在线观看-99在线免费播放



官方論壇
官方淘寶
官方博客
微信公眾號
點擊聯(lián)系吳工 點擊聯(lián)系周老師
您的當(dāng)前位置:主頁-old > 教程中心 > 案例中心 > 至簡設(shè)計案例 >

【案例】電子鬧鐘設(shè)計

發(fā)布時間:2023-04-13   作者:admin 瀏覽量:

案例編號:001600000064

至簡設(shè)計系列_鬧鐘


--作者:小黑同學(xué)

本文為明德?lián)P原創(chuàng)及錄用文章,轉(zhuǎn)載請注明出處!

1.1 總體設(shè)計

1.1.1 概述

數(shù)字時鐘是采用數(shù)字電路技術(shù)實現(xiàn)時、分、秒計時顯示的裝置,可以用數(shù)字同時顯示時,分,秒

的精確時間并實現(xiàn)準(zhǔn)確校時,具備體積小、重量輕、抗干擾能力強(qiáng)、對環(huán)境要求高、高精確性、容易

開發(fā)等特性,在工業(yè)控制系統(tǒng)、智能化儀器表、辦公自動化系統(tǒng)等諸多領(lǐng)域取得了極為廣泛的應(yīng)用,

諸如自動報警、按時自動打鈴、時間程序自動控制、定時廣播、自定啟閉路燈、定時開關(guān)烘箱、通斷

動力設(shè)備、甚至各種定時電器的自動啟用等。與傳統(tǒng)表盤式機(jī)械時鐘相比,數(shù)字時鐘具有更高的準(zhǔn)確

性和直觀性,由于沒有機(jī)械裝置,其使用壽命更長。

1.1.2 設(shè)計目標(biāo)

設(shè)計一款具有鬧鐘功能的數(shù)字時鐘,具體要求如下

1、 用 8 個數(shù)碼管實現(xiàn),四個一組,每組有分鐘和秒。左邊一組是時間顯示,右邊一組用來

做鬧鐘時間。

2、 當(dāng)左邊時間等于右邊時,蜂鳴器響 5 秒。

3、 鬧鐘時間和顯示時間均可通過 3 個按鍵設(shè)置。設(shè)置方法:按下按鍵 1,時鐘暫停,跳到

設(shè)置時間狀態(tài),再按下按鍵 1,回到正常狀態(tài)。通過按鍵 2,選擇要設(shè)置的位置,初始

設(shè)置秒個位,按一下,設(shè)置秒十位,再按下,設(shè)置分個位,以此類推,循環(huán)設(shè)置。通過

按鍵 3,設(shè)置數(shù)值,按一下數(shù)值加 1,如果溢出則重新變?yōu)?0。

1.1.3 系統(tǒng)結(jié)構(gòu)框圖

系統(tǒng)結(jié)構(gòu)框圖如下所示:

結(jié)構(gòu)圖共分兩個,如果使用的開發(fā)板上是矩陣鍵盤的時候,對應(yīng)的結(jié)構(gòu)圖是圖一。如果使用的開

發(fā)板上是普通按鍵的時候,對應(yīng)的結(jié)構(gòu)圖是圖二。


圖一


圖二


1.1.4 模塊功能

? 按鍵檢測模塊實現(xiàn)功能

1、將外來異步信號打兩拍處理,將異步信號同步化。

2、實現(xiàn) 20ms 按鍵消抖功能,并輸出有效按鍵信號。


? 矩陣鍵盤模塊實現(xiàn)功能

1、將外來異步信號打兩拍處理,將異步信號同步化。

2、實現(xiàn) 20ms 按鍵消抖功能。

3、實現(xiàn)矩陣鍵盤的按鍵檢測功能,并輸出有效按鍵信號。

? 時間產(chǎn)生模塊實現(xiàn)功能

1、 產(chǎn)生顯示時間數(shù)據(jù)。

2、 產(chǎn)生鬧鐘時間數(shù)據(jù),

3、根據(jù)接收到的不同的按鍵信號,產(chǎn)生暫停、開啟、設(shè)置時間的功能。

? 數(shù)碼管顯示模塊實現(xiàn)功能

1、 對接收到的時間數(shù)據(jù)進(jìn)行譯碼。

? 蜂鳴器模塊實現(xiàn)功能

1、 將接受到的顯示時間數(shù)據(jù)與鬧鐘時間數(shù)據(jù)進(jìn)行比較,控制蜂鳴器的開啟。

1.1.5 頂層信號



1.1.6 參考代碼

下面是使用普通按鍵的頂層代碼:





1.	module  alarm_clock(  
2.	    clk       ,  
3.	    rst_n     ,  
4.	    key       ,  
5.	    segment   ,  
6.	    seg_sel   ,  
7.	    beep  
8.	);  
9.	input                   clk             ;  
10.	input                   rst_n           ;  
11.	input   [2:0 ]          key             ;  
12.	output  [7:0 ]          segment         ;  
13.	output  [7:0 ]          seg_sel         ;  
14.	output                  beep            ;  
15.	  
16.	wire    [7:0 ]          segment         ;  
17.	wire    [7:0 ]          seg_sel         ;  
18.	wire                    beep            ;  
19.	wire    [3:0 ]          xs_sec_low      ;  
20.	wire    [3:0 ]          xs_sec_high     ;  
21.	wire    [3:0 ]          xs_min_low      ;  
22.	wire    [3:0 ]          xs_min_high     ;  
23.	wire    [3:0 ]          sec_low         ;  
24.	wire    [3:0 ]          sec_high        ;  
25.	wire    [3:0 ]          min_low         ;  
26.	wire    [3:0 ]          min_high        ;  
27.	wire    [25:0]          counter         ;  
28.	wire    [3:0 ]          key_vld         ;  
29.	wire                    flag_set        ;  
30.	  
31.	key_module u0(  
32.	             .clk         (clk         ),  
33.	             .rst_n       (rst_n       ),  
34.	             .key_in      (key         ),  
35.	             .key_vld     (key_vld     )  
36.	             );  
37.	time_data u1(  
38.	             .clk         (clk         ),   
39.	             .rst_n       (rst_n       ),   
40.	             .key_vld     (key_vld     ),   
41.	             .flag_set    (flag_set    ),   
42.	             .counter     (counter     ),  
43.	             .sec_low     (sec_low     ),  
44.	             .sec_high    (sec_high    ),  
45.	             .min_low     (min_low     ),  
46.	             .min_high    (min_high    ),  
47.	             .xs_sec_low  (xs_sec_low  ),   
48.	             .xs_sec_high (xs_sec_high ),   
49.	             .xs_min_low  (xs_min_low  ),   
50.	             .xs_min_high (xs_min_high )   
51.	             );  
52.	beep u2(  
53.	             .clk         (clk         ),   
54.	             .rst_n       (rst_n       ),   
55.	             .flag_set    (flag_set    ),   
56.	             .counter     (counter     ),   
57.	             .beep        (beep        ),  
58.	             .sec_low     (sec_low     ),  
59.	             .sec_high    (sec_high    ),  
60.	             .min_low     (min_low     ),  
61.	             .min_high    (min_high    ),  
62.	             .xs_sec_low  (xs_sec_low  ),  
63.	             .xs_sec_high (xs_sec_high ),  
64.	             .xs_min_low  (xs_min_low  ),  
65.	             .xs_min_high (xs_min_high )   
66.	             );  
67.	seg_disp u3(   
68.	             .clk         (clk         ),   
69.	             .rst_n       (rst_n       ),   
70.	             .segment_data({xs_min_high,xs_min_low,xs_sec_high,xs_sec_low,min_high,min_low,sec_high,sec_low}),   
71.	             .segment     (segment     ),   
72.	             .seg_sel     (seg_sel     )    
73.	);  
74.	  
75.	  
76.	endmodule  


下面是使用矩陣鍵盤的頂層代碼:






1.	module  alarm_clock_jvzhen(  
2.	    clk       ,  
3.	    rst_n     ,  
4.	    key_col   ,  
5.	    key_row   ,  
6.	    segment   ,  
7.	    seg_sel   ,  
8.	    beep  
9.	);  
10.	input                   clk             ;  
11.	input                   rst_n           ;  
12.	input   [3:0 ]          key_col         ;  
13.	output  [3:0 ]          key_row         ;  
14.	output  [7:0 ]          segment         ;  
15.	output  [7:0 ]          seg_sel         ;  
16.	output                  beep            ;  
17.	  
18.	wire    [7:0 ]          segment         ;  
19.	wire    [7:0 ]          seg_sel         ;  
20.	wire                    beep            ;  
21.	wire    [3:0 ]          xs_sec_low      ;  
22.	wire    [3:0 ]          xs_sec_high     ;  
23.	wire    [3:0 ]          xs_min_low      ;  
24.	wire    [3:0 ]          xs_min_high     ;  
25.	wire    [3:0 ]          sec_low         ;  
26.	wire    [3:0 ]          sec_high        ;  
27.	wire    [3:0 ]          min_low         ;  
28.	wire    [3:0 ]          min_high        ;  
29.	wire    [25:0]          counter         ;  
30.	wire    [3:0 ]          key_vld         ;  
31.	wire                    flag_set        ;  
32.	wire    [15:0]          key_out         ;  
33.	  
34.	key_scan  u0(  
35.	             .clk         (clk         ),  
36.	             .rst_n       (rst_n       ),  
37.	             .key_col     (key_col     ),  
38.	             .key_row     (key_row     ),  
39.	             .key_en      (key_vld     )  
40.	             );  
41.	time_data u1(  
42.	             .clk         (clk         ),   
43.	             .rst_n       (rst_n       ),   
44.	             .key_vld     (key_vld     ),   
45.	             .flag_set    (flag_set    ),   
46.	             .counter     (counter     ),  
47.	             .sec_low     (sec_low     ),  
48.	             .sec_high    (sec_high    ),  
49.	             .min_low     (min_low     ),  
50.	             .min_high    (min_high    ),  
51.	             .xs_sec_low  (xs_sec_low  ),   
52.	             .xs_sec_high (xs_sec_high ),   
53.	             .xs_min_low  (xs_min_low  ),   
54.	             .xs_min_high (xs_min_high )   
55.	             );  
56.	beep u2(  
57.	             .clk         (clk         ),   
58.	             .rst_n       (rst_n       ),   
59.	             .flag_set    (flag_set    ),   
60.	             .counter     (counter     ),   
61.	             .beep        (beep        ),  
62.	             .sec_low     (sec_low     ),  
63.	             .sec_high    (sec_high    ),  
64.	             .min_low     (min_low     ),  
65.	             .min_high    (min_high    ),  
66.	             .xs_sec_low  (xs_sec_low  ),  
67.	             .xs_sec_high (xs_sec_high ),  
68.	             .xs_min_low  (xs_min_low  ),  
69.	             .xs_min_high (xs_min_high )   
70.	             );  
71.	seg_disp u3(   
72.	             .clk         (clk         ),   
73.	             .rst_n       (rst_n       ),   
74.	             .segment_data({xs_min_high,xs_min_low,xs_sec_high,xs_sec_low,min_high,min_low,sec_high,sec_low}),   
75.	             .segment     (segment     ),   
76.	             .seg_sel     (seg_sel     )    
77.	);  
78.	  
79.	  
80.	endmodule  


1.2 按鍵檢測模塊設(shè)計

1.2.1 接口信號



1.2.2 設(shè)計思路

在前面的案例中已經(jīng)有按鍵檢測的介紹,所以這里不在過多介紹,詳細(xì)介紹請看下方鏈接:

【每周 FPGA 案例】至簡設(shè)計系列_按鍵控制數(shù)字時鐘

1.2.3 參考代碼

使用明德?lián)P的計數(shù)器模板,可以很快速很熟練地寫出按鍵消抖模塊。





1.	module  alarm_clock_jvzhen(  
2.	    clk       ,  
3.	    rst_n     ,  
4.	    key_col   ,  
5.	    key_row   ,  
6.	    segment   ,  
7.	    seg_sel   ,  
8.	    beep  
9.	);  
10.	input                   clk             ;  
11.	input                   rst_n           ;  
12.	input   [3:0 ]          key_col         ;  
13.	output  [3:0 ]          key_row         ;  
14.	output  [7:0 ]          segment         ;  
15.	output  [7:0 ]          seg_sel         ;  
16.	output                  beep            ;  
17.	  
18.	wire    [7:0 ]          segment         ;  
19.	wire    [7:0 ]          seg_sel         ;  
20.	wire                    beep            ;  
21.	wire    [3:0 ]          xs_sec_low      ;  
22.	wire    [3:0 ]          xs_sec_high     ;  
23.	wire    [3:0 ]          xs_min_low      ;  
24.	wire    [3:0 ]          xs_min_high     ;  
25.	wire    [3:0 ]          sec_low         ;  
26.	wire    [3:0 ]          sec_high        ;  
27.	wire    [3:0 ]          min_low         ;  
28.	wire    [3:0 ]          min_high        ;  
29.	wire    [25:0]          counter         ;  
30.	wire    [3:0 ]          key_vld         ;  
31.	wire                    flag_set        ;  
32.	wire    [15:0]          key_out         ;  
33.	  
34.	key_scan  u0(  
35.	             .clk         (clk         ),  
36.	             .rst_n       (rst_n       ),  
37.	             .key_col     (key_col     ),  
38.	             .key_row     (key_row     ),  
39.	             .key_en      (key_vld     )  
40.	             );  
41.	time_data u1(  
42.	             .clk         (clk         ),   
43.	             .rst_n       (rst_n       ),   
44.	             .key_vld     (key_vld     ),   
45.	             .flag_set    (flag_set    ),   
46.	             .counter     (counter     ),  
47.	             .sec_low     (sec_low     ),  
48.	             .sec_high    (sec_high    ),  
49.	             .min_low     (min_low     ),  
50.	             .min_high    (min_high    ),  
51.	             .xs_sec_low  (xs_sec_low  ),   
52.	             .xs_sec_high (xs_sec_high ),   
53.	             .xs_min_low  (xs_min_low  ),   
54.	             .xs_min_high (xs_min_high )   
55.	             );  
56.	beep u2(  
57.	             .clk         (clk         ),   
58.	             .rst_n       (rst_n       ),   
59.	             .flag_set    (flag_set    ),   
60.	             .counter     (counter     ),   
61.	             .beep        (beep        ),  
62.	             .sec_low     (sec_low     ),  
63.	             .sec_high    (sec_high    ),  
64.	             .min_low     (min_low     ),  
65.	             .min_high    (min_high    ),  
66.	             .xs_sec_low  (xs_sec_low  ),  
67.	             .xs_sec_high (xs_sec_high ),  
68.	             .xs_min_low  (xs_min_low  ),  
69.	             .xs_min_high (xs_min_high )   
70.	             );  
71.	seg_disp u3(   
72.	             .clk         (clk         ),   
73.	             .rst_n       (rst_n       ),   
74.	             .segment_data({xs_min_high,xs_min_low,xs_sec_high,xs_sec_low,min_high,min_low,sec_high,sec_low}),   
75.	             .segment     (segment     ),   
76.	             .seg_sel     (seg_sel     )    
77.	);  
78.	  
79.	  
80.	endmodule  

1.3 矩陣鍵盤模塊設(shè)計

1.3.1 接口信號



1.3.2 設(shè)計思路

在前面的案例中已經(jīng)有矩陣鍵盤的介紹,所以這里不在過多介紹,詳細(xì)介紹請看下方鏈接:

http://fpgabbs.com/forum.php?mod=viewthread&tid=310

1.3.3 參考代碼





1.	always  @(posedge clk or negedge rst_n)begin  
2.	    if(rst_n==1'b0)begin  
3.	        key_col_ff0 <= 4'b1111;  
4.	        key_col_ff1 <= 4'b1111;  
5.	    end  
6.	    else begin  
7.	        key_col_ff0 <= key_col    ;  
8.	        key_col_ff1 <= key_col_ff0;  
9.	    end  
10.	end  
11.	  
12.	  
13.	always @(posedge clk or negedge rst_n) begin   
14.	    if (rst_n==0) begin  
15.	        shake_cnt <= 0;   
16.	    end  
17.	    else if(add_shake_cnt) begin  
18.	        if(end_shake_cnt)  
19.	            shake_cnt <= 0;   
20.	        else  
21.	            shake_cnt <= shake_cnt+1 ;  
22.	   end  
23.	end  
24.	assign add_shake_cnt = key_col_ff1!=4'hf;  
25.	assign end_shake_cnt = add_shake_cnt  && shake_cnt == TIME_20MS-1 ;  
26.	  
27.	  
28.	always  @(posedge clk or negedge rst_n)begin  
29.	    if(rst_n==1'b0)begin  
30.	        state_c <= CHK_COL;  
31.	    end  
32.	    else begin  
33.	        state_c <= state_n;  
34.	    end  
35.	end  
36.	  
37.	always  @(*)begin  
38.	    case(state_c)  
39.	        CHK_COL: begin  
40.	                     if(col2row_start )begin  
41.	                         state_n = CHK_ROW;  
42.	                     end  
43.	                     else begin  
44.	                         state_n = CHK_COL;  
45.	                     end  
46.	                 end  
47.	        CHK_ROW: begin  
48.	                     if(row2del_start)begin  
49.	                         state_n = DELAY;  
50.	                     end  
51.	                     else begin  
52.	                         state_n = CHK_ROW;  
53.	                     end  
54.	                 end  
55.	        DELAY :  begin  
56.	                     if(del2wait_start)begin  
57.	                         state_n = WAIT_END;  
58.	                     end  
59.	                     else begin  
60.	                         state_n = DELAY;  
61.	                     end  
62.	                 end  
63.	        WAIT_END: begin  
64.	                     if(wait2col_start)begin  
65.	                         state_n = CHK_COL;  
66.	                     end  
67.	                     else begin  
68.	                         state_n = WAIT_END;  
69.	                     end  
70.	                  end  
71.	       default: state_n = CHK_COL;  
72.	    endcase  
73.	end  
74.	assign col2row_start = state_c==CHK_COL  && end_shake_cnt;  
75.	assign row2del_start = state_c==CHK_ROW  && row_index==3 && end_row_cnt;  
76.	assign del2wait_start= state_c==DELAY    && end_row_cnt;  
77.	assign wait2col_start= state_c==WAIT_END && key_col_ff1==4'hf;  
78.	  
79.	always  @(posedge clk or negedge rst_n)begin  
80.	    if(rst_n==1'b0)begin  
81.	        key_row <= 4'b0;  
82.	    end  
83.	    else if(state_c==CHK_ROW)begin  
84.	        key_row <= ~(1'b1 << row_index);  
85.	    end  
86.	    else begin  
87.	        key_row <= 4'b0;  
88.	    end  
89.	end  
90.	  
91.	  
92.	always @(posedge clk or negedge rst_n) begin   
93.	    if (rst_n==0) begin  
94.	        row_index <= 0;   
95.	    end  
96.	    else if(add_row_index) begin  
97.	        if(end_row_index)  
98.	            row_index <= 0;   
99.	        else  
100.	            row_index <= row_index+1 ;  
101.	   end  
102.	   else if(state_c!=CHK_ROW)begin  
103.	       row_index <= 0;  
104.	   end  
105.	end  
106.	assign add_row_index = state_c==CHK_ROW && end_row_cnt;  
107.	assign end_row_index = add_row_index  && row_index == 4-1 ;  
108.	  
109.	  
110.	always @(posedge clk or negedge rst_n) begin   
111.	    if (rst_n==0) begin  
112.	        row_cnt <= 0;   
113.	    end  
114.	    else if(add_row_cnt) begin  
115.	        if(end_row_cnt)  
116.	            row_cnt <= 0;   
117.	        else  
118.	            row_cnt <= row_cnt+1 ;  
119.	   end  
120.	end  
121.	assign add_row_cnt = state_c==CHK_ROW || state_c==DELAY;  
122.	assign end_row_cnt = add_row_cnt  && row_cnt == 16-1 ;  
123.	  
124.	  
125.	always  @(posedge clk or negedge rst_n)begin  
126.	    if(rst_n==1'b0)begin  
127.	        key_col_get <= 0;  
128.	    end  
129.	    else if(state_c==CHK_COL && end_shake_cnt ) begin  
130.	        if(key_col_ff1==4'b1110)  
131.	            key_col_get <= 0;  
132.	        else if(key_col_ff1==4'b1101)  
133.	            key_col_get <= 1;  
134.	        else if(key_col_ff1==4'b1011)  
135.	            key_col_get <= 2;  
136.	        else   
137.	            key_col_get <= 3;  
138.	    end  
139.	end  
140.	  
141.	  
142.	always  @(posedge clk or negedge rst_n)begin  
143.	    if(rst_n==1'b0)begin  
144.	        key_out <= 0;  
145.	    end  
146.	    else if(state_c==CHK_ROW && end_row_cnt)begin  
147.	        key_out <= {row_index,key_col_get};  
148.	    end  
149.	    else begin  
150.	        key_out <= 0;  
151.	    end  
152.	end  
153.	  
154.	always  @(posedge clk or negedge rst_n)begin  
155.	    if(rst_n==1'b0)begin  
156.	        key_vld <= 1'b0;  
157.	    end  
158.	    else if(state_c==CHK_ROW && end_row_cnt && key_col_ff1[key_col_get]==1'b0)begin  
159.	        key_vld <= 1'b1;  
160.	    end  
161.	    else begin  
162.	        key_vld <= 1'b0;  
163.	    end  
164.	end  
165.	  
166.	  
167.	always  @(*)begin  
168.	    if(rst_n==1'b0)begin  
169.	        key_en = 0;  
170.	    end  
171.	    else if(key_vld && key_out==0)begin  
172.	        key_en = 4'b0001;  
173.	    end  
174.	    else if(key_vld && key_out==1)begin  
175.	        key_en = 4'b0010;  
176.	    end  
177.	    else if(key_vld && key_out==2)begin  
178.	        key_en = 4'b0100;  
179.	    end  
180.	    else begin  
181.	        key_en = 0;  
182.	    end  
183.	end  

1.4 時間產(chǎn)生模塊設(shè)計

1.4.1 接口信號



1.4.2 設(shè)計思路

根據(jù)題目功能要求可知,要顯示的時間就是在完整的數(shù)字時鐘的基礎(chǔ)上,減少了時的高位和低位

的顯示,再介紹架構(gòu)之前,先了解一下本模塊其他幾個信號的作用。

設(shè)置狀態(tài)指示信號 flag_set:該信號初始狀態(tài)為低電平,表示模塊處于正常工作狀態(tài),當(dāng)按下按

鍵 key1 時,設(shè)置狀態(tài)指示信號進(jìn)行翻轉(zhuǎn),變?yōu)楦唠娖剑硎具M(jìn)入到設(shè)置狀態(tài)。

設(shè)置位計數(shù)器 sel_cnt:該計數(shù)器表示要設(shè)置的位,初始狀態(tài)為 0,表示可以設(shè)置鬧鐘的秒低位,

當(dāng)其為 1 時表示可以設(shè)置鬧鐘的秒的高位,按照這樣的順序依次類推,當(dāng)其為 7 的時候,表示可以設(shè)

置顯示時間的分高位。加一條件為 key_vld[1]==1'b1,表示按下按鍵 key2 的時候加一;結(jié)束條件為 8,

顯示時間的四個數(shù)碼管加上鬧鐘的四個數(shù)碼管共 8 個,所以數(shù) 8 個就清零。

由此可提出 5 個計數(shù)器的架構(gòu),如下圖所示:



該架構(gòu)由 5 個計數(shù)器組成:時鐘計數(shù)器 counter、秒低位計數(shù)器 xs_sec_low、秒高位計數(shù)器 xs

_sec_high、分低位計數(shù)器 xs_min_low、分高位計數(shù)器 xs_min_high。

時鐘計數(shù)器 counter:用于計算 1 秒的時鐘個數(shù),加一條件為 flag_set==1'b0,表示剛上電時開

始計數(shù),key1 按下之后,進(jìn)入設(shè)置模式,停止計數(shù),再按下又重新開始計數(shù);結(jié)束條件為 5000000

0,表示數(shù)到 1 秒就清零。

秒低位計數(shù)器 xs_sec_low:用于對 1 秒進(jìn)行計數(shù),加一條件為(sel_cnt==5-1 && set_en) || e

nd_counter,表示在設(shè)置狀態(tài)下可通過按鍵 key3 來控制加一,或者在正常狀態(tài)時數(shù)到 1 秒就加 1;

結(jié)束條件為 10,表示數(shù)到 10 秒就清零。

秒高位計數(shù)器 xs_sec_high:用于對 10 秒進(jìn)行計數(shù),加一條件為(sel_cnt==6-1 && set_en) ||

end_xs_sec_low,表示在設(shè)置狀態(tài)下可通過按鍵 key3 來控制加一,或者在正常狀態(tài)時數(shù)到 10 秒就

加 1;結(jié)束條件為 6,表示數(shù)到 60 秒就清零。

分低位計數(shù)器 xs_min_low:用于對 1 分進(jìn)行計數(shù),加一條件為(sel_cnt==7-1 && set_en) || e

nd_xs_sec_high,表示在設(shè)置狀態(tài)下可通過按鍵 key3 來控制加一,或者在正常狀態(tài)時數(shù)到 1 分就加

1;結(jié)束條件為 10,表示數(shù)到 10 分就清零。

分高位計數(shù)器 xs_min_high:用于對 10 分進(jìn)行計數(shù),加一條件為(sel_cnt==8-1 && set_en) ||

end_xs_min_low,表示在設(shè)置狀態(tài)下可通過按鍵 key3 來控制加一,或者在正常狀態(tài)時數(shù)到 10 分就

加 1;結(jié)束條件為 6,表示數(shù)到 60 分就清零。

上面介紹了顯示時間的計數(shù)器架構(gòu),下面我們來思考一下鬧鐘部分的架構(gòu)。

我們都知道鬧鐘的工作原理,它本身不會自動計數(shù),需要我們手動設(shè)置。根據(jù)本設(shè)計的功能要求,

有四個數(shù)碼管來顯示設(shè)置的鬧鐘秒的高低位和分的高低位,因此我們提出四個計數(shù)器組成的架構(gòu),這


四個計數(shù)器相互獨(dú)立,互不干涉,結(jié)構(gòu)圖如下:

該架構(gòu)由 4 個計數(shù)器組成:秒低位計數(shù)器 sec_low、秒高位計數(shù)器 sec_high、分低位計數(shù)器 mi

n_low、分高位計數(shù)器 min_high。

秒低位計數(shù)器 sec_low:用于對鬧鐘秒的低位進(jìn)行計數(shù),加一條件為 sel_cnt==1-1 && set_en,

表示在設(shè)置狀態(tài)下通過按鍵 key3 來控制加一 ;結(jié)束條件為 10,表示最大能設(shè)置為 9,超過之后便

清零。

秒高位計數(shù)器 sec_high:用于對鬧鐘秒的高位進(jìn)行計數(shù),加一條件為 sel_cnt==2-1 && set_en,

表示在設(shè)置狀態(tài)下可通過按鍵 key3 來控制加一;結(jié)束條件為 6,表示最大能設(shè)置為 5,超過之后便

清零。

分低位計數(shù)器 min_low:用于對鬧鐘分的低位進(jìn)行計數(shù),加一條件為 sel_cnt==3-1 && set_en,

表示在設(shè)置狀態(tài)下可通過按鍵 key3 來控制加一;結(jié)束條件為 10,表示最大能設(shè)置為 9,超過之后便

清零。

分高位計數(shù)器 min_high:用于對鬧鐘分高位進(jìn)行計數(shù),加一條件為 sel_cnt==4-1 && set_en,

表示在設(shè)置狀態(tài)下可通過按鍵 key3 來控制加一;結(jié)束條件為 6,表示最大能設(shè)置為 5,超過之后便

清零。


1.4.3 參考代碼

使用明德?lián)P的計數(shù)器模板,可以很快速很熟練地寫出時間產(chǎn)生模塊。





always  @(posedge clk or negedge rst_n)begin
2.	    if(rst_n==1'b0)begin
3.	        flag_set<=1'b0;
4.	    end
5.	    else if(key_vld[0]==1'b1)begin
6.	        flag_set<=~flag_set;
7.	    end
8.	    else begin
9.	        flag_set<=flag_set;
10.	    end
11.	end
12.	
13.	
14.	always @(posedge clk or negedge rst_n) begin 
15.	    if (rst_n==0) begin
16.	        sel_cnt <= 0; 
17.	    end
18.	    else if(add_sel_cnt) begin
19.	        if(end_sel_cnt)
20.	            sel_cnt <= 0; 
21.	        else
22.	            sel_cnt <= sel_cnt+1 ;
23.	   end
24.	end
25.	assign add_sel_cnt = key_vld[1]==1'b1;
26.	assign end_sel_cnt = add_sel_cnt  && sel_cnt == 8-1 ;
27.	
28.	
29.	always  @(posedge clk or negedge rst_n)begin
30.	    if(rst_n==1'b0)begin
31.	        set_en<=1'b0;
32.	    end
33.	    else if(flag_set==1'b1 && key_vld[2]==1'b1)begin
34.	        set_en<=1'b1;
35.	    end
36.	    else begin
37.	        set_en<=1'b0;
38.	    end
39.	end
40.	
41.	
42.	always @(posedge clk or negedge rst_n) begin 
43.	    if (rst_n==0) begin
44.	        counter <= 0; 
45.	    end
46.	    else if(add_counter) begin
47.	        if(end_counter)
48.	            counter <= 0; 
49.	        else
50.	            counter <= counter+1 ;
51.	   end
52.	end
53.	assign add_counter = flag_set==1'b0;
54.	assign end_counter = add_counter  && counter == 26'd5000_0000-1;
55.	
56.	
57.	always @(posedge clk or negedge rst_n) begin 
58.	    if (rst_n==0) begin
59.	        sec_low <= 0; 
60.	    end
61.	    else if(add_sec_low) begin
62.	        if(end_sec_low)
63.	            sec_low <= 0; 
64.	        else
65.	            sec_low <= sec_low+1 ;
66.	   end
67.	end
68.	assign add_sec_low = sel_cnt==1-1 && set_en;
69.	assign end_sec_low = add_sec_low  && sec_low == 10-1 ;
70.	
71.	
72.	always @(posedge clk or negedge rst_n) begin 
73.	    if (rst_n==0) begin
74.	        sec_high <= 0; 
75.	    end
76.	    else if(add_sec_high) begin
77.	        if(end_sec_high)
78.	            sec_high <= 0; 
79.	        else
80.	            sec_high <= sec_high+1 ;
81.	   end
82.	end
83.	assign add_sec_high = sel_cnt==2-1 && set_en;
84.	assign end_sec_high = add_sec_high  && sec_high == 6-1 ;
85.	
86.	
87.	always @(posedge clk or negedge rst_n) begin 
88.	    if (rst_n==0) begin
89.	        min_low <= 0; 
90.	    end
91.	    else if(add_min_low) begin
92.	        if(end_min_low)
93.	            min_low <= 0; 
94.	        else
95.	            min_low <= min_low+1 ;
96.	   end
97.	end
98.	assign add_min_low = sel_cnt==3-1 && set_en;
99.	assign end_min_low = add_min_low  && min_low == 10-1 ;
100.	
101.	always @(posedge clk or negedge rst_n) begin 
102.	    if (rst_n==0) begin
103.	        min_high <= 0; 
104.	    end
105.	    else if(add_min_high) begin
106.	        if(end_min_high)
107.	            min_high <= 0; 
108.	        else
109.	            min_high <= min_high+1 ;
110.	   end
111.	end
112.	assign add_min_high = sel_cnt==4-1 && set_en;
113.	assign end_min_high = add_min_high  && min_high == 6-1 ;
114.	
115.	
116.	always @(posedge clk or negedge rst_n) begin 
117.	    if (rst_n==0) begin
118.	        xs_sec_low <= 0; 
119.	    end
120.	    else if(add_xs_sec_low) begin
121.	        if(end_xs_sec_low)
122.	            xs_sec_low <= 0; 
123.	        else
124.	            xs_sec_low <= xs_sec_low+1 ;
125.	   end
126.	end
127.	assign add_xs_sec_low = (sel_cnt==5-1 && set_en) || end_counter;
128.	assign end_xs_sec_low = add_xs_sec_low && xs_sec_low == 10-1 ;
129.	
130.	
131.	always @(posedge clk or negedge rst_n) begin 
132.	    if (rst_n==0) begin
133.	        xs_sec_high <= 0; 
134.	    end
135.	    else if(add_xs_sec_high) begin
136.	        if(end_xs_sec_high)
137.	            xs_sec_high <= 0; 
138.	        else
139.	            xs_sec_high <= xs_sec_high+1 ;
140.	   end
141.	end
142.	assign add_xs_sec_high = (sel_cnt==6-1 && set_en) || end_xs_sec_low;
143.	assign end_xs_sec_high = add_xs_sec_high  && xs_sec_high == 6-1 ;
144.	
145.	
146.	always @(posedge clk or negedge rst_n) begin 
147.	    if (rst_n==0) begin
148.	        xs_min_low <= 0; 
149.	    end
150.	    else if(add_xs_min_low) begin
151.	        if(end_xs_min_low)
152.	            xs_min_low <= 0; 
153.	        else
154.	            xs_min_low <= xs_min_low+1 ;
155.	   end
156.	end
157.	assign add_xs_min_low = (sel_cnt==7-1 && set_en) || end_xs_sec_high;
158.	assign end_xs_min_low = add_xs_min_low  && xs_min_low == 10-1 ;
159.	
160.	
161.	always @(posedge clk or negedge rst_n) begin 
162.	    if (rst_n==0) begin
163.	        xs_min_high <= 0; 
164.	    end
165.	    else if(add_xs_min_high) begin
166.	        if(end_xs_min_high)
167.	            xs_min_high <= 0; 
168.	        else
169.	            xs_min_high <= xs_min_high+1 ;
170.	   end
171.	end
172.	assign add_xs_min_high = (sel_cnt==8-1 && set_en) || end_xs_min_low;
173.	assign end_xs_min_high = add_xs_min_high  && xs_min_high == 6-1 ; 

1.5 數(shù)碼管顯示模塊設(shè)計


1.5.1 接口信號



1.5.2 設(shè)計思路

在前面的案例中已經(jīng)有數(shù)碼管顯示的介紹,所以這里不在過多介紹,詳細(xì)介紹請看下方鏈接:

http://fpgabbs.com/forum.php?mod=viewthread&tid=399

1.5.3 參考代碼





174.	always @(posedge clk or negedge rst_n) begin 
175.	    if (rst_n==0) begin
176.	        delay <= 0; 
177.	    end
178.	    else if(add_delay) begin
179.	        if(end_delay)
180.	            delay <= 0; 
181.	        else
182.	            delay <= delay+1 ;
183.	   end
184.	end
185.	assign add_delay = 1;
186.	assign end_delay = add_delay  && delay == 2000-1 ;
187.	
188.	
189.	
190.	
191.	always @(posedge clk or negedge rst_n) begin 
192.	    if (rst_n==0) begin
193.	        delay_time <= 0; 
194.	    end
195.	    else if(add_delay_time) begin
196.	        if(end_delay_time)
197.	            delay_time <= 0; 
198.	        else
199.	            delay_time <= delay_time+1 ;
200.	   end
201.	end
202.	assign add_delay_time = end_delay;
203.	assign end_delay_time = add_delay_time  && delay_time == 8-1 ;
204.	
205.	
206.	assign segment_tmp  = segment_data[(1+delay_time)*4-1 -:4];
207.	always  @(posedge clk or negedge rst_n)begin
208.	    if(rst_n==1'b0)begin
209.	        segment <= ZERO;
210.	    end
211.	    else begin
212.	        case(segment_tmp)
213.	            4'd0:segment <= ZERO;
214.	            4'd1:segment <= ONE  ;
215.	            4'd2:segment <= TWO  ;
216.	            4'd3:segment <= THREE;
217.	            4'd4:segment <= FOUR ;
218.	            4'd5:segment <= FIVE ;
219.	            4'd6:segment <= SIX  ;
220.	            4'd7:segment <= SEVEN;
221.	            4'd8:segment <= EIGHT;
222.	            4'd9:segment <= NINE ;
223.	            default:begin
224.	                segment <= segment;
225.	            end
226.	        endcase
227.	    end
228.	end
229.	
230.	
231.	always  @(posedge clk or negedge rst_n)begin
232.	    if(rst_n==1'b0)begin
233.	        seg_sel <= 8'b1111_1111;
234.	    end
235.	    else begin
236.	        seg_sel <= ~(8'b1<<delay_time);
237.	    end
238.	end

1.6 蜂鳴器模塊設(shè)計

1.6.1 接口信號



1.6.2 設(shè)計思路

本模塊主要通過將顯示時間與設(shè)置的鬧鐘時間進(jìn)行比較,如果相同的話,就控制 beep 拉低,持

續(xù)時間為 5 秒。由此提出一個計數(shù)器的架構(gòu),如下圖所示。



該架構(gòu)由蜂鳴器控制信號 beep、秒計數(shù)器 miao 和鬧鐘觸發(fā)指示信號 flag_add 組成。

秒計數(shù)器秒:用于對 5 秒的時間進(jìn)行計數(shù),加一條件為 flag_add && end_counter,表示當(dāng)鬧

鐘被觸發(fā),并且經(jīng)過 1 秒的時間就加一;結(jié)束條件為 5,表示數(shù)完 5 秒就清零。

鬧鐘觸發(fā)指示信號 flag:當(dāng)其為高電平時表示鬧鐘被觸發(fā),低電平表示沒有被觸發(fā)。初始狀態(tài)為

低電平,從低變高的條件為 sec_low==xs_sec_low&&sec_high==xs_sec_high&&min_low==xs_min

_low&&min_high==xs_min_high&&init&&!key1_func,表示當(dāng)顯示時間的秒高低位、分高低位和鬧鐘

設(shè)置的秒高低位、分高低位相等,同時不處于剛上電的初始狀態(tài)和設(shè)置狀態(tài)時,鬧鐘被觸發(fā);從高變

低的條件為 end_miao,表示當(dāng) 5 秒數(shù)完之后,就拉低。

蜂鳴器控制信號 beep:當(dāng)其為低電平時,控制蜂鳴器響,為高電平時不響。初始狀態(tài)為高電平,

從高變低的條件為 flag_add,表示計數(shù)器開始計數(shù)之后便將其拉低,當(dāng)檢測到 flag_add=0 的時候,

便將其拉高。

1.6.3 參考代碼





239.	always  @(posedge clk or negedge rst_n)begin
240.	    if(rst_n==1'b0)begin
241.	        flag_add <= 0;
242.	    end
243.	    else if(sec_low==xs_sec_low&&sec_high==xs_sec_high&&min_low==xs_min_low&&min_high==xs_min_high&&init&&flag_set==0)begin
244.	        flag_add <= 1;
245.	    end
246.	    else if(end_miao)begin
247.	        flag_add <= 0;
248.	    end
249.	end
250.	
251.	
252.	always@(*)begin
253.	    if(!sec_low&&!sec_high&&!min_low&&!min_high)begin
254.	        init=0;
255.	    end
256.	    else begin
257.	        init=1;
258.	    end
259.	end
260.	
261.	
262.	always @(posedge clk or negedge rst_n) begin 
263.	    if (rst_n==0) begin
264.	        miao <= 0; 
265.	    end
266.	    else if(add_miao) begin
267.	        if(end_miao)
268.	            miao <= 0; 
269.	        else
270.	            miao <= miao+1 ;
271.	   end
272.	end
273.	assign add_miao = flag_add && end_counter;
274.	assign end_miao = add_miao  && miao == 5-1 ;
275.	
276.	
277.	always@(posedge clk or negedge rst_n)begin
278.	     if(rst_n==1'b0)begin
279.	        beep<=1'b1;
280.	    end
281.	    else if(flag_add)begin
282.	        beep<=1'b0;
283.	    end
284.	    else
285.	        beep<=1'b1;
286.	end 


1.7 效果和總結(jié)

? 下圖是該工程在 mp801 開發(fā)板上的現(xiàn)象

其中按鍵 s4 控制數(shù)字時鐘的暫停與開始,按鍵 s3 來選擇需要設(shè)置的位,按鍵 s2 設(shè)置數(shù)值。左

邊四個數(shù)碼管顯示的是時鐘的時間,右邊四個數(shù)碼管顯示的是鬧鐘設(shè)置的時間。



? 下圖是該工程在 db603 開發(fā)板上的現(xiàn)象

其中按鍵 s1 控制數(shù)字時鐘的暫停與開始,按鍵 s2 來選擇需要設(shè)置的位,按鍵 s3 設(shè)置數(shù)值。左

邊四個數(shù)碼管顯示的是時鐘的時間,右邊四個數(shù)碼管顯示的是鬧鐘設(shè)置的時間。



? 下圖是該工程在 ms980 試驗箱上的現(xiàn)象

其中按鍵 s1 控制數(shù)字時鐘的暫停與開始,按鍵 s2 來選擇需要設(shè)置的位,按鍵 s3 設(shè)置數(shù)值。左

邊四個數(shù)碼管顯示的是時鐘的時間,右邊四個數(shù)碼管顯示的是鬧鐘設(shè)置的時間。



由于該項目的上板現(xiàn)象是動態(tài)的,開始、暫停、時間設(shè)置等現(xiàn)象無法通過圖片表現(xiàn)出來,想觀看

完整現(xiàn)象的朋友可以看一下現(xiàn)象演示的視頻。


感興趣的朋友也可以訪問明德?lián)P論壇(http://www.fpgabbs.cn/)進(jìn)行 FPGA 相關(guān)工程設(shè)計學(xué)習(xí),

也可以看一下我們往期的文章:

《基于 FPGA 的密碼鎖設(shè)計》

《波形相位頻率可調(diào) DDS 信號發(fā)生器》

《基于 FPGA 的曼徹斯特編碼解碼設(shè)計》

《基于 FPGA 的出租車計費(fèi)系統(tǒng)》

《數(shù)電基礎(chǔ)與 Verilog 設(shè)計》

《基于 FPGA 的頻率、電壓測量》

《基于 FPGA 的漢明碼編碼解碼設(shè)計》

《關(guān)于鎖存器問題的討論》

《阻塞賦值與非阻塞賦值》

《參數(shù)例化時自動計算位寬的解決辦法》


明德?lián)P是一家專注于 FPGA 領(lǐng)域的專業(yè)性公司,公司主要業(yè)務(wù)包括開發(fā)板、教育培訓(xùn)、項目承

接、人才服務(wù)等多個方向。

點撥開發(fā)板——學(xué)習(xí) FPGA 的入門之選。

MP801 開發(fā)板——千兆網(wǎng)、ADDA、大容量 SDRAM 等,學(xué)習(xí)和項目需求一步到位。

網(wǎng)絡(luò)培訓(xùn)班——不管時間和空間,明德?lián)P隨時在你身邊,助你快速學(xué)習(xí) FPGA。

周末培訓(xùn)班——明天的你會感激現(xiàn)在的努力進(jìn)取,升職加薪明德?lián)P來助你。

就業(yè)培訓(xùn)班——七大企業(yè)級項目實訓(xùn),獲得豐富的項目經(jīng)驗,高薪就業(yè)。

專題課程——高手修煉課:提升設(shè)計能力;實用調(diào)試技巧課:提升定位和解決問題能力;FIFO 架構(gòu)

設(shè)計課:助你快速成為架構(gòu)設(shè)計師;時序約束、數(shù)字信號處理、PCIE、綜合項目實踐課等你來選。

項目承接——承接企業(yè) FPGA 研發(fā)項目。

人才服務(wù)——提供人才推薦、人才代培、人才派遣等服務(wù)。


   拓展閱讀
主站蜘蛛池模板: 日韩欧美三级视频 | 欧美久久xxxxxx影院 | 亚洲你懂得 | 看片在线观看 | 免费一级欧美片在线观免看 | a级情欲视频免费观看 | 91精品综合国产在线观看 | 在线观看人成网站深夜免费 | 亚洲人成网站在线观看青青 | 精品久久看 | 青草青视频在线观看 | 国产久热美女福利视频 | 欧美特黄级乱色毛片 | 97色老99久久九九爱精品 | 欧美在线观看一区二区 | 8x成人在线 | 国产黄色免费在线观看 | 免费大片在线观看 | 91在线视频网址 | 毛片大全在线 | 国产在线一区二区视频 | 91久久精品日日躁夜夜躁欧美 | 亚洲精品高清在线观看 | 国产精品国产三级国产专不∫ | 日韩欧美一区二区三区在线播放 | 最新亚洲国产有精品 | 色天天色综合 | 香蕉视频黄色片 | 免费黄色网址在线观看 | 国产免费高清mv视频在线观看 | 国产 欧美 日韩 在线 | 欧美一区二区三区婷婷月色 | 夜恋全部国产精品视频 | 久久综合中文字幕 | 亚洲中字幕永久在线观看 | 大狠狠大臿蕉香蕉大视频 | 综合亚洲一区二区三区 | 精品特级毛片 | 1级黄色毛片 | 美女黄色免费看 | 国产成人v片视频在线观看 国产成人v视频在线观看 |