现在的位置: 首页 > 综合 > 正文

(原創) 如何設計電子鐘(I)? (SOC) (Verilog) (DE2)

2013年07月07日 ⁄ 综合 ⁄ 共 6916字 ⁄ 字号 评论关闭

Abstract
學會計數器除頻電路後,就能以這兩個電路為基礎,設計一個電子鐘,並可自行調整目前時間。

Introduction
使用環境:Quartus II 7.2 SP3 + DE2(Cyclone II EP2C35F627C6)

(筆記) 如何設計計數器? (SOC) (Verilog) (MegaCore)討論過計數器,接著在(原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)討論過萬用除頻器,利用這兩個基礎,就可以設計一個簡易的電子鐘,如同電子錶一樣顯示時間。

Specification

SW17 enable
SW16 reset
SW15 load (設定時間)
SW[3:0] 設定分的個位數
SW[6:4] 設定分的十位數
SW[10:7] 設定時的個位數
SW[13:11] 設定時的十位數
HEX[2] 顯示秒的個位數
HEX[3] 顯示秒的十位數
HEX[4] 顯示分的個位數
HEX[5] 顯示分的十位數
HEX[6] 顯示時的個位數
HEX[7] 顯示時的十位數

 

Block Diagram

 

 

 digi_clock00

digi_clock01

這是一個簡化的系統方塊圖,因為寬度的關係,我將input與output都與以省略,上圖的divn是個除頻器,負責將DE2提供的50MHz clock除頻程1 Hz,seg7_lut則是負責將數字顯示在7段顯示器上。clock的細部實現為下圖,由兩個60計數器負責,24計數器負責

digi_clock.v / Verilog

1 /* 
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4 Filename    : digi_clock.v
5 Compiler    : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g
6 Description : Demo how to write digital clock top module
7 Release     : 07/27/2008 1.0
8 */
9 
10 module digi_clock (
11   input         CLOCK_50,
12   input  [17:0] SW,
13   input  [3:0]  KEY,
14   output [6:0]  HEX2,
15   output [6:0]  HEX3,
16   output [6:0]  HEX4,
17   output [6:0]  HEX5,
18   output [6:0]  HEX6,
19   output [6:0]  HEX7
20 );
21 
22 wire       clk_1;
23 wire [3:0] w_sq0;
24 wire [2:0] w_sq1;
25 wire [3:0] w_mq0;
26 wire [2:0] w_mq1;
27 wire [3:0] w_hq0;
28 wire [2:0] w_hq1;
29 
30 // 1Hz clock
31 divn # (.WIDTH(26), .N(50000000))
32 u0 (
33   .clk(CLOCK_50),
34   .rst_n(KEY[0]),
35   .o_clk(clk_1)
36 );
37 
38 clock u1 (
39   .clk(clk_1),
40   .en(SW[17]),     // input  enable
41   .clr(SW[16]),    // input  clear
42   .load(SW[15]),   // input  load
43   .sd0(4'h0),      // input  second digit 0
44   .sd1(3'h0),      // input  second digit 1
45   .md0(SW[3:0]),   // input  minute digit 0
46   .md1(SW[6:4]),   // input  minute digit 1
47   .hd0(SW[10:7]),  // input  hour digit   0
48   .hd1(SW[13:11]), // input  hour digit   1
49   .sq0(w_sq0),     // output second digit 0
50   .sq1(w_sq1),     // output second digit 1
51   .mq0(w_mq0),     // output minute digit 0
52   .mq1(w_mq1),     // output minute digit 1
53   .hq0(w_hq0),     // output minute digit 0
54   .hq1(w_hq1)      // output minute digit 1
55 );
56 
57 // sec. dig0 to seg7
58 seg7_lut u2 (
59   .i_dig(w_sq0),
60   .o_seg(HEX2)
61 );
62 
63 // sec. dig1 to seg7
64 seg7_lut u3 (
65   .i_dig({1'b0, w_sq1}),
66   .o_seg(HEX3)
67 );
68 
69 // min. dig0 to seg7
70 seg7_lut u4 (
71   .i_dig(w_mq0),
72   .o_seg(HEX4)
73 );
74 
75 // min. dig1 to seg7
76 seg7_lut u5 (
77   .i_dig({1'b0, w_mq1}),
78   .o_seg(HEX5)
79 );
80 
81 // hour dig0 to seg7
82 seg7_lut u6 (
83   .i_dig(w_hq0),
84   .o_seg(HEX6)
85 );
86 
87 // hour dig1 to seg7
88 seg7_lut u7 (
89   .i_dig({1'b0, w_hq1}),
90   .o_seg(HEX7)
91 );
92 
93 endmodule

這是整個project的top module,為了簡化pin assignment的動作,所以port的命名方式和DE2_pin_assignments.csv相同,或許你跟我一樣不喜歡port用大寫的coding style,但為了pin assignment方便,只好在top module配合一下大寫,其他module的port一樣可以用小寫。

30行

// 1Hz clock
divn # (.WIDTH(26), .N(50000000))
u0 (
  .clk(CLOCK_50),
  .rst_n(KEY[
0]),
  .o_clk(clk_1)
);

divn為(原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)所寫過的萬用除頻器,由於DE2提供的clock是50MHz,但電子鐘只希望每秒變化一次,所以要除頻剩下1Hz,所以要將50MHz除50M,經過計算,這樣需26位才夠,所以傳進26與50000000。

divn.v / Verilog

1 /* 
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4 Filename    : divn.v
5 Compiler    : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g
6 Description : Demo how to write frequency divider by n
7 Release     : 07/16/2008 1.0
8 */
9 
10 module divn    (
11   input  clk,
12   input  rst_n,
13   output o_clk
14 );
15 
16 parameter WIDTH = 3;
17 parameter N     = 6;
18 
19 reg [WIDTH-1:0] cnt_p;
20 reg [WIDTH-1:0] cnt_n;
21 reg             clk_p;
22 reg             clk_n;
23 
24 assign o_clk = (N == 1) ? clk :
25                (N[0])   ? (clk_p | clk_n) : (clk_p);
26        
27 always@(posedge clk or negedge rst_n) begin
28   if (!rst_n)
29     cnt_p <= 0;
30   else if (cnt_p == (N-1))
31     cnt_p <= 0;
32   else
33     cnt_p <= cnt_p + 1;
34 end
35 
36 always@(posedge clk or negedge rst_n) begin
37   if (!rst_n)
38     clk_p <= 1;
39   else if (cnt_p < (N>>1))
40     clk_p = 1;
41   else
42     clk_p = 0;   
43 end
44 
45 always@(negedge clk or negedge rst_n) begin
46   if (!rst_n)
47     cnt_n <= 0;
48   else if (cnt_n == (N-1))
49     cnt_n <= 0;
50   else
51     cnt_n <= cnt_n + 1;
52 end
53 
54 always@(negedge clk or negedge rst_n) begin
55   if (!rst_n)
56     clk_n <= 1;
57   else if (cnt_n < (N>>1))
58     clk_n = 1;
59   else
60     clk_n = 0;
61 end
62 
63 endmodule
64 

dinn.v請參考(原創) 如何設計除頻器? (SOC) (Verilog) (MegaCore)中的討論。

seg7_lut.v / Verilog

1 /* 
2 (C) OOMusou 2008 http://oomusou.cnblogs.com
3 
4 Filename    : seg7_lut.V
5 Compiler    : Quartus II 7.2 SP3
6 Description : Demo how to use 8 bit 7 segment display decimal
7 Release     : 07/20/2008 1.0
8 */
9 module seg7_lut (
10   input      [3:0] i_dig,
11   output reg [6:0] o_seg
12 );
13 
14 always@(i_dig) begin
15   case(i_dig)
16     4'h1: o_seg = 7'b111_1001;  // ---t----
17     4'h2: o_seg = 7'b010_0100;  // |      |
18     4'h3: o_seg = 7'b011_0000;  // lt    rt
19     4'h4: o_seg = 7'b001_1001;  // |      |
20     4'h5: o_seg = 7'b001_0010;  // ---m----
21     4'h6: o_seg = 7'b000_0010;  // |      |
22     4'h7: o_seg = 7'b111_1000;  // lb    rb
23     4'h8: o_seg = 7'b000_0000;  // |      |
24     4'h9: o_seg = 7'b001_1000;  // ---b----
25     4'ha: o_seg = 7'b000_1000;
26     4'hb: o_seg = 7'b000_0011;
27     4'hc: o_seg = 7'b100_0110;
28     4'hd: o_seg = 7'b010_0001;
29     4'he: o_seg = 7'b000_0110;
30     4'hf: o_seg = 7'b000_1110;
31     4'h0: o_seg = 7'b100_0000;
32   endcase
33 end
34 
35 endmodule

這是一個7段顯示器的lookup table,請參考(原創) 如何以16進位顯示8位數的七段顯示器? (SOC) (Verilog) (DE2)

clock.v / Verilog

  1 /* 
  2 (C) OOMusou 2008 http://oomusou.cnblogs.com
  3 
  4 Filename    : clock.v
  5 Compiler    : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g
  6 Description : Demo how to write clock counter
  7 Release     : 07/28/2008 1.0
  8 */
  9 
10 module clock (
11   input        clk,
12   input        en, 
13   input        clr,
14   input        load,
15   input  [3:0] sd0,
16   input  [2:0] sd1,
17   input  [3:0] md0,
18   input  [2:0] md1,
19   input  [3:0] hd0,
20   input  [2:0] hd1,
21   output [3:0] sq0,
22   output [2:0] sq1, 
23   output [3:0] mq0,
24   output [2:0] mq1,
25   output [3:0] hq0,
26   output [1:0] hq1,
27   output       co  
28 );
29 
30 wire       w_clr;
31 wire [3:0] w_md0;
32 wire [2:0] w_md1;
33 reg  [3:0] w_hd0;
34 reg  [2:0] w_hd1;
35 wire       w_sco; // second carry
36 wire       w_mco; // minute carry
37 wire       w_hco; // hour carry
38 
39 counter60 sec (
40   .clk(clk),
41   .load(load),
42   .clr(w_clr),
43   .en(en),
44   .d0(sd0),
45   .d1(sd1),
46   .q0(sq0),
47   .q1(sq1),
48   .co(w_sco)
49 );
50 
51 counter60 min (
52   .clk(clk),
53   .load(load),
54   .clr(w_clr),
55   .en(en & w_sco),
56   .d0(w_md0),
57   .d1(w_md1),
58   .q0(mq0),
59   .q1(mq1),
60   .co(w_mco)
61 );
62 
63 counter24 hour (
64   .clk(clk),
65   .load(load),
66   .clr(w_clr),
67   .en(en & w_mco & w_sco),
68   .d0(w_hd0),
69   .d1(w_hd1),
70   .q0(hq0),
71   .q1(hq1),
72   .co(w_hco)
73 );
74 
75 assign w_clr = clr | co;
76 assign co    = w_hco & w_mco & w_sco;
77 assign w_md0 = (!load) ? 0 :
78                (md0 < 10) ? md0 : 9;
79 assign w_md1 = (!load) ? 0 :
80                (md1 < 6? md1 : 5;
81                      
82 always@(load or hd0 or hd1) begin
83   if (!load) begin
84     w_hd0 = 0;
85     w_hd1 = 0;
86   end
87   else begin
88     if (hd1 <= 1) begin // 0 1
89       w_hd1 = hd1;
90      
91       if (hd0 < 10)
92         w_hd0 = hd0;
93       else
94         w_hd0 = 9;
95     end
96     else begin // >= 2
97       w_hd1 = 2;
98      
99       if (hd0 < 4)
100         w_hd0 = hd0;
101       else
102         w_hd0 = 3;
103     end
104   end
105 end                       
106 
107 endmodule

clock.v事實上已經是一個完整功能的電子鐘,可以單獨用testbench測試,但為了要和DE2周邊搭配,所以才又包了一個digi_clock.v。

clock.v主要有兩個功能:
1.例化時、分、秒3個instance。
2.對輸入做防呆的動作。

75行

assign w_clr = clr | co;
assign co    = w_hco & w_mco &

抱歉!评论已关闭.