当前位置:   article > 正文

基于FPGA的数字时钟的设计课设(HUAT)_fpga数字时钟课程设计

fpga数字时钟课程设计

 

 


前言

学校黄老师的FPGA的设计课设,最后的课设为数字时钟,实现分时的计数功能,带有整点报时,按键调节的功能,供电子类学生学习和参考。

 


 

一、数字时钟课设目标

l 基本要求

1、能进行正常的时、分、秒计时功能,分别由6个数码管显示24小时、60分钟、60秒钟的计数器显示。

2、能利用实验系统上的按键实现“校时”“校分”功能:

⑴按下“SA”键时,计时器迅速递增,并按24小时循环,计满23小时后回“00”

⑵按下“SB”键时,计分器迅速递增,并按59分钟循环,计满59分钟后回“00”,但不向“时”进位;

⑷要求按下“SA”、“SB”或“SC”时均不产生数字跳变(SA”、“SB”、“SC”按键是有抖动的,必须对其消除抖动处理)。

3、能利用扬声器做整点报时:

⑴当计时到达5950秒时开始报时,在5950秒、52秒、54秒、56秒、58秒鸣叫,鸣叫声频率可定为512Hz

⑵到达5960秒时为最后一声整点报时,整点报时频率可定为1024Hz

4、用层次化设计方法设计该电路,用Verilog语言编写各个功能模块。

5、完成电路设计后,用实验系统下载验证。

l 发挥部分

   要求实现闹铃功能,准确到分钟。用功能仿真的方法验证,可通过观察有关波形确认电路设计是否正确。

二、部分代码

1.clock.v代码的编写

     秒计数器
 

  1. reg [25:0] cnt2;
  2. wire add_cnt2;
  3. wire end_cnt2;
  4. always@(posedge clk or negedge rst_n)begin //1s计数,可以通过按键更改
  5. if(rst_n == 0)
  6. cnt2 <= 0;
  7. else if (add_cnt2)begin
  8. if(end_cnt2)
  9. cnt2 <= 0;
  10. else
  11. cnt2 <= cnt2 +1;
  12. end
  13. end
  14. assign add_cnt2 = 1;
  15. assign end_cnt2 = add_cnt2 && cnt2 == y-1;//y可以通过按键更改,实现按键调节时钟频率

us计数器
 

  1. reg [8:0] cnt0;
  2. always@(posedge clk or negedge rst_n) //数码管显示
  3. if(rst_n == 0)
  4. cnt0 <= 0;
  5. else if (add_cnt0)
  6. begin
  7. if(end_cnt0 )
  8. cnt0 <= 0;
  9. else
  10. cnt0 <= cnt0 +1;
  11. end
  12. assign add_cnt0 = 1;
  13. assign end_cnt0 = add_cnt0 && cnt0== TIME_1US-1;//通过短时间的数码管显示,实现动态扫描

数码管显示   对4个数码管进行us级的循环点亮,达到视觉上的暂留
 

  1. reg [2:0] cnt1;
  2. wire add_cnt1;
  3. wire end_cnt1;
  4. always@(posedge clk or negedge rst_n)begin //4个数码管
  5. if(rst_n == 0)
  6. cnt1 <= 0;
  7. else if (add_cnt1)begin
  8. if(end_cnt1)
  9. cnt1 <= 0;
  10. else
  11. cnt1 <= cnt1 +1;
  12. end
  13. end
  14. assign add_cnt1 = end_cnt0;
  15. assign end_cnt1 = add_cnt1 && cnt1 == 4-1;

数码管动态扫描

  1. always@(posedge clk or negedge rst_n) //动态扫描
  2. begin
  3. if(rst_n == 1'b0)
  4. seg_sel <= 4'b111_1;
  5. else if (cnt1 == 0)
  6. seg_sel <= 4'b111_0;
  7. else if (cnt1 == 1)
  8. seg_sel <= 4'b110_1;
  9. else if (cnt1 == 2)
  10. seg_sel <= 4'b101_1;
  11. else if (cnt1 == 3)
  12. seg_sel <= 4'b011_1;
  13. else
  14. seg_sel <= 4'b111_1;
  15. end

数码管选择显示
 

  1. reg [3:0] sel_data;
  2. always@(posedge clk or negedge rst_n) // 选择显示
  3. begin
  4. if(rst_n == 0)
  5. seg_ment <=8'hc0;
  6. else if (sel_data==0)
  7. seg_ment <= 8'hc0;
  8. else if (sel_data==1)
  9. seg_ment <= 8'hf9;
  10. else if (sel_data==2)
  11. seg_ment <= 8'ha4;
  12. else if (sel_data==3)
  13. seg_ment <= 8'hb0;
  14. else if (sel_data==4)
  15. seg_ment <= 8'h99;
  16. else if (sel_data==5)
  17. seg_ment <= 8'h92;
  18. else if (sel_data==6)
  19. seg_ment <= 8'h82;
  20. else if (sel_data==7)
  21. seg_ment <= 8'hf8;
  22. else if (sel_data==8)
  23. seg_ment <= 8'h80;
  24. else if (sel_data==9)
  25. seg_ment <= 8'h90;
  26. else
  27. seg_ment <= 8'hc0;
  28. end
  29. always@(*)
  30. begin
  31. if (cnt1==0)
  32. sel_data <= m_g;
  33. else if (cnt1==1)
  34. sel_data <= m_s;
  35. else if (cnt1==2)
  36. sel_data <= s_g;
  37. else
  38. sel_data <= s_s;
  39. end

 

分个位 分十位 时个位 时十位
 

  1. reg [3:0] m_g;
  2. wire add_m_g;
  3. wire end_m_g;
  4. always@(posedge clk or negedge rst_n)begin
  5. if(rst_n == 0)
  6. m_g <= 0;
  7. else if (add_m_g)
  8. begin
  9. if(end_m_g)
  10. m_g <= 0;
  11. else
  12. m_g <= m_g +1;
  13. end
  14. else
  15. m_g <= m_g;
  16. end
  17. assign add_m_g = end_cnt2;
  18. assign end_m_g = add_m_g && m_g == 10-1;
  19. reg [2:0] m_s;
  20. wire add_m_s;
  21. wire end_m_s;
  22. always@(posedge clk or negedge rst_n)begin
  23. if(rst_n == 0)
  24. m_s <= 0;
  25. else if (add_m_s)begin
  26. if(end_m_s)
  27. m_s <= 0;
  28. else
  29. m_s <= m_s +1;
  30. end
  31. end
  32. assign add_m_s = end_m_g;
  33. assign end_m_s = add_m_s && m_s == 6-1;
  34. reg [3:0] s_g;
  35. wire add_s_g;
  36. wire end_s_g;
  37. always@(posedge clk or negedge rst_n)begin
  38. if(rst_n == 0)
  39. s_g <= 0;
  40. else if (add_s_g)
  41. begin
  42. if(end_s_g)
  43. s_g <= 0;
  44. else if (key_in1 == 1'b0)//保证按键按下时位不产生变化
  45. s_g <= s_g ;
  46. else
  47. s_g <= s_g +1;
  48. end
  49. else
  50. s_g <= s_g;
  51. end
  52. assign add_s_g = end_m_s;
  53. assign end_s_g = add_s_g && s_g == x-1;
  54. reg [1:0] s_s;
  55. wire add_s_s;
  56. wire end_s_s;
  57. always@(posedge clk or negedge rst_n)begin
  58. if(rst_n == 0)
  59. s_s <= 0;
  60. else if (add_s_s)begin
  61. if(end_s_s)
  62. s_s <= 0;
  63. else
  64. s_s <= s_s +1;
  65. end
  66. end
  67. assign add_s_s = end_s_g;
  68. assign end_s_s = add_s_s && s_s == 3-1;
  69. always@(*)
  70. begin
  71. if(s_s==2)
  72. x=4;
  73. else
  74. x=10;
  75. end

上述基本可以达到数码管显示计数的效果

//按键更改频率
 

  1. parameter TIME_1S = 5000_000_0;
  2. parameter TIME_1MS = 5000_000;
  3. parameter TIME_1NS = 5000_00;
  4. always@(posedge clk or negedge rst_n)
  5. if(rst_n == 1'b0)
  6. y <= TIME_1S;
  7. else if ( key_in1 == 1'b0) //按键1改时钟频率,同时s_g数码管不变
  8. begin
  9. y=TIME_1MS;
  10. end
  11. else if (key_in2 == 1'b0)//按键2 改时钟频率,改的更快
  12. y=TIME_1NS;
  13. else
  14. begin
  15. y <= TIME_1S;
  16. end

 

beep报时
 

  1. //beep 计数
  2. reg [24:0] cnt;
  3. reg [2:0] cnt_500ms;
  4. reg [17:0] freq_cnt;
  5. reg [17:0] freq_data;
  6. reg [17:0] freq_data2;
  7. wire [16:0] duty_data1;
  8. wire [16:0] duty_data2;
  9. // beep 0.5s的计数
  10. always@(posedge clk or negedge rst_n)
  11. if(rst_n == 1'b0)
  12. cnt <= 25'd0;
  13. else if (cnt == CNT_MAX)
  14. cnt <= 25'd0;
  15. else
  16. cnt <= cnt + 25'b1;
  17. always@(posedge clk or negedge rst_n)
  18. if(rst_n == 1'b0)
  19. cnt_500ms <= 3'd0;
  20. else if ((cnt_500ms == 3'd6)&&(cnt == CNT_MAX))
  21. cnt_500ms <= 3'd0;
  22. else if (cnt == CNT_MAX)
  23. cnt_500ms <= cnt_500ms + 3'd1;
  24. else
  25. cnt_500ms <= cnt_500ms;
  26. //频率计数
  27. always@(posedge clk or negedge rst_n)
  28. if(rst_n == 1'b0)
  29. freq_cnt <= 18'd0;
  30. else if ((freq_cnt == freq_data)||(cnt == CNT_MAX))
  31. freq_cnt <= 18'd0;
  32. else
  33. freq_cnt <= freq_cnt + 18'd1;
  34. always@(posedge clk or negedge rst_n)
  35. if(rst_n == 1'b0)
  36. freq_data <= DO;
  37. else case(cnt_500ms)
  38. 3'd0:
  39. begin
  40. freq_data <= DO;
  41. freq_data2<= XI;
  42. end
  43. default :
  44. begin
  45. freq_data <= DO;
  46. freq_data2<= XI;
  47. end
  48. endcase
  49. assign duty_data1 = freq_data >> 1;
  50. assign duty_data2 = freq_data2 >> 1;
  51. //报时
  52. always@(posedge clk or negedge rst_n)
  53. if(rst_n == 1'b0)
  54. beep <= 1'b0;
  55. else if ((freq_cnt >= duty_data1)&&(((m_s == 5)&&(m_g== 2))||((m_s == 5)&&
  56. (m_g ==0))||((m_s == 5)&&(m_g ==4))||((m_s == 5)&&(m_g ==6))||((m_s == 5)&&(m_g ==8))))// 50 52 54 56 58 报时
  57. beep <= 1'b1;
  58. else if ((freq_cnt >= duty_data2)&&(((m_s == 0)&&(m_g== 0))))// 正点报时
  59. beep <= 1'b1;
  60. else
  61. beep <= 1'b0;

 

 

2.完整代码

  1. module clock_k_b
  2. (
  3. input clk,
  4. input rst_n,
  5. input wire key_in1,
  6. input wire key_in2,
  7. output reg [3:0] seg_sel,
  8. output reg [7:0] seg_ment,
  9. output reg beep
  10. );
  11. parameter TIME_1US = 500;
  12. parameter TIME_1S = 5000_000_0;
  13. parameter TIME_1MS = 5000_000;
  14. parameter TIME_1NS = 5000_00;
  15. parameter CNT_MAX =25'd24_999_999;
  16. parameter DO = 18'd190839;
  17. parameter XI = 18'd101213;
  18. //
  19. reg [25:0] y;
  20. reg [8:0] cnt0;
  21. reg [3:0] x;
  22. wire add_cnt0;
  23. wire end_cnt0;
  24. //beep 计数
  25. reg [24:0] cnt;
  26. reg [2:0] cnt_500ms;
  27. reg [17:0] freq_cnt;
  28. reg [17:0] freq_data;
  29. reg [17:0] freq_data2;
  30. wire [16:0] duty_data1;
  31. wire [16:0] duty_data2;
  32. // beep 0.5s的计数
  33. always@(posedge clk or negedge rst_n)
  34. if(rst_n == 1'b0)
  35. cnt <= 25'd0;
  36. else if (cnt == CNT_MAX)
  37. cnt <= 25'd0;
  38. else
  39. cnt <= cnt + 25'b1;
  40. always@(posedge clk or negedge rst_n)
  41. if(rst_n == 1'b0)
  42. cnt_500ms <= 3'd0;
  43. else if ((cnt_500ms == 3'd6)&&(cnt == CNT_MAX))
  44. cnt_500ms <= 3'd0;
  45. else if (cnt == CNT_MAX)
  46. cnt_500ms <= cnt_500ms + 3'd1;
  47. else
  48. cnt_500ms <= cnt_500ms;
  49. //频率计数
  50. always@(posedge clk or negedge rst_n)
  51. if(rst_n == 1'b0)
  52. freq_cnt <= 18'd0;
  53. else if ((freq_cnt == freq_data)||(cnt == CNT_MAX))
  54. freq_cnt <= 18'd0;
  55. else
  56. freq_cnt <= freq_cnt + 18'd1;
  57. always@(posedge clk or negedge rst_n)
  58. if(rst_n == 1'b0)
  59. freq_data <= DO;
  60. else case(cnt_500ms)
  61. 3'd0:
  62. begin
  63. freq_data <= DO;
  64. freq_data2<= XI;
  65. end
  66. default :
  67. begin
  68. freq_data <= DO;
  69. freq_data2<= XI;
  70. end
  71. endcase
  72. assign duty_data1 = freq_data >> 1;
  73. assign duty_data2 = freq_data2 >> 1;
  74. //报时
  75. always@(posedge clk or negedge rst_n)
  76. if(rst_n == 1'b0)
  77. beep <= 1'b0;
  78. else if ((freq_cnt >= duty_data1)&&(((m_s == 5)&&(m_g== 2))||((m_s == 5)&&
  79. (m_g ==0))||((m_s == 5)&&(m_g ==4))||((m_s == 5)&&(m_g ==6))||((m_s == 5)&&(m_g ==8))))// 50 52 54 56 58 报时
  80. beep <= 1'b1;
  81. else if ((freq_cnt >= duty_data2)&&(((m_s == 0)&&(m_g== 0))))// 正点报时
  82. beep <= 1'b1;
  83. else
  84. beep <= 1'b0;
  85. always@(posedge clk or negedge rst_n)
  86. if(rst_n == 1'b0)
  87. y <= TIME_1S;
  88. else if ( key_in1 == 1'b0) //按键1改时钟频率,同时s_g数码管不变
  89. begin
  90. y=TIME_1MS;
  91. end
  92. else if (key_in2 == 1'b0)//按键2 改时钟频率,改的更快
  93. y=TIME_1NS;
  94. else
  95. begin
  96. y <= TIME_1S;
  97. end
  98. /* always@(posedge clk or negedge rst_n)
  99. if(rst_n == 1'b0)
  100. begin
  101. //beep <= 1'b0;
  102. led <= 1'b1;
  103. end
  104. else if (m_s>= 5)
  105. begin
  106. //beep <= 1'b1;
  107. led <= ~led;
  108. end
  109. else
  110. begin
  111. //beep <= 1'b0;
  112. led <= led;
  113. end */
  114. always@(posedge clk or negedge rst_n) //数码管显示
  115. if(rst_n == 0)
  116. cnt0 <= 0;
  117. else if (add_cnt0)
  118. begin
  119. if(end_cnt0 )
  120. cnt0 <= 0;
  121. else
  122. cnt0 <= cnt0 +1;
  123. end
  124. assign add_cnt0 = 1;
  125. assign end_cnt0 = add_cnt0 && cnt0== TIME_1US-1;
  126. reg [2:0] cnt1;
  127. wire add_cnt1;
  128. wire end_cnt1;
  129. always@(posedge clk or negedge rst_n)begin //4个数码管
  130. if(rst_n == 0)
  131. cnt1 <= 0;
  132. else if (add_cnt1)begin
  133. if(end_cnt1)
  134. cnt1 <= 0;
  135. else
  136. cnt1 <= cnt1 +1;
  137. end
  138. end
  139. assign add_cnt1 = end_cnt0;
  140. assign end_cnt1 = add_cnt1 && cnt1 == 4-1;
  141. reg [25:0] cnt2;
  142. wire add_cnt2;
  143. wire end_cnt2;
  144. always@(posedge clk or negedge rst_n)begin //1s计数,可以通过按键更改
  145. if(rst_n == 0)
  146. cnt2 <= 0;
  147. else if (add_cnt2)begin
  148. if(end_cnt2)
  149. cnt2 <= 0;
  150. else
  151. cnt2 <= cnt2 +1;
  152. end
  153. end
  154. assign add_cnt2 = 1;
  155. assign end_cnt2 = add_cnt2 && cnt2 == y-1;
  156. reg [3:0] sel_data;
  157. always@(posedge clk or negedge rst_n) // 选择显示
  158. begin
  159. if(rst_n == 0)
  160. seg_ment <=8'hc0;
  161. else if (sel_data==0)
  162. seg_ment <= 8'hc0;
  163. else if (sel_data==1)
  164. seg_ment <= 8'hf9;
  165. else if (sel_data==2)
  166. seg_ment <= 8'ha4;
  167. else if (sel_data==3)
  168. seg_ment <= 8'hb0;
  169. else if (sel_data==4)
  170. seg_ment <= 8'h99;
  171. else if (sel_data==5)
  172. seg_ment <= 8'h92;
  173. else if (sel_data==6)
  174. seg_ment <= 8'h82;
  175. else if (sel_data==7)
  176. seg_ment <= 8'hf8;
  177. else if (sel_data==8)
  178. seg_ment <= 8'h80;
  179. else if (sel_data==9)
  180. seg_ment <= 8'h90;
  181. else
  182. seg_ment <= 8'hc0;
  183. end
  184. always@(posedge clk or negedge rst_n) //动态扫描
  185. begin
  186. if(rst_n == 1'b0)
  187. seg_sel <= 4'b111_1;
  188. else if (cnt1 == 0)
  189. seg_sel <= 4'b111_0;
  190. else if (cnt1 == 1)
  191. seg_sel <= 4'b110_1;
  192. else if (cnt1 == 2)
  193. seg_sel <= 4'b101_1;
  194. else if (cnt1 == 3)
  195. seg_sel <= 4'b011_1;
  196. else
  197. seg_sel <= 4'b111_1;
  198. end
  199. reg [3:0] m_g;
  200. wire add_m_g;
  201. wire end_m_g;
  202. always@(posedge clk or negedge rst_n)begin
  203. if(rst_n == 0)
  204. m_g <= 0;
  205. else if (add_m_g)
  206. begin
  207. if(end_m_g)
  208. m_g <= 0;
  209. else
  210. m_g <= m_g +1;
  211. end
  212. else
  213. m_g <= m_g;
  214. end
  215. assign add_m_g = end_cnt2;
  216. assign end_m_g = add_m_g && m_g == 10-1;
  217. reg [2:0] m_s;
  218. wire add_m_s;
  219. wire end_m_s;
  220. always@(posedge clk or negedge rst_n)begin
  221. if(rst_n == 0)
  222. m_s <= 0;
  223. else if (add_m_s)begin
  224. if(end_m_s)
  225. m_s <= 0;
  226. else
  227. m_s <= m_s +1;
  228. end
  229. end
  230. assign add_m_s = end_m_g;
  231. assign end_m_s = add_m_s && m_s == 6-1;
  232. reg [3:0] s_g;
  233. wire add_s_g;
  234. wire end_s_g;
  235. always@(posedge clk or negedge rst_n)begin
  236. if(rst_n == 0)
  237. s_g <= 0;
  238. else if (add_s_g)
  239. begin
  240. if(end_s_g)
  241. s_g <= 0;
  242. else if (key_in1 == 1'b0)
  243. s_g <= s_g ;
  244. else
  245. s_g <= s_g +1;
  246. end
  247. else
  248. s_g <= s_g;
  249. end
  250. assign add_s_g = end_m_s;
  251. assign end_s_g = add_s_g && s_g == x-1;
  252. reg [1:0] s_s;
  253. wire add_s_s;
  254. wire end_s_s;
  255. always@(posedge clk or negedge rst_n)begin
  256. if(rst_n == 0)
  257. s_s <= 0;
  258. else if (add_s_s)begin
  259. if(end_s_s)
  260. s_s <= 0;
  261. else
  262. s_s <= s_s +1;
  263. end
  264. end
  265. assign add_s_s = end_s_g;
  266. assign end_s_s = add_s_s && s_s == 3-1;
  267. always@(*)
  268. begin
  269. if(s_s==2)
  270. x=4;
  271. else
  272. x=10;
  273. end
  274. /* always@(posedge clk or negedge rst_n)
  275. begin
  276. if(rst_n == 1'b0)
  277. sel_data <= 0;
  278. else if (cnt1==0)
  279. sel_data <= m_g;
  280. else if (cnt1==1)
  281. sel_data <= m_s;
  282. else if (cnt1==2)
  283. sel_data <= s_g;
  284. else if (cnt1==3)
  285. sel_data <= s_s;
  286. end */
  287. always@(*)
  288. begin
  289. if (cnt1==0)
  290. sel_data <= m_g;
  291. else if (cnt1==1)
  292. sel_data <= m_s;
  293. else if (cnt1==2)
  294. sel_data <= s_g;
  295. else
  296. sel_data <= s_s;
  297. end
  298. endmodule

3.仿真代码

  1. `timescale 1ns/1ns
  2. module tb_clock();
  3. parameter CYCLE = 20;
  4. reg clk;
  5. reg rst_n;
  6. wire [3:0] seg_sel;
  7. wire [6:0] seg_ment;
  8. clock
  9. #(
  10. .TIME_1US (100),
  11. .TIME_1S (10)
  12. )
  13. clock_inst
  14. (
  15. .clk (clk),
  16. .rst_n (rst_n),
  17. .seg_sel (seg_sel),
  18. .seg_ment (seg_ment)
  19. );
  20. initial
  21. begin
  22. clk = 0;
  23. forever#(CYCLE/2)begin
  24. clk=~clk;
  25. end
  26. end
  27. initial
  28. begin
  29. #1
  30. rst_n = 0;
  31. #(10*CYCLE);
  32. rst_n = 1;
  33. end
  34. endmodule

总结

这是暑假自学搞得数字时钟的设计,虽然功能齐全,但是难免有点不完美的地方,也可以通过层次化的设计让代码变得没有这么长,可以通过这一份代码,要是期末课设弄不出来,参考一下也是可以的,免得挂了,功能反正都可以实现。若有更好的点子也可以一起交流学习一下。

 


 

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号