案(àn)例編号(hào):001600000064
至(zhì)簡設計(jì)系(xì)列_鬧鐘(zhōng)
--作者(zhě):小黑(hēi)同(tóng)学
本(běn)文(wén)为(wèi)明(míng)德揚原創及(jí)录(lù)用(yòng)文(wén)章(zhāng),轉(zhuǎn)载請注明(míng)出(chū)处!
1.1 總(zǒng)體(tǐ)設計(jì)
1.1.1 概述
數字(zì)时(shí)鐘(zhōng)是(shì)采用(yòng)數字(zì)電(diàn)路(lù)技術(shù)实現(xiàn)时(shí)、分(fēn)、秒(miǎo)計(jì)时(shí)顯示的(de)裝(zhuāng)置,可(kě)以(yǐ)用(yòng)數字(zì)同(tóng)时(shí)顯示时(shí),分(fēn),秒(miǎo)
的(de)精确时(shí)間(jiān)并实現(xiàn)準确校(xiào)时(shí),具備體(tǐ)積小、重(zhòng)量(liàng)輕(qīng)、抗干(gàn)擾能(néng)力強(qiáng)、对(duì)环(huán)境要(yào)求高(gāo)、高(gāo)精确性(xìng)、容易
開(kāi)發(fà)等特(tè)性(xìng),在(zài)工業控制系(xì)統、智能(néng)化(huà)儀器表(biǎo)、辦(bàn)公自(zì)動(dòng)化(huà)系(xì)統等诸多(duō)領域取(qǔ)得了(le)极(jí)为(wèi)廣泛的(de)應(yìng)用(yòng),
诸如(rú)自(zì)動(dòng)報警、按时(shí)自(zì)動(dòng)打(dǎ)鈴、时(shí)間(jiān)程序自(zì)動(dòng)控制、定(dìng)时(shí)廣播、自(zì)定(dìng)啟閉路(lù)燈(dēng)、定(dìng)时(shí)開(kāi)關(guān)烘箱、通(tòng)斷
動(dòng)力設備、甚至(zhì)各(gè)種(zhǒng)定(dìng)时(shí)電(diàn)器的(de)自(zì)動(dòng)啟用(yòng)等。與(yǔ)傳統表(biǎo)盤式機(jī)械时(shí)鐘(zhōng)相比,數字(zì)时(shí)鐘(zhōng)具有(yǒu)更(gèng)高(gāo)的(de)準确
性(xìng)和(hé)直(zhí)观性(xìng),由(yóu)于(yú)沒(méi)有(yǒu)機(jī)械裝(zhuāng)置,其使用(yòng)壽命更(gèng)长。
1.1.2 設計(jì)目标(biāo)
設計(jì)一(yī)款具有(yǒu)鬧鐘(zhōng)功能(néng)的(de)數字(zì)时(shí)鐘(zhōng),具體(tǐ)要(yào)求如(rú)下(xià)
1、 用(yòng) 8 个(gè)數碼管(guǎn)实現(xiàn),四(sì)个(gè)一(yī)組,每組有(yǒu)分(fēn)鐘(zhōng)和(hé)秒(miǎo)。左(zuǒ)邊(biān)一(yī)組是(shì)时(shí)間(jiān)顯示,右(yòu)邊(biān)一(yī)組用(yòng)来(lái)
做鬧鐘(zhōng)时(shí)間(jiān)。
2、 當左(zuǒ)邊(biān)时(shí)間(jiān)等于(yú)右(yòu)邊(biān)时(shí),蜂鳴器響 5 秒(miǎo)。
3、 鬧鐘(zhōng)时(shí)間(jiān)和(hé)顯示时(shí)間(jiān)均可(kě)通(tòng)过(guò) 3 个(gè)按鍵設置。設置方(fāng)法:按下(xià)按鍵 1,时(shí)鐘(zhōng)暫停,跳到(dào)
設置时(shí)間(jiān)狀态,再按下(xià)按鍵 1,回(huí)到(dào)正(zhèng)常狀态。通(tòng)过(guò)按鍵 2,選擇要(yào)設置的(de)位置,初始
設置秒(miǎo)个(gè)位,按一(yī)下(xià),設置秒(miǎo)十(shí)位,再按下(xià),設置分(fēn)个(gè)位,以(yǐ)此(cǐ)類(lèi)推,循环(huán)設置。通(tòng)过(guò)
按鍵 3,設置數值,按一(yī)下(xià)數值加 1,如(rú)果(guǒ)溢出(chū)則重(zhòng)新變(biàn)为(wèi) 0。
1.1.3 系(xì)統結構框图(tú)
系(xì)統結構框图(tú)如(rú)下(xià)所(suǒ)示:
結構图(tú)共(gòng)分(fēn)两(liǎng)个(gè),如(rú)果(guǒ)使用(yòng)的(de)開(kāi)發(fà)板上(shàng)是(shì)矩阵(zhèn)鍵盤的(de)时(shí)候,对(duì)應(yìng)的(de)結構图(tú)是(shì)图(tú)一(yī)。如(rú)果(guǒ)使用(yòng)的(de)開(kāi)
發(fà)板上(shàng)是(shì)普通(tòng)按鍵的(de)时(shí)候,对(duì)應(yìng)的(de)結構图(tú)是(shì)图(tú)二(èr)。


1.1.4 模块(kuài)功能(néng)
➢ 按鍵檢测模块(kuài)实現(xiàn)功能(néng)
1、将外(wài)来(lái)异(yì)步信(xìn)号(hào)打(dǎ)两(liǎng)拍处理,将异(yì)步信(xìn)号(hào)同(tóng)步化(huà)。
2、实現(xiàn) 20ms 按鍵消抖功能(néng),并輸出(chū)有(yǒu)效按鍵信(xìn)号(hào)。
➢ 矩阵(zhèn)鍵盤模块(kuài)实現(xiàn)功能(néng)
1、将外(wài)来(lái)异(yì)步信(xìn)号(hào)打(dǎ)两(liǎng)拍处理,将异(yì)步信(xìn)号(hào)同(tóng)步化(huà)。
2、实現(xiàn) 20ms 按鍵消抖功能(néng)。
3、实現(xiàn)矩阵(zhèn)鍵盤的(de)按鍵檢测功能(néng),并輸出(chū)有(yǒu)效按鍵信(xìn)号(hào)。
➢ 时(shí)間(jiān)産生(shēng)模块(kuài)实現(xiàn)功能(néng)
1、 産生(shēng)顯示时(shí)間(jiān)數據(jù)。
2、 産生(shēng)鬧鐘(zhōng)时(shí)間(jiān)數據(jù),
3、根(gēn)據(jù)接收(shōu)到(dào)的(de)不(bù)同(tóng)的(de)按鍵信(xìn)号(hào),産生(shēng)暫停、開(kāi)啟、設置时(shí)間(jiān)的(de)功能(néng)。
➢ 數碼管(guǎn)顯示模块(kuài)实現(xiàn)功能(néng)
1、 对(duì)接收(shōu)到(dào)的(de)时(shí)間(jiān)數據(jù)進(jìn)行譯碼。
➢ 蜂鳴器模块(kuài)实現(xiàn)功能(néng)
1、 将接受到(dào)的(de)顯示时(shí)間(jiān)數據(jù)與(yǔ)鬧鐘(zhōng)时(shí)間(jiān)數據(jù)進(jìn)行比較,控制蜂鳴器的(de)開(kāi)啟。
1.1.5 頂层信(xìn)号(hào)

1.1.6 參考代(dài)碼
下(xià)面(miàn)是(shì)使用(yòng)普通(tòng)按鍵的(de)頂层代(dài)碼:
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
下(xià)面(miàn)是(shì)使用(yòng)矩阵(zhèn)鍵盤的(de)頂层代(dài)碼:
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 按鍵檢测模块(kuài)設計(jì)
1.2.1 接口(kǒu)信(xìn)号(hào)

1.2.2 設計(jì)思(sī)路(lù)
在(zài)前(qián)面(miàn)的(de)案(àn)例中(zhōng)已經(jīng)有(yǒu)按鍵檢测的(de)介紹,所(suǒ)以(yǐ)这(zhè)里(lǐ)不(bù)在(zài)过(guò)多(duō)介紹,詳细(xì)介紹請看(kàn)下(xià)方(fāng)鍊(liàn)接:
【每周 FPGA 案(àn)例】至(zhì)簡設計(jì)系(xì)列_按鍵控制數字(zì)时(shí)鐘(zhōng)
1.2.3 參考代(dài)碼
使用(yòng)明(míng)德揚的(de)計(jì)數器模板,可(kě)以(yǐ)很快(kuài)速很熟練地(dì)写出(chū)按鍵消抖模块(kuài)。
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 矩阵(zhèn)鍵盤模块(kuài)設計(jì)
1.3.1 接口(kǒu)信(xìn)号(hào)

1.3.2 設計(jì)思(sī)路(lù)
在(zài)前(qián)面(miàn)的(de)案(àn)例中(zhōng)已經(jīng)有(yǒu)矩阵(zhèn)鍵盤的(de)介紹,所(suǒ)以(yǐ)这(zhè)里(lǐ)不(bù)在(zài)过(guò)多(duō)介紹,詳细(xì)介紹請看(kàn)下(xià)方(fāng)鍊(liàn)接:
http://fpgabbs.com/forum.php?mod=viewthread&tid=310
1.3.3 參考代(dài)碼
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 时(shí)間(jiān)産生(shēng)模块(kuài)設計(jì)
1.4.1 接口(kǒu)信(xìn)号(hào)

1.4.2 設計(jì)思(sī)路(lù)
根(gēn)據(jù)題(tí)目功能(néng)要(yào)求可(kě)知,要(yào)顯示的(de)时(shí)間(jiān)就(jiù)是(shì)在(zài)完整的(de)數字(zì)时(shí)鐘(zhōng)的(de)基礎上(shàng),減少(shǎo)了(le)时(shí)的(de)高(gāo)位和(hé)低位
的(de)顯示,再介紹架構之前(qián),先(xiān)了(le)解(jiě)一(yī)下(xià)本(běn)模块(kuài)其他(tā)幾(jǐ)个(gè)信(xìn)号(hào)的(de)作用(yòng)。
設置狀态指示信(xìn)号(hào) flag_set:該信(xìn)号(hào)初始狀态为(wèi)低電(diàn)平,表(biǎo)示模块(kuài)处于(yú)正(zhèng)常工作狀态,當按下(xià)按
鍵 key1 时(shí),設置狀态指示信(xìn)号(hào)進(jìn)行翻轉(zhuǎn),變(biàn)为(wèi)高(gāo)電(diàn)平,表(biǎo)示進(jìn)入(rù)到(dào)設置狀态。
設置位計(jì)數器 sel_cnt:該計(jì)數器表(biǎo)示要(yào)設置的(de)位,初始狀态为(wèi) 0,表(biǎo)示可(kě)以(yǐ)設置鬧鐘(zhōng)的(de)秒(miǎo)低位,
當其为(wèi) 1 时(shí)表(biǎo)示可(kě)以(yǐ)設置鬧鐘(zhōng)的(de)秒(miǎo)的(de)高(gāo)位,按照这(zhè)樣(yàng)的(de)順序依次(cì)類(lèi)推,當其为(wèi) 7 的(de)时(shí)候,表(biǎo)示可(kě)以(yǐ)設
置顯示时(shí)間(jiān)的(de)分(fēn)高(gāo)位。加一(yī)条(tiáo)件(jiàn)为(wèi) key_vld[1]==1'b1,表(biǎo)示按下(xià)按鍵 key2 的(de)时(shí)候加一(yī);結束(shù)条(tiáo)件(jiàn)为(wèi) 8,
顯示时(shí)間(jiān)的(de)四(sì)个(gè)數碼管(guǎn)加上(shàng)鬧鐘(zhōng)的(de)四(sì)个(gè)數碼管(guǎn)共(gòng) 8 个(gè),所(suǒ)以(yǐ)數 8 个(gè)就(jiù)清(qīng)零(líng)。
由(yóu)此(cǐ)可(kě)提(tí)出(chū) 5 个(gè)計(jì)數器的(de)架構,如(rú)下(xià)图(tú)所(suǒ)示:

該架構由(yóu) 5 个(gè)計(jì)數器組成(chéng):时(shí)鐘(zhōng)計(jì)數器 counter、秒(miǎo)低位計(jì)數器 xs_sec_low、秒(miǎo)高(gāo)位計(jì)數器 xs
_sec_high、分(fēn)低位計(jì)數器 xs_min_low、分(fēn)高(gāo)位計(jì)數器 xs_min_high。
时(shí)鐘(zhōng)計(jì)數器 counter:用(yòng)于(yú)計(jì)算 1 秒(miǎo)的(de)时(shí)鐘(zhōng)个(gè)數,加一(yī)条(tiáo)件(jiàn)为(wèi) flag_set==1'b0,表(biǎo)示刚上(shàng)電(diàn)时(shí)開(kāi)
始計(jì)數,key1 按下(xià)之後(hòu),進(jìn)入(rù)設置模式,停止計(jì)數,再按下(xià)又重(zhòng)新開(kāi)始計(jì)數;結束(shù)条(tiáo)件(jiàn)为(wèi) 5000000
0,表(biǎo)示數到(dào) 1 秒(miǎo)就(jiù)清(qīng)零(líng)。
秒(miǎo)低位計(jì)數器 xs_sec_low:用(yòng)于(yú)对(duì) 1 秒(miǎo)進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi)(sel_cnt==5-1 && set_en) || e
nd_counter,表(biǎo)示在(zài)設置狀态下(xià)可(kě)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī),或(huò)者(zhě)在(zài)正(zhèng)常狀态时(shí)數到(dào) 1 秒(miǎo)就(jiù)加 1;
結束(shù)条(tiáo)件(jiàn)为(wèi) 10,表(biǎo)示數到(dào) 10 秒(miǎo)就(jiù)清(qīng)零(líng)。
秒(miǎo)高(gāo)位計(jì)數器 xs_sec_high:用(yòng)于(yú)对(duì) 10 秒(miǎo)進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi)(sel_cnt==6-1 && set_en) ||
end_xs_sec_low,表(biǎo)示在(zài)設置狀态下(xià)可(kě)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī),或(huò)者(zhě)在(zài)正(zhèng)常狀态时(shí)數到(dào) 10 秒(miǎo)就(jiù)
加 1;結束(shù)条(tiáo)件(jiàn)为(wèi) 6,表(biǎo)示數到(dào) 60 秒(miǎo)就(jiù)清(qīng)零(líng)。
分(fēn)低位計(jì)數器 xs_min_low:用(yòng)于(yú)对(duì) 1 分(fēn)進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi)(sel_cnt==7-1 && set_en) || e
nd_xs_sec_high,表(biǎo)示在(zài)設置狀态下(xià)可(kě)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī),或(huò)者(zhě)在(zài)正(zhèng)常狀态时(shí)數到(dào) 1 分(fēn)就(jiù)加
1;結束(shù)条(tiáo)件(jiàn)为(wèi) 10,表(biǎo)示數到(dào) 10 分(fēn)就(jiù)清(qīng)零(líng)。
分(fēn)高(gāo)位計(jì)數器 xs_min_high:用(yòng)于(yú)对(duì) 10 分(fēn)進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi)(sel_cnt==8-1 && set_en) ||
end_xs_min_low,表(biǎo)示在(zài)設置狀态下(xià)可(kě)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī),或(huò)者(zhě)在(zài)正(zhèng)常狀态时(shí)數到(dào) 10 分(fēn)就(jiù)
加 1;結束(shù)条(tiáo)件(jiàn)为(wèi) 6,表(biǎo)示數到(dào) 60 分(fēn)就(jiù)清(qīng)零(líng)。
上(shàng)面(miàn)介紹了(le)顯示时(shí)間(jiān)的(de)計(jì)數器架構,下(xià)面(miàn)我(wǒ)们(men)来(lái)思(sī)考一(yī)下(xià)鬧鐘(zhōng)部(bù)分(fēn)的(de)架構。
我(wǒ)们(men)都知道(dào)鬧鐘(zhōng)的(de)工作原理,它(tā)本(běn)身(shēn)不(bù)会(huì)自(zì)動(dòng)計(jì)數,需要(yào)我(wǒ)们(men)手(shǒu)動(dòng)設置。根(gēn)據(jù)本(běn)設計(jì)的(de)功能(néng)要(yào)求,
有(yǒu)四(sì)个(gè)數碼管(guǎn)来(lái)顯示設置的(de)鬧鐘(zhōng)秒(miǎo)的(de)高(gāo)低位和(hé)分(fēn)的(de)高(gāo)低位,因(yīn)此(cǐ)我(wǒ)们(men)提(tí)出(chū)四(sì)个(gè)計(jì)數器組成(chéng)的(de)架構,这(zhè)
四(sì)个(gè)計(jì)數器相互独立,互不(bù)干(gàn)涉,結構图(tú)如(rú)下(xià):

該架構由(yóu) 4 个(gè)計(jì)數器組成(chéng):秒(miǎo)低位計(jì)數器 sec_low、秒(miǎo)高(gāo)位計(jì)數器 sec_high、分(fēn)低位計(jì)數器 mi
n_low、分(fēn)高(gāo)位計(jì)數器 min_high。
秒(miǎo)低位計(jì)數器 sec_low:用(yòng)于(yú)对(duì)鬧鐘(zhōng)秒(miǎo)的(de)低位進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi) sel_cnt==1-1 && set_en,
表(biǎo)示在(zài)設置狀态下(xià)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī) ;結束(shù)条(tiáo)件(jiàn)为(wèi) 10,表(biǎo)示最(zuì)大能(néng)設置为(wèi) 9,超过(guò)之後(hòu)便
清(qīng)零(líng)。
秒(miǎo)高(gāo)位計(jì)數器 sec_high:用(yòng)于(yú)对(duì)鬧鐘(zhōng)秒(miǎo)的(de)高(gāo)位進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi) sel_cnt==2-1 && set_en,
表(biǎo)示在(zài)設置狀态下(xià)可(kě)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī);結束(shù)条(tiáo)件(jiàn)为(wèi) 6,表(biǎo)示最(zuì)大能(néng)設置为(wèi) 5,超过(guò)之後(hòu)便
清(qīng)零(líng)。
分(fēn)低位計(jì)數器 min_low:用(yòng)于(yú)对(duì)鬧鐘(zhōng)分(fēn)的(de)低位進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi) sel_cnt==3-1 && set_en,
表(biǎo)示在(zài)設置狀态下(xià)可(kě)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī);結束(shù)条(tiáo)件(jiàn)为(wèi) 10,表(biǎo)示最(zuì)大能(néng)設置为(wèi) 9,超过(guò)之後(hòu)便
清(qīng)零(líng)。
分(fēn)高(gāo)位計(jì)數器 min_high:用(yòng)于(yú)对(duì)鬧鐘(zhōng)分(fēn)高(gāo)位進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi) sel_cnt==4-1 && set_en,
表(biǎo)示在(zài)設置狀态下(xià)可(kě)通(tòng)过(guò)按鍵 key3 来(lái)控制加一(yī);結束(shù)条(tiáo)件(jiàn)为(wèi) 6,表(biǎo)示最(zuì)大能(néng)設置为(wèi) 5,超过(guò)之後(hòu)便
清(qīng)零(líng)。
1.4.3 參考代(dài)碼
使用(yòng)明(míng)德揚的(de)計(jì)數器模板,可(kě)以(yǐ)很快(kuài)速很熟練地(dì)写出(chū)时(shí)間(jiān)産生(shēng)模块(kuài)。
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 數碼管(guǎn)顯示模块(kuài)設計(jì)
1.5.1 接口(kǒu)信(xìn)号(hào)

1.5.2 設計(jì)思(sī)路(lù)
在(zài)前(qián)面(miàn)的(de)案(àn)例中(zhōng)已經(jīng)有(yǒu)數碼管(guǎn)顯示的(de)介紹,所(suǒ)以(yǐ)这(zhè)里(lǐ)不(bù)在(zài)过(guò)多(duō)介紹,詳细(xì)介紹請看(kàn)下(xià)方(fāng)鍊(liàn)接:
http://fpgabbs.com/forum.php?mod=viewthread&tid=399
1.5.3 參考代(dài)碼
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 蜂鳴器模块(kuài)設計(jì)
1.6.1 接口(kǒu)信(xìn)号(hào)

1.6.2 設計(jì)思(sī)路(lù)
本(běn)模块(kuài)主(zhǔ)要(yào)通(tòng)过(guò)将顯示时(shí)間(jiān)與(yǔ)設置的(de)鬧鐘(zhōng)时(shí)間(jiān)進(jìn)行比較,如(rú)果(guǒ)相同(tóng)的(de)話(huà),就(jiù)控制 beep 拉低,持(chí)
續时(shí)間(jiān)为(wèi) 5 秒(miǎo)。由(yóu)此(cǐ)提(tí)出(chū)一(yī)个(gè)計(jì)數器的(de)架構,如(rú)下(xià)图(tú)所(suǒ)示。

該架構由(yóu)蜂鳴器控制信(xìn)号(hào) beep、秒(miǎo)計(jì)數器 miao 和(hé)鬧鐘(zhōng)觸發(fà)指示信(xìn)号(hào) flag_add 組成(chéng)。
秒(miǎo)計(jì)數器秒(miǎo):用(yòng)于(yú)对(duì) 5 秒(miǎo)的(de)时(shí)間(jiān)進(jìn)行計(jì)數,加一(yī)条(tiáo)件(jiàn)为(wèi) flag_add && end_counter,表(biǎo)示當鬧
鐘(zhōng)被(bèi)觸發(fà),并且經(jīng)过(guò) 1 秒(miǎo)的(de)时(shí)間(jiān)就(jiù)加一(yī);結束(shù)条(tiáo)件(jiàn)为(wèi) 5,表(biǎo)示數完 5 秒(miǎo)就(jiù)清(qīng)零(líng)。
鬧鐘(zhōng)觸發(fà)指示信(xìn)号(hào) flag:當其为(wèi)高(gāo)電(diàn)平时(shí)表(biǎo)示鬧鐘(zhōng)被(bèi)觸發(fà),低電(diàn)平表(biǎo)示沒(méi)有(yǒu)被(bèi)觸發(fà)。初始狀态为(wèi)
低電(diàn)平,從低變(biàn)高(gāo)的(de)条(tiáo)件(jiàn)为(wèi) sec_low==xs_sec_low&&sec_high==xs_sec_high&&min_low==xs_min
_low&&min_high==xs_min_high&&init&&!key1_func,表(biǎo)示當顯示时(shí)間(jiān)的(de)秒(miǎo)高(gāo)低位、分(fēn)高(gāo)低位和(hé)鬧鐘(zhōng)
設置的(de)秒(miǎo)高(gāo)低位、分(fēn)高(gāo)低位相等,同(tóng)时(shí)不(bù)处于(yú)刚上(shàng)電(diàn)的(de)初始狀态和(hé)設置狀态时(shí),鬧鐘(zhōng)被(bèi)觸發(fà);從高(gāo)變(biàn)
低的(de)条(tiáo)件(jiàn)为(wèi) end_miao,表(biǎo)示當 5 秒(miǎo)數完之後(hòu),就(jiù)拉低。
蜂鳴器控制信(xìn)号(hào) beep:當其为(wèi)低電(diàn)平时(shí),控制蜂鳴器響,为(wèi)高(gāo)電(diàn)平时(shí)不(bù)響。初始狀态为(wèi)高(gāo)電(diàn)平,
從高(gāo)變(biàn)低的(de)条(tiáo)件(jiàn)为(wèi) flag_add,表(biǎo)示計(jì)數器開(kāi)始計(jì)數之後(hòu)便将其拉低,當檢测到(dào) flag_add=0 的(de)时(shí)候,
便将其拉高(gāo)。
1.6.3 參考代(dài)碼
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 效果(guǒ)和(hé)總(zǒng)結
➢ 下(xià)图(tú)是(shì)該工程在(zài) mp801 開(kāi)發(fà)板上(shàng)的(de)現(xiàn)象(xiàng)
其中(zhōng)按鍵 s4 控制數字(zì)时(shí)鐘(zhōng)的(de)暫停與(yǔ)開(kāi)始,按鍵 s3 来(lái)選擇需要(yào)設置的(de)位,按鍵 s2 設置數值。左(zuǒ)
邊(biān)四(sì)个(gè)數碼管(guǎn)顯示的(de)是(shì)时(shí)鐘(zhōng)的(de)时(shí)間(jiān),右(yòu)邊(biān)四(sì)个(gè)數碼管(guǎn)顯示的(de)是(shì)鬧鐘(zhōng)設置的(de)时(shí)間(jiān)。

➢ 下(xià)图(tú)是(shì)該工程在(zài) db603 開(kāi)發(fà)板上(shàng)的(de)現(xiàn)象(xiàng)
其中(zhōng)按鍵 s1 控制數字(zì)时(shí)鐘(zhōng)的(de)暫停與(yǔ)開(kāi)始,按鍵 s2 来(lái)選擇需要(yào)設置的(de)位,按鍵 s3 設置數值。左(zuǒ)
邊(biān)四(sì)个(gè)數碼管(guǎn)顯示的(de)是(shì)时(shí)鐘(zhōng)的(de)时(shí)間(jiān),右(yòu)邊(biān)四(sì)个(gè)數碼管(guǎn)顯示的(de)是(shì)鬧鐘(zhōng)設置的(de)时(shí)間(jiān)。

➢ 下(xià)图(tú)是(shì)該工程在(zài) ms980 試验(yàn)箱上(shàng)的(de)現(xiàn)象(xiàng)
其中(zhōng)按鍵 s1 控制數字(zì)时(shí)鐘(zhōng)的(de)暫停與(yǔ)開(kāi)始,按鍵 s2 来(lái)選擇需要(yào)設置的(de)位,按鍵 s3 設置數值。左(zuǒ)
邊(biān)四(sì)个(gè)數碼管(guǎn)顯示的(de)是(shì)时(shí)鐘(zhōng)的(de)时(shí)間(jiān),右(yòu)邊(biān)四(sì)个(gè)數碼管(guǎn)顯示的(de)是(shì)鬧鐘(zhōng)設置的(de)时(shí)間(jiān)。

由(yóu)于(yú)該項目的(de)上(shàng)板現(xiàn)象(xiàng)是(shì)動(dòng)态的(de),開(kāi)始、暫停、时(shí)間(jiān)設置等現(xiàn)象(xiàng)无法通(tòng)过(guò)图(tú)片(piàn)表(biǎo)現(xiàn)出(chū)来(lái),想(xiǎng)观看(kàn)
完整現(xiàn)象(xiàng)的(de)朋友可(kě)以(yǐ)看(kàn)一(yī)下(xià)現(xiàn)象(xiàng)演示的(de)視頻。
温(wēn)馨提(tí)示:明(míng)德揚2023推出(chū)了(le)全(quán)新課程——邏輯設計(jì)基本(běn)功修煉課,降低学習FPGA門(mén)檻的(de)同(tóng)时(shí),增加了(le)学習的(de)趣味性(xìng),并組織了(le)考試赢積分(fēn)活動(dòng)
http://www.minyingyiyuan.com/ffkc/415.html
(點(diǎn)擊→了(le)解(jiě)課程詳情(qíng)☝)感(gǎn)興趣請聯系(xì)易老(lǎo)师(shī):13112063618(微信(xìn)同(tóng)步)