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



官方論壇
官方淘寶
官方博客
微信公眾號
點擊聯系吳工 點擊聯系周老師

【案例】電子鬧鐘設計

發布時間:2023-04-13   作者:admin 瀏覽量:

案例編號:001600000064

至簡設計系列_鬧鐘


--作者:小黑同學

本文為明德揚原創及錄用文章,轉載請注明出處!

1.1 總體設計

1.1.1 概述

數字時鐘是采用數字電路技術實現時、分、秒計時顯示的裝置,可以用數字同時顯示時,分,秒

的精確時間并實現準確校時,具備體積小、重量輕、抗干擾能力強、對環境要求高、高精確性、容易

開發等特性,在工業控制系統、智能化儀器表、辦公自動化系統等諸多領域取得了極為廣泛的應用,

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

動力設備、甚至各種定時電器的自動啟用等。與傳統表盤式機械時鐘相比,數字時鐘具有更高的準確

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

1.1.2 設計目標

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

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

做鬧鐘時間。

2、 當左邊時間等于右邊時,蜂鳴器響 5 秒。

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

設置時間狀態,再按下按鍵 1,回到正常狀態。通過按鍵 2,選擇要設置的位置,初始

設置秒個位,按一下,設置秒十位,再按下,設置分個位,以此類推,循環設置。通過

按鍵 3,設置數值,按一下數值加 1,如果溢出則重新變為 0。

1.1.3 系統結構框圖

系統結構框圖如下所示:

結構圖共分兩個,如果使用的開發板上是矩陣鍵盤的時候,對應的結構圖是圖一。如果使用的開

發板上是普通按鍵的時候,對應的結構圖是圖二。


圖一


圖二


1.1.4 模塊功能

? 按鍵檢測模塊實現功能

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

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


? 矩陣鍵盤模塊實現功能

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

2、實現 20ms 按鍵消抖功能。

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

? 時間產生模塊實現功能

1、 產生顯示時間數據。

2、 產生鬧鐘時間數據,

3、根據接收到的不同的按鍵信號,產生暫停、開啟、設置時間的功能。

? 數碼管顯示模塊實現功能

1、 對接收到的時間數據進行譯碼。

? 蜂鳴器模塊實現功能

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

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 按鍵檢測模塊設計

1.2.1 接口信號



1.2.2 設計思路

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

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

1.2.3 參考代碼

使用明德揚的計數器模板,可以很快速很熟練地寫出按鍵消抖模塊。





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 矩陣鍵盤模塊設計

1.3.1 接口信號



1.3.2 設計思路

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

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 時間產生模塊設計

1.4.1 接口信號



1.4.2 設計思路

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

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

設置狀態指示信號 flag_set:該信號初始狀態為低電平,表示模塊處于正常工作狀態,當按下按

鍵 key1 時,設置狀態指示信號進行翻轉,變為高電平,表示進入到設置狀態。

設置位計數器 sel_cnt:該計數器表示要設置的位,初始狀態為 0,表示可以設置鬧鐘的秒低位,

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

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

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

由此可提出 5 個計數器的架構,如下圖所示:



該架構由 5 個計數器組成:時鐘計數器 counter、秒低位計數器 xs_sec_low、秒高位計數器 xs

_sec_high、分低位計數器 xs_min_low、分高位計數器 xs_min_high。

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

始計數,key1 按下之后,進入設置模式,停止計數,再按下又重新開始計數;結束條件為 5000000

0,表示數到 1 秒就清零。

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

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

結束條件為 10,表示數到 10 秒就清零。

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

end_xs_sec_low,表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀態時數到 10 秒就

加 1;結束條件為 6,表示數到 60 秒就清零。

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

nd_xs_sec_high,表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀態時數到 1 分就加

1;結束條件為 10,表示數到 10 分就清零。

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

end_xs_min_low,表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀態時數到 10 分就

加 1;結束條件為 6,表示數到 60 分就清零。

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

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

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


四個計數器相互獨立,互不干涉,結構圖如下:

該架構由 4 個計數器組成:秒低位計數器 sec_low、秒高位計數器 sec_high、分低位計數器 mi

n_low、分高位計數器 min_high。

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

表示在設置狀態下通過按鍵 key3 來控制加一 ;結束條件為 10,表示最大能設置為 9,超過之后便

清零。

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

表示在設置狀態下可通過按鍵 key3 來控制加一;結束條件為 6,表示最大能設置為 5,超過之后便

清零。

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

表示在設置狀態下可通過按鍵 key3 來控制加一;結束條件為 10,表示最大能設置為 9,超過之后便

清零。

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

表示在設置狀態下可通過按鍵 key3 來控制加一;結束條件為 6,表示最大能設置為 5,超過之后便

清零。


1.4.3 參考代碼

使用明德揚的計數器模板,可以很快速很熟練地寫出時間產生模塊。





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 數碼管顯示模塊設計


1.5.1 接口信號



1.5.2 設計思路

在前面的案例中已經有數碼管顯示的介紹,所以這里不在過多介紹,詳細介紹請看下方鏈接:

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 蜂鳴器模塊設計

1.6.1 接口信號



1.6.2 設計思路

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

續時間為 5 秒。由此提出一個計數器的架構,如下圖所示。



該架構由蜂鳴器控制信號 beep、秒計數器 miao 和鬧鐘觸發指示信號 flag_add 組成。

秒計數器秒:用于對 5 秒的時間進行計數,加一條件為 flag_add && end_counter,表示當鬧

鐘被觸發,并且經過 1 秒的時間就加一;結束條件為 5,表示數完 5 秒就清零。

鬧鐘觸發指示信號 flag:當其為高電平時表示鬧鐘被觸發,低電平表示沒有被觸發。初始狀態為

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

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

設置的秒高低位、分高低位相等,同時不處于剛上電的初始狀態和設置狀態時,鬧鐘被觸發;從高變

低的條件為 end_miao,表示當 5 秒數完之后,就拉低。

蜂鳴器控制信號 beep:當其為低電平時,控制蜂鳴器響,為高電平時不響。初始狀態為高電平,

從高變低的條件為 flag_add,表示計數器開始計數之后便將其拉低,當檢測到 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 效果和總結

? 下圖是該工程在 mp801 開發板上的現象

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

邊四個數碼管顯示的是時鐘的時間,右邊四個數碼管顯示的是鬧鐘設置的時間。



? 下圖是該工程在 db603 開發板上的現象

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

邊四個數碼管顯示的是時鐘的時間,右邊四個數碼管顯示的是鬧鐘設置的時間。



? 下圖是該工程在 ms980 試驗箱上的現象

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

邊四個數碼管顯示的是時鐘的時間,右邊四個數碼管顯示的是鬧鐘設置的時間。



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

完整現象的朋友可以看一下現象演示的視頻。


感興趣的朋友也可以訪問明德揚論壇(http://www.fpgabbs.cn/)進行 FPGA 相關工程設計學習,

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

《基于 FPGA 的密碼鎖設計》

《波形相位頻率可調 DDS 信號發生器》

《基于 FPGA 的曼徹斯特編碼解碼設計》

《基于 FPGA 的出租車計費系統》

《數電基礎與 Verilog 設計》

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

《基于 FPGA 的漢明碼編碼解碼設計》

《關于鎖存器問題的討論》

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

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


明德揚是一家專注于 FPGA 領域的專業性公司,公司主要業務包括開發板、教育培訓、項目承

接、人才服務等多個方向。

點撥開發板——學習 FPGA 的入門之選。

MP801 開發板——千兆網、ADDA、大容量 SDRAM 等,學習和項目需求一步到位。

網絡培訓班——不管時間和空間,明德揚隨時在你身邊,助你快速學習 FPGA。

周末培訓班——明天的你會感激現在的努力進取,升職加薪明德揚來助你。

就業培訓班——七大企業級項目實訓,獲得豐富的項目經驗,高薪就業。

專題課程——高手修煉課:提升設計能力;實用調試技巧課:提升定位和解決問題能力;FIFO 架構

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

項目承接——承接企業 FPGA 研發項目。

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


   拓展閱讀
主站蜘蛛池模板: 蜜桃一区| 欧美激情婷婷 | 银杏视频影院在线看 | 欧美三级成人观看 | 大陆精品偷拍视频在线播放 | 亚洲国产人成中文幕一级二级 | 狠狠色成人综合网图片区 | 欧美1区2区3区 | 亚洲成a人片在线观看中文 亚洲成a人片在线观看中文动漫 | 亚洲 另类色区 欧美日韩 | 日韩欧美第一页 | 亚洲a级片在线观看 | 黄视频在线播放 | 色优久久 | 手机能看的黄色网址 | 久久99精品久久久久久秒播放器 | 污污网站免费观看 | 久久久精品日本一区二区三区 | 亚洲精品国产福利片 | 欧美伦理片在线 | 国产玖玖视频 | 亚洲国产精品免费观看 | 欧美午夜免费毛片a级 | 亚洲成本人网亚洲视频大全 | 免费一级毛片不卡在线播放 | 国产主播专区 | 免费一级毛片在线播放不收费 | 永久免费视频网站在线观看 | 国产短视频精品区第一页 | 日本一级毛一级毛片短视频 | 国产精品天天看特色大片不卡 | 在线播放国产视频 | 国产精品视频一区麻豆 | 丁香婷婷激情网 | 亚洲精品一级片 | a毛片视频 | 亚洲最大成人综合网 | 精品国产成人a在线观看 | 中国的毛片 | 欧美日韩成人在线观看 | 亚洲高清在线看 |