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



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

【案例】按鍵控制數字時鐘設計

發布時間:2021-06-25   作者:admin 瀏覽量:

案例編號:001600000062

至簡設計系列_按鍵控制數字時鐘

--作者:小黑同學

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

1.1 總體設計

1.1.1 概述

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

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

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

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

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

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

1.1.2 設計目標

本設計要求實現可設置的數字時鐘(速度快 10 倍,每過 0.1s,秒數加 1),具體要求如下:

1、 按下按鍵 key1,時鐘暫停,跳到設置時間狀態,在按按鍵 key1,回到正常狀態。

2、 通過按鍵 key2,選擇要設置的位置,初始時設置秒低位,按一下,設置秒高位,再按下,

設置分低位,依次類推,循環設置。

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

4、 通過數碼管將時間實時顯示出來。

5、 如果開發板上的按鍵是矩陣鍵盤,那么要產生需要的按鍵信號,需要通過例化矩陣鍵盤模塊

來產生。

1.1.3 系統結構框圖

系統結構框圖如下所示:

「每周FPGA案例」按鍵控制數字時鐘設計
「每周FPGA案例」按鍵控制數字時鐘設計

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

發板上是矩陣鍵盤的時候,對應的結構圖是圖二。

1.1.4 模塊功能

? 按鍵檢測模塊實現功能

將外來異步信號打兩拍處理,將異步信號同步化;

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

? 矩陣鍵盤模塊實現功能

將外來異步信號打兩拍處理,將異步信號同步化;

實現 20ms 按鍵消抖功能;

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

? 時間產生模塊實現功能

產生時間數據;

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

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

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

1.1.5 頂層信號

「每周FPGA案例」按鍵控制數字時鐘設計

1.1.6 參考代碼

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


1.	module  key_clock(  
2.	    clk    ,  
3.	    rst_n  ,  
4.	    key    ,  
5.	    segment,  
6.	    seg_sel  
7.	);  
8.	  
9.	parameter   COUNT_TIME      =   23'd500_0000;  
10.	parameter   DELAY_TIME      =   10000       ;  
11.	parameter   SEG_WID         =   8           ;  
12.	parameter   SEG_SEL         =   6           ;  
13.	  
14.	parameter   KEY_S           =   4           ;  
15.	parameter   KEY_W           =   3           ;  
16.	  
17.	input                   clk         ;  
18.	input                   rst_n       ;  
19.	input   [ 2:0]          key         ;  
20.	output  [ 7:0]          segment     ;  
21.	output  [ 6:0]          seg_sel     ;  
22.	  
23.	wire    [ 2:0]          key_vld     ;  
24.	wire    [23:0]          segment_data;  
25.	wire    [ 3:0]          cnt2        ;  
26.	wire    [ 3:0]          cnt3        ;  
27.	wire    [ 3:0]          cnt4        ;  
28.	wire    [ 3:0]          cnt5        ;  
29.	wire    [ 3:0]          cnt6        ;  
30.	wire    [ 3:0]          cnt7        ;  
31.	  
32.	  
33.	             key_module  uut0(  
34.	                .clk     (clk    ),  
35.	                .rst_n   (rst_n  ),  
36.	                .key_in  (key    ),  
37.	                .key_vld (key_vld)  
38.	             );  
39.	  
40.	  
41.	             time_data  uut1(  
42.	                .clk      (clk    ),   
43.	                .rst_n    (rst_n  ),   
44.	                .key_vld  (key_vld),   
45.	                .cnt2     (cnt2   ),   
46.	                .cnt3     (cnt3   ),   
47.	                .cnt4     (cnt4   ),   
48.	                .cnt5     (cnt5   ),   
49.	                .cnt6     (cnt6   ),   
50.	                .cnt7     (cnt7   )   
51.	  
52.	             );  
53.	  
54.	  
55.	             seg_disp  uut2(  
56.	                 .clk          (clk                          ),   
57.	                 .rst_n        (rst_n                        ),   
58.	                 .segment      (segment                      ),   
59.	                 .seg_sel      (seg_sel                      ),  
60.	                 .segment_data (cnt7,cnt6,cnt5,cnt4,cnt3,cnt2)   
61.	  
62.	             );  
63.	  
64.	  
65.	endmodule  


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


66.	module  key_clock_jvzhen(  
67.	    clk    ,  
68.	    rst_n  ,  
69.	    key_col,  
70.	    key_row,  
71.	    segment,  
72.	    seg_sel  
73.	);  
74.	  
75.	parameter   COUNT_TIME      =   23'd500_0000;  
76.	parameter   DELAY_TIME      =   10000       ;  
77.	parameter   SEG_WID         =   8           ;  
78.	parameter   SEG_SEL         =   6           ;  
79.	  
80.	parameter   KEY_S           =   4           ;  
81.	parameter   KEY_W           =   3           ;  
82.	  
83.	input                   clk         ;  
84.	input                   rst_n       ;  
85.	input   [ 3:0]          key_col     ;  
86.	output  [ 3:0]          key_row     ;  
87.	output  [ 7:0]          segment     ;  
88.	output  [ 6:0]          seg_sel     ;  
89.	  
90.	wire    [ 3:0]          key_vld     ;  
91.	wire    [ 3:0]          cnt2        ;  
92.	wire    [ 3:0]          cnt3        ;  
93.	wire    [ 3:0]          cnt4        ;  
94.	wire    [ 3:0]          cnt5        ;  
95.	wire    [ 3:0]          cnt6        ;  
96.	wire    [ 3:0]          cnt7        ;  
97.	  
98.	  
99.	             key_scan  uut0(  
100.	                .clk     (clk    ),  
101.	                .rst_n   (rst_n  ),  
102.	                .key_col (key_col),  
103.	                .key_row (key_row),  
104.	                .key_en  (key_vld)  
105.	             );  
106.	  
107.	  
108.	             time_data  uut1(  
109.	                .clk      (clk    ),   
110.	                .rst_n    (rst_n  ),   
111.	                .key_vld  (key_vld),   
112.	                .cnt2     (cnt2   ),   
113.	                .cnt3     (cnt3   ),   
114.	                .cnt4     (cnt4   ),   
115.	                .cnt5     (cnt5   ),   
116.	                .cnt6     (cnt6   ),   
117.	                .cnt7     (cnt7   )   
118.	  
119.	             );  
120.	  
121.	  
122.	             seg_disp  uut2(  
123.	                 .clk          (clk                            ),   
124.	                 .rst_n        (rst_n                          ),   
125.	                 .segment      (segment                        ),   
126.	                 .seg_sel      (seg_sel                        ),  
127.	                 .segment_data ({cnt7,cnt6,cnt5,cnt4,cnt3,cnt2})  
128.	             );  
129.	  
130.	  
131.	endmodule  


1.2 按鍵檢測模塊設計

1.2.1 接口信號

「每周FPGA案例」按鍵控制數字時鐘設計

1.2.2 設計思路

? 硬件電路

「每周FPGA案例」按鍵控制數字時鐘設計

獨立式按鍵工作原理如上圖所示,4 條輸入線連接到 FPGA 的 IO 口上,當按鍵 S1 按下時,3.

3V 的電源通過電阻 R53 再通過按鍵 S1 最終進入 GND 形成一條通路,這條線路的全部電壓都加在 R

53 上,則 KS0 是低電平。當松開按鍵后,線路斷開,就不會有電流通過,KS0 應該是 3.3V,為高電

平。我們可以通過 KS0 這個 IO 口的高低電平狀態來判斷是否有按鍵按下。其他按鍵原理與 S1 一致。

從圖上可以看出,如果我們按下按鍵,那么按鍵就會接通并連接到低電平 GND,如果我們沒有

按下,那么按鍵就會斷開并接到 3.3V,因此按鍵為低電平有效。通常的按鍵所用開關為機械彈性開

關,當機械觸點斷開或者閉合時,由于機械觸點的彈性作用,一個按鍵開關在閉合時不會馬上穩定地

接通,在斷開時也不會一下子斷開。因而機械式按鍵在閉合及斷開的瞬間均伴隨有一連串的抖動,如

果不進行處理,會使系統識別到抖動信號而進行不必要的反應,導致模塊功能不正常,為了避免這種

現象的產生,需要進行按鍵消抖的操作

? 按鍵消抖

按鍵消抖主要分為硬件消抖和軟件消抖。兩個"與非"門構成一個 RS 觸發器為常用的硬件消抖。

軟件方法消抖,即檢測出鍵閉合后執行一個延時程序,抖動時間的長短由按鍵的機械特性決定,一般

為 5ms~20ms,讓前沿抖動消失后再一次檢測鍵的狀態,如果仍保持閉合狀態電平,則確認按下按

鍵操作有效。當檢測到按鍵釋放后,也要給 5ms~20ms 的延時,待后沿抖動消失后才能轉入該鍵的

處理程序。經過按鍵消抖的行人優先按鍵,判斷按鍵有效后,按鍵信號傳遞給控制系統,控制系統再

進入相應的處理程序。

「每周FPGA案例」按鍵控制數字時鐘設計

由于按鍵按下去的時間一般都會大于 20ms,為了達到不管按鍵按下多久,都視為按下一次的效

果,提出以下計數器架構,如下圖所示:

「每周FPGA案例」按鍵控制數字時鐘設計

消抖計數器 cnt:用于計算 20ms 的時間,加一條件為 flag==0 &&(&key_in_ff1==0),表示當

某個按鍵按下就開始計數;結束條件為 100000,表示數到 20ms 就結束

按鍵:表示被按下的按鍵,沒被按下時為高電平,按下后為低電平。

Flag:20ms 指示信號,默認為低電平,當按鍵按鍵按下 20ms 后變為高電平,直到按鍵信號變

高電平,重新拉低。

1.2.3 參考代碼

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


132.	module key_module(  
133.	    clk    ,  
134.	    rst_n  ,  
135.	    key_in ,  
136.	    key_vld   
137.	);  
138.	parameter                           DATA_W    = 20          ;  
139.	parameter                           KEY_W     = 3           ;  
140.	parameter                           TIME_20MS = 1_000_000   ;  
141.	  
142.	input                               clk                     ;  
143.	input                               rst_n                   ;  
144.	input           [KEY_W-1 :0]        key_in                  ;  
145.	output          [KEY_W-1 :0]        key_vld                 ;  
146.	reg             [KEY_W-1 :0]        key_vld                 ;  
147.	reg             [DATA_W-1:0]        cnt                     ;  
148.	wire                                add_cnt                 ;  
149.	wire                                end_cnt                 ;  
150.	reg                                 flag_add                ;  
151.	reg             [KEY_W-1 :0]        key_in_ff1              ;  
152.	reg             [KEY_W-1 :0]        key_in_ff0              ;  
153.	  
154.	  
155.	always  @(posedge clk or negedge rst_n)begin  
156.	    if(rst_n==1'b0)begin  
157.	        cnt <= 20'b0;  
158.	    end  
159.	    else if(add_cnt)begin  
160.	        if(end_cnt)  
161.	            cnt <= 20'b0;  
162.	        else  
163.	            cnt <= cnt + 1'b1;  
164.	    end  
165.	    else begin  
166.	        cnt <= 0;  
167.	    end  
168.	end  
169.	  
170.	assign add_cnt = flag_add==1'b0 && (&key_in_ff1==0);  
171.	assign end_cnt = add_cnt && cnt == TIME_20MS - 1;  
172.	  
173.	  
174.	always  @(posedge clk or negedge rst_n)begin  
175.	    if(rst_n==1'b0)begin  
176.	        flag_add <= 1'b0;  
177.	    end  
178.	    else if(end_cnt)begin  
179.	        flag_add <= 1'b1;  
180.	    end  
181.	    else if(&key_in_ff1==1)begin  
182.	        flag_add <= 1'b0;  
183.	    end  
184.	end  
185.	  
186.	  
187.	always  @(posedge clk or negedge rst_n)begin  
188.	    if(rst_n==1'b0)begin  
189.	        key_in_ff0 <= {{KEY_W}{1'b1}};  
190.	        key_in_ff1 <= {{KEY_W}{1'b1}};  
191.	    end  
192.	    else begin  
193.	        key_in_ff0 <= key_in    ;  
194.	        key_in_ff1 <= key_in_ff0;  
195.	    end  
196.	end  
197.	  
198.	  
199.	always  @(posedge clk or negedge rst_n)begin  
200.	    if(rst_n==1'b0)begin  
201.	        key_vld <= 0;  
202.	    end  
203.	    else if(end_cnt)begin  
204.	        key_vld <= ~key_in_ff1;  
205.	    end  
206.	    else begin  
207.	        key_vld <= 0;  
208.	    end  
209.	end  
210.	  
211.	  
212.	endmodule  


1.3 矩陣鍵盤模塊設計

1.3.1 接口信號

「每周FPGA案例」按鍵控制數字時鐘設計

1.3.2 設計思路

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

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

1.3.3 參考代碼


1.	module  key_scan(  
2.	                 clk    ,  
3.	                 rst_n  ,  
4.	                 key_col,  
5.	                 key_row,  
6.	                 key_en     
7.	               );  
8.	  
9.	  
10.	    parameter      KEY_W    =   4      ;  
11.	    parameter      CHK_COL  =   0      ;  
12.	    parameter      CHK_ROW  =   1      ;  
13.	    parameter      DELAY    =   2      ;  
14.	    parameter      WAIT_END =   3      ;  
15.	    parameter      COL_CNT  =   16     ;  
16.	    parameter      TIME_20MS=   1000000;  
17.	  
18.	    input               clk              ;  
19.	    input               rst_n            ;  
20.	    input [3:0]         key_col          ;  
21.	  
22.	    output[3:0]         key_en           ;  
23.	    output[KEY_W-1:0]   key_row          ;  
24.	  
25.	    reg   [3:0]         key_out          ;  
26.	    reg   [KEY_W-1:0]   key_row          ;  
27.	    reg                 key_vld          ;  
28.	  
29.	  
30.	    reg   [3:0]         key_col_ff0      ;  
31.	    reg   [3:0]         key_col_ff1      ;  
32.	    reg   [1:0]         key_col_get      ;  
33.	    reg   [3:0]         key_en           ;  
34.	    wire                end_shake_cnt    ;  
35.	    reg                 end_shake_cnt_ff0;  
36.	    reg   [3:0]         state_c          ;  
37.	    reg   [19:0]        shake_cnt        ;  
38.	    reg   [3:0]         state_n          ;  
39.	    reg   [1:0]         row_index        ;  
40.	    reg   [15:0]        row_cnt          ;  
41.	    wire                col2row_start    ;   
42.	    wire                row2del_start    ;  
43.	    wire                del2wait_start   ;  
44.	    wire                wait2col_start   ;  
45.	    wire                add_row_cnt      ;  
46.	    wire                end_row_cnt      ;  
47.	    wire                add_shake_cnt    ;  
48.	    wire                add_row_index    ;  
49.	    wire                end_row_index    ;  
50.	  
51.	  
52.	always  @(posedge clk or negedge rst_n)begin  
53.	    if(rst_n==1'b0)begin  
54.	        key_col_ff0 <= 4'b1111;  
55.	        key_col_ff1 <= 4'b1111;  
56.	    end  
57.	    else begin  
58.	        key_col_ff0 <= key_col    ;  
59.	        key_col_ff1 <= key_col_ff0;  
60.	    end  
61.	end  
62.	  
63.	  
64.	always @(posedge clk or negedge rst_n) begin   
65.	    if (rst_n==0) begin  
66.	        shake_cnt <= 0;   
67.	    end  
68.	    else if(add_shake_cnt) begin  
69.	        if(end_shake_cnt)  
70.	            shake_cnt <= 0;   
71.	        else  
72.	            shake_cnt <= shake_cnt+1 ;  
73.	   end  
74.	end  
75.	assign add_shake_cnt = key_col_ff1!=4'hf;  
76.	assign end_shake_cnt = add_shake_cnt  && shake_cnt == TIME_20MS-1 ;  
77.	  
78.	  
79.	always  @(posedge clk or negedge rst_n)begin  
80.	    if(rst_n==1'b0)begin  
81.	        state_c <= CHK_COL;  
82.	    end  
83.	    else begin  
84.	        state_c <= state_n;  
85.	    end  
86.	end  
87.	  
88.	always  @(*)begin  
89.	    case(state_c)  
90.	        CHK_COL: begin  
91.	                     if(col2row_start )begin  
92.	                         state_n = CHK_ROW;  
93.	                     end  
94.	                     else begin  
95.	                         state_n = CHK_COL;  
96.	                     end  
97.	                 end  
98.	        CHK_ROW: begin  
99.	                     if(row2del_start)begin  
100.	                         state_n = DELAY;  
101.	                     end  
102.	                     else begin  
103.	                         state_n = CHK_ROW;  
104.	                     end  
105.	                 end  
106.	        DELAY :  begin  
107.	                     if(del2wait_start)begin  
108.	                         state_n = WAIT_END;  
109.	                     end  
110.	                     else begin  
111.	                         state_n = DELAY;  
112.	                     end  
113.	                 end  
114.	        WAIT_END: begin  
115.	                     if(wait2col_start)begin  
116.	                         state_n = CHK_COL;  
117.	                     end  
118.	                     else begin  
119.	                         state_n = WAIT_END;  
120.	                     end  
121.	                  end  
122.	       default: state_n = CHK_COL;  
123.	    endcase  
124.	end  
125.	assign col2row_start = state_c==CHK_COL  && end_shake_cnt;  
126.	assign row2del_start = state_c==CHK_ROW  && row_index==3 && end_row_cnt;  
127.	assign del2wait_start= state_c==DELAY    && end_row_cnt;  
128.	assign wait2col_start= state_c==WAIT_END && key_col_ff1==4'hf;  
129.	  
130.	always  @(posedge clk or negedge rst_n)begin  
131.	    if(rst_n==1'b0)begin  
132.	        key_row <= 4'b0;  
133.	    end  
134.	    else if(state_c==CHK_ROW)begin  
135.	        key_row <= ~(1'b1 << row_index);  
136.	    end  
137.	    else begin  
138.	        key_row <= 4'b0;  
139.	    end  
140.	end  
141.	  
142.	  
143.	  
144.	  
145.	  
146.	always @(posedge clk or negedge rst_n) begin   
147.	    if (rst_n==0) begin  
148.	        row_index <= 0;   
149.	    end  
150.	    else if(add_row_index) begin  
151.	        if(end_row_index)  
152.	            row_index <= 0;   
153.	        else  
154.	            row_index <= row_index+1 ;  
155.	   end  
156.	   else if(state_c!=CHK_ROW)begin  
157.	       row_index <= 0;  
158.	   end  
159.	end  
160.	assign add_row_index = state_c==CHK_ROW && end_row_cnt;  
161.	assign end_row_index = add_row_index  && row_index == 4-1 ;  
162.	  
163.	  
164.	always @(posedge clk or negedge rst_n) begin   
165.	    if (rst_n==0) begin  
166.	        row_cnt <= 0;   
167.	    end  
168.	    else if(add_row_cnt) begin  
169.	        if(end_row_cnt)  
170.	            row_cnt <= 0;   
171.	        else  
172.	            row_cnt <= row_cnt+1 ;  
173.	   end  
174.	end  
175.	assign add_row_cnt = state_c==CHK_ROW || state_c==DELAY;  
176.	assign end_row_cnt = add_row_cnt  && row_cnt == 16-1 ;  
177.	  
178.	  
179.	  
180.	always  @(posedge clk or negedge rst_n)begin  
181.	    if(rst_n==1'b0)begin  
182.	        key_col_get <= 0;  
183.	    end  
184.	    else if(state_c==CHK_COL && end_shake_cnt ) begin  
185.	        if(key_col_ff1==4'b1110)  
186.	            key_col_get <= 0;  
187.	        else if(key_col_ff1==4'b1101)  
188.	            key_col_get <= 1;  
189.	        else if(key_col_ff1==4'b1011)  
190.	            key_col_get <= 2;  
191.	        else   
192.	            key_col_get <= 3;  
193.	    end  
194.	end  
195.	  
196.	  
197.	always  @(posedge clk or negedge rst_n)begin  
198.	    if(rst_n==1'b0)begin  
199.	        key_out <= 0;  
200.	    end  
201.	    else if(state_c==CHK_ROW && end_row_cnt)begin  
202.	        key_out <= {row_index,key_col_get};  
203.	    end  
204.	    else begin  
205.	        key_out <= 0;  
206.	    end  
207.	end  
208.	  
209.	always  @(posedge clk or negedge rst_n)begin  
210.	    if(rst_n==1'b0)begin  
211.	        key_vld <= 1'b0;  
212.	    end  
213.	    else if(state_c==CHK_ROW && end_row_cnt && key_col_ff1[key_col_get]==1'b0)begin  
214.	        key_vld <= 1'b1;  
215.	    end  
216.	    else begin  
217.	        key_vld <= 1'b0;  
218.	    end  
219.	end  
220.	  
221.	  
222.	always  @(*)begin  
223.	    if(rst_n==1'b0)begin  
224.	        key_en = 0;  
225.	    end  
226.	    else if(key_vld && key_out==0)begin  
227.	        key_en = 4'b0001;  
228.	    end  
229.	    else if(key_vld && key_out==1)begin  
230.	        key_en = 4'b0010;  
231.	    end  
232.	    else if(key_vld && key_out==2)begin  
233.	        key_en = 4'b0100;  
234.	    end  
235.	    else begin  
236.	        key_en = 0;  
237.	    end  
238.	end  
239.	  
240.	  
241.	Endmodule


1.4 時間產生模塊設計

1.4.1 接口信號

「每周FPGA案例」按鍵控制數字時鐘設計

1.4.2 設計思路

根據題目功能要求可知,要設計數字時鐘,由此我們可以提出 7 個計數器的架構,如下圖所示:

「每周FPGA案例」按鍵控制數字時鐘設計

該架構由 7 個計數器組成:時鐘計數器 cnt1、秒低位計數器 cnt2、秒高位計數器 cnt3、分低位

計數器 cnt4、分高位計數器 cnt5、時低位計數器 cnt6、時高位計數器 cnt7。

時鐘計數器 cnt1:用于計算 0.1 秒的時鐘個數,加一條件為 key1_func==0,表示剛上電時開始

計數,key1 按下之后停止計數,再按下又重新開始計數;結束條件為 5000000,表示數到 0.1 秒就

清零。

秒低位計數器 cnt2:用于對"1 秒"(實際為 0.1 秒)進行計數,加一條件為(key1_func &&cn

t0==0 &&key3_func)||(key1_func==0 &&end_cnt1),表示在設置狀態下可通過按鍵 key3 來控制加

一,或者在正常狀態時數到 1 秒就加 1;結束條件為 10,表示數到 10 秒就清零。

秒高位計數器 cnt3:用于對 10 秒進行計數,加一條件為(key1_func &&cnt0==1 &&key3_func)

||(key1_func==0 &&end_cnt2),表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀態時

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

分低位計數器 cnt4:用于對 1 分進行計數,加一條件為(key1_func &&cnt0==2 &&key3_func)|

|(key1_func==0 &&end_cnt3),表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀態時

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

分高位計數器 cnt5:用于對 10 分進行計數,加一條件為(key1_func &&cnt0==3 &&key3_func)

||(key1_func==0 &&end_cnt4),表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀態時

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

時低位計數器 cnt6:用于對 1 小時進行計數,加一條件為(key1_func &&cnt0==4 &&key3_fun

c)||(key1_func==0 &&end_cnt5),表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀態

時數到 1 小時就加 1;結束條件為 x,表示數到 x 小時就清零。

時高位計數器 cnt7:用于對 10 小時進行計數,加一條件為(key1_func &&cnt0==5 &&key3_fu

nc)||(key1_func==0 &&end_cnt6),表示在設置狀態下可通過按鍵 key3 來控制加一,或者在正常狀

態時數到 10 小時就加 1;結束條件為 y,表示數到 y*10 小時就清零。

1.4.3 參考代碼

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


1.	module time_data(  
2.	    clk      ,  
3.	    rst_n    ,  
4.	    key_vld  ,  
5.	    cnt2     ,  
6.	    cnt3     ,  
7.	    cnt4     ,  
8.	    cnt5     ,  
9.	    cnt6     ,  
10.	    cnt7  
11.	);  
12.	input                   clk         ;  
13.	input                   rst_n       ;  
14.	input   [ 3:0]          key_vld     ;  
15.	output  [ 3:0]          cnt2        ;  
16.	output  [ 3:0]          cnt3        ;  
17.	output  [ 3:0]          cnt4        ;  
18.	output  [ 3:0]          cnt5        ;  
19.	output  [ 3:0]          cnt6        ;  
20.	output  [ 3:0]          cnt7        ;  
21.	  
22.	reg                     key1_func   ;  
23.	reg                     key3_func   ;  
24.	reg     [ 2:0]          cnt0        ;  
25.	wire                    add_cnt0    ;  
26.	wire                    end_cnt0    ;  
27.	reg     [ 23:0]          cnt1       ;  
28.	wire                    add_cnt1    ;  
29.	wire                    end_cnt1    ;  
30.	reg     [ 3:0]          cnt2        ;  
31.	wire                    add_cnt2    ;  
32.	wire                    end_cnt2    ;  
33.	reg     [ 3:0]          cnt3        ;  
34.	wire                    add_cnt3    ;  
35.	wire                    end_cnt3    ;  
36.	reg     [ 3:0]          cnt4        ;  
37.	wire                    add_cnt4    ;  
38.	wire                    end_cnt4    ;  
39.	reg     [ 3:0]          cnt5        ;  
40.	wire                    add_cnt5    ;  
41.	wire                    end_cnt5    ;  
42.	reg     [ 3:0]          cnt6        ;  
43.	reg     [ 3:0]          x           ;  
44.	wire                    add_cnt6    ;  
45.	wire                    end_cnt6    ;  
46.	reg     [ 3:0]          cnt7        ;  
47.	reg     [ 1:0]          y           ;  
48.	wire                    add_cnt7    ;  
49.	wire                    end_cnt7    ;  
50.	  
51.	  
52.	  
53.	always  @(posedge clk or negedge rst_n)begin  
54.	    if(rst_n==1'b0)begin  
55.	        key1_func<=1'b0;  
56.	    end  
57.	    else if(key_vld[0]==1'b1)begin  
58.	        key1_func<=~key1_func;  
59.	    end  
60.	    else begin  
61.	        key1_func<=key1_func;  
62.	    end  
63.	end  
64.	  
65.	  
66.	  
67.	always @(posedge clk or negedge rst_n) begin   
68.	    if (rst_n==0) begin  
69.	        cnt0 <= 0;   
70.	    end  
71.	    else if(add_cnt0) begin  
72.	        if(end_cnt0)  
73.	            cnt0 <= 0;   
74.	        else  
75.	            cnt0 <= cnt0+1 ;  
76.	   end  
77.	end  
78.	assign add_cnt0 = key_vld[1];  
79.	assign end_cnt0 = add_cnt0  && cnt0 == 6-1 ;  
80.	  
81.	  
82.	always  @(posedge clk or negedge rst_n)begin  
83.	    if(rst_n==1'b0)begin  
84.	        key3_func<=1'b0;  
85.	    end  
86.	    else if(key1_func==1'b1 && key_vld[2]==1'b1)begin       
87.	        key3_func<=1'b1;  
88.	    end  
89.	    else begin  
90.	        key3_func<=1'b0;  
91.	    end  
92.	end  
93.	  
94.	  
95.	always @(posedge clk or negedge rst_n) begin   
96.	    if (rst_n==0) begin  
97.	        cnt1 <= 0;   
98.	    end  
99.	    else if(add_cnt1) begin  
100.	        if(end_cnt1)  
101.	            cnt1 <= 0;   
102.	        else  
103.	            cnt1 <= cnt1+1 ;  
104.	   end  
105.	   else begin  
106.	       cnt1 <= 0;  
107.	   end  
108.	end  
109.	assign add_cnt1 = key1_func==0;  
110.	assign end_cnt1 = add_cnt1  && cnt1 == 500_0000-1 ;  
111.	  
112.	  
113.	  
114.	  
115.	always @(posedge clk or negedge rst_n) begin   
116.	    if (rst_n==0) begin  
117.	        cnt2 <= 0;   
118.	    end  
119.	    else if(add_cnt2) begin  
120.	        if(end_cnt2)  
121.	            cnt2 <= 0;   
122.	        else  
123.	            cnt2 <= cnt2+1 ;  
124.	   end  
125.	end  
126.	assign add_cnt2 = (key1_func && cnt0==0 && key3_func) || (key1_func==0 && end_cnt1);  
127.	assign end_cnt2 = add_cnt2  && cnt2 == 10-1 ;  
128.	  
129.	  
130.	  
131.	  
132.	always @(posedge clk or negedge rst_n) begin   
133.	    if (rst_n==0) begin  
134.	        cnt3 <= 0;   
135.	    end  
136.	    else if(add_cnt3) begin  
137.	        if(end_cnt3)  
138.	            cnt3 <= 0;   
139.	        else  
140.	            cnt3 <= cnt3+1 ;  
141.	   end  
142.	end  
143.	assign add_cnt3 = (key1_func && cnt0==1 && key3_func) || (key1_func==0 && end_cnt2);  
144.	assign end_cnt3 = add_cnt3  && cnt3 == 6-1 ;  
145.	  
146.	  
147.	  
148.	always @(posedge clk or negedge rst_n) begin   
149.	    if (rst_n==0) begin  
150.	        cnt4 <= 0;   
151.	    end  
152.	    else if(add_cnt4) begin  
153.	        if(end_cnt4)  
154.	            cnt4 <= 0;   
155.	        else  
156.	            cnt4 <= cnt4+1 ;  
157.	   end  
158.	end  
159.	assign add_cnt4 = (key1_func && cnt0==2 && key3_func) || (key1_func==0 && end_cnt3);  
160.	assign end_cnt4 = add_cnt4  && cnt4 == 10-1 ;  
161.	  
162.	  
163.	always @(posedge clk or negedge rst_n) begin   
164.	    if (rst_n==0) begin  
165.	        cnt5 <= 0;   
166.	    end  
167.	    else if(add_cnt5) begin  
168.	        if(end_cnt5)  
169.	            cnt5 <= 0;   
170.	        else  
171.	            cnt5 <= cnt5+1 ;  
172.	   end  
173.	end  
174.	assign add_cnt5 = (key1_func && cnt0==3 && key3_func) || (key1_func==0 && end_cnt4);  
175.	assign end_cnt5 = add_cnt5  && cnt5 == 6-1 ;  
176.	  
177.	  
178.	always @(posedge clk or negedge rst_n) begin   
179.	    if (rst_n==0) begin  
180.	        cnt6 <= 0;   
181.	    end  
182.	    else if(add_cnt6) begin  
183.	        if(end_cnt6)  
184.	            cnt6 <= 0;   
185.	        else  
186.	            cnt6 <= cnt6+1 ;  
187.	   end  
188.	end  
189.	assign add_cnt6 = (key1_func && cnt0==4 && key3_func) || (key1_func==0 && end_cnt5);  
190.	assign end_cnt6 = add_cnt6  && cnt6 == x-1 ;  
191.	  
192.	  
193.	  
194.	always @(posedge clk or negedge rst_n) begin   
195.	    if (rst_n==0) begin  
196.	        cnt7 <= 0;   
197.	    end  
198.	    else if(add_cnt7) begin  
199.	        if(end_cnt7)  
200.	            cnt7 <= 0;   
201.	        else  
202.	            cnt7 <= cnt7+1 ;  
203.	   end  
204.	end  
205.	assign add_cnt7 = (key1_func && cnt0==5 && key3_func) || (key1_func==0 && end_cnt6);  
206.	assign end_cnt7 = add_cnt7  && cnt7 == y-1 ;  
207.	  
208.	  
209.	always  @(*)begin  
210.	    if(cnt7==2)begin  
211.	        x = 4;  
212.	    end  
213.	    else begin  
214.	        x =10;  
215.	    end  
216.	end  
217.	  
218.	always  @(*)begin  
219.	    if(cnt6>=4)begin  
220.	        y = 2;  
221.	    end  
222.	    else begin  
223.	        y = 3;  
224.	    end  
225.	end  
226.	  
227.	  
228.	endmodule  


1.5 數碼管顯示模塊設計

1.5.1 接口信號

「每周FPGA案例」按鍵控制數字時鐘設計

1.5.2 設計思路

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

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

1.5.3 參考代碼


1.	module seg_disp(  
2.	    clk         ,  
3.	    rst_n       ,  
4.	    segment     ,  
5.	    segment_data,  
6.	    seg_sel  
7.	);  
8.	parameter   ZERO            =   8'b1100_0000;  
9.	parameter   ONE             =   8'b1111_1001;  
10.	parameter   TWO             =   8'b1010_0100;  
11.	parameter   THREE           =   8'b1011_0000;  
12.	parameter   FOUR            =   8'b1001_1001;  
13.	parameter   FIVE            =   8'b1001_0010;  
14.	parameter   SIX             =   8'b1000_0010;  
15.	parameter   SEVEN           =   8'b1111_1000;  
16.	parameter   EIGHT           =   8'b1000_0000;  
17.	parameter   NINE            =   8'b1001_0000;  
18.	  
19.	  
20.	  
21.	input                   clk         ;  
22.	input                   rst_n       ;  
23.	input   [23:0]          segment_data;  
24.	output  [ 7:0]          segment     ;  
25.	output  [ 5:0]          seg_sel     ;  
26.	  
27.	  
28.	reg     [ 7:0]          segment     ;  
29.	wire    [ 7:0]          segment_tmp ;  
30.	reg     [ 5:0]          seg_sel     ;  
31.	  
32.	  
33.	reg     [15:0]          cnt8        ;  
34.	wire                    add_cnt8    ;  
35.	wire                    end_cnt8    ;  
36.	reg     [ 2:0]          cnt9        ;  
37.	wire                    add_cnt9    ;  
38.	wire                    end_cnt9    ;  
39.	  
40.	  
41.	  
42.	  
43.	always @(posedge clk or negedge rst_n) begin   
44.	    if (rst_n==0) begin  
45.	        cnt8 <= 0;   
46.	    end  
47.	    else if(add_cnt8) begin  
48.	        if(end_cnt8)  
49.	            cnt8 <= 0;   
50.	        else  
51.	            cnt8 <= cnt8+1 ;  
52.	   end  
53.	end  
54.	assign add_cnt8 = 1;  
55.	assign end_cnt8 = add_cnt8  && cnt8 == 10000-1 ;  
56.	  
57.	  
58.	  
59.	  
60.	always @(posedge clk or negedge rst_n) begin   
61.	    if (rst_n==0) begin  
62.	        cnt9 <= 0;   
63.	    end  
64.	    else if(add_cnt9) begin  
65.	        if(end_cnt9)  
66.	            cnt9 <= 0;   
67.	        else  
68.	            cnt9 <= cnt9+1 ;  
69.	   end  
70.	end  
71.	assign add_cnt9 = end_cnt8;  
72.	assign end_cnt9 = add_cnt9  && cnt9 == 6-1 ;  
73.	  
74.	  
75.	  
76.	  
77.	assign segment_tmp = segment_data[(1+cnt9)*4-1 -:4];  
78.	  
79.	always@(posedge clk or negedge rst_n)begin  
80.	    if(rst_n==1'b0)begin  
81.	         segment<=ZERO;  
82.	    end  
83.	    else  begin  
84.	        case(segment_tmp)  
85.	            4'd0:segment <= ZERO;  
86.	            4'd1:segment <= ONE;  
87.	            4'd2:segment <= TWO;  
88.	            4'd3:segment <= THREE;  
89.	            4'd4:segment <= FOUR;  
90.	            4'd5:segment <= FIVE ;  
91.	            4'd6:segment <= SIX ;  
92.	            4'd7:segment <= SEVEN ;  
93.	            4'd8:segment <= EIGHT ;  
94.	            4'd9:segment <= NINE ;  
95.	            default:begin  
96.	                segment<=segment;  
97.	            end  
98.	        endcase  
99.	    end  
100.	end  
101.	  
102.	  
103.	  
104.	  
105.	always@(posedge clk or negedge rst_n)begin  
106.	    if(rst_n==1'b0)begin  
107.	        seg_sel <= 6'b11_1110;  
108.	    end  
109.	    else begin  
110.	        seg_sel <= ~(6'b1<<cnt9);  
111.	    end  
112.	end  
113.	  
114.	endmodule  


1.6 效果和總結

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

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

「每周FPGA案例」按鍵控制數字時鐘設計

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

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

「每周FPGA案例」按鍵控制數字時鐘設計

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

「每周FPGA案例」按鍵控制數字時鐘設計

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

由于該項目的上板現象是動態的,開始、暫停、時間設置等

現象無法通過圖片表現出來,想觀看

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

設計視頻教程、工程源文件請到明德揚論壇觀看或下載!

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

往期推薦:

《基于 FPGA 的密碼鎖設計》

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

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

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

《數電基礎與 Verilog 設計》

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

   拓展閱讀
主站蜘蛛池模板: 亚洲精品一区二区三区在线播放| 日韩 亚洲 制服 欧美 综合 | 久久视频精品a线视频在线观看| 伊人色婷婷| 国产中文字幕在线视频| 真人特级毛片免费视频| 一级呦女专区毛片| 亚洲伦理在线| 色亚洲影院| 特黄特黄一级高清免费大片| 女人精69xxxxx免费视频| 亚洲人成在线精品| 亚洲欧美一二三区| 免费成人午夜视频| 欧美爱片| 国产成在线观看免费视频成本人| 黄色一级毛片免费看| 成人最新午夜免费视频| 色综合图区| 中日欧洲精品视频在线| 一级三级黄色片| 天天草夜夜骑| 欧美太黄太色视频在线观看| 麻豆传媒在线视频| 久久婷婷国产综合精品| 婷婷综合影院| 一区不卡在线观看| 久草a视频| 日本精品国产| 日韩美毛片| 成人免费视频网| 国产亚洲精品一区二区久久 | 亚洲国产第一区二区香蕉| 天堂mv亚洲mv在线播放9蜜| 老妇女五级毛片| 亚洲国产激情一区二区三区| 成人免费看黄| 成人三级影院| 成人黄色影视| 成人亚洲国产| 在线成人|