当前位置:   article > 正文

北邮22级信通院数电:Verilog-FPGA(11)第十一周实验(2)设计一个24秒倒计时器_24秒倒计时器程序

24秒倒计时器程序

北邮22信通一枚~

跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章

持续关注作者 迎接数电实验学习~

获取更多文章,请访问专栏:

北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客

目录

一.代码部分

1.1  counter_24.v

1.2  divide.v

1.3  debounce.v

二.管脚分配

三.实验效果


一.代码部分

1.1  counter_24.v

  1. module counter_24
  2. (
  3. input clk,rst,hold,
  4. output [8:0] seg_led_1,
  5. output [8:0] seg_led_2,
  6. output reg [7:0] led
  7. );
  8. wire clk_lh;
  9. wire hold_pulse;
  10. reg hold_flag;
  11. reg back_to_zero_flag;
  12. reg [6:0] seg [16:0];
  13. reg [3:0] cnt_ge;
  14. reg [3:0] cnt_shi;
  15. initial
  16. begin
  17. seg[0] = 7'h3f;
  18. seg[1] = 7'h06;
  19. seg[2] = 7'h5b;
  20. seg[3] = 7'h4f;
  21. seg[4] = 7'h66;
  22. seg[5] = 7'h6d;
  23. seg[6] = 7'h7d;
  24. seg[7] = 7'h07;
  25. seg[8] = 7'h7f;
  26. seg[9] = 7'h6f;
  27. seg[10] = 7'hf7;
  28. seg[11] = 7'h7c;
  29. seg[12] = 7'h39;
  30. seg[13] = 7'h5e;
  31. seg[14] = 7'h79;
  32. seg[15] = 7'h71;
  33. end
  34. debounce debounce_1
  35. (
  36. .clk(clk),
  37. .rst(rst),
  38. .key(hold),
  39. .key_pulse(hold_pulse)
  40. );
  41. divide # (.WIDTH(32),.N(12000000)) divide_1
  42. (
  43. .clk(clk),
  44. .rst_n(rst),
  45. .clkout(clk_lh)
  46. );
  47. always @ (posedge hold_pulse)
  48. if(!rst==1)
  49. hold_flag <= 0;
  50. else
  51. hold_flag <= ~hold_flag;
  52. always @ (*)
  53. if(!rst==1)
  54. back_to_zero_flag <= 0;
  55. else if( cnt_shi==0 && cnt_ge==0)
  56. back_to_zero_flag <= 1;
  57. else
  58. back_to_zero_flag <= 0;
  59. always @ (posedge clk_lh or negedge rst)
  60. begin
  61. if(!rst==1)
  62. begin
  63. cnt_ge <= 4'd4;
  64. cnt_shi <=4'd2;
  65. end
  66. else if(hold_flag==1)
  67. begin
  68. cnt_ge <= cnt_ge;
  69. cnt_shi <= cnt_shi;
  70. end
  71. else if(cnt_shi==0 && cnt_ge==0)
  72. begin
  73. cnt_shi <= cnt_shi;
  74. cnt_ge <=cnt_ge;
  75. end
  76. else if(cnt_ge==0)
  77. begin
  78. cnt_ge <=4'd9;
  79. cnt_shi <= cnt_shi-1;
  80. end
  81. else
  82. begin cnt_ge <= cnt_ge-1; end
  83. end
  84. //计时完成点亮led
  85. always @ (back_to_zero_flag)
  86. begin
  87. if(back_to_zero_flag == 1)
  88. led = 8'b0;
  89. else
  90. led = 8'b1111_1111;
  91. end
  92. assign seg_led_1[8:0] = {2'b00,seg[cnt_ge]};
  93. assign seg_led_2[8:0] = {2'b00,seg[cnt_shi]};
  94. endmodule

1.2  divide.v

  1. module divide ( clk,rst_n,clkout);
  2. input clk,rst_n; //输入信号,其中clk连接到FPGA的C1脚,频率为12MHz
  3. output clkout; //输出信号,可以连接到LED观察分频的时钟
  4. //parameter是verilog里常数语句
  5. parameter WIDTH = 3; //计数器的位数,计数的最大值为 2**WIDTH-1
  6. parameter N = 5; //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出
  7. reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
  8. reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟
  9. //上升沿触发时计数器的控制
  10. always @ (posedge clk or negedge rst_n ) //posedge和negedge是verilog表示信号上升沿和下降沿
  11. //当clk上升沿来临或者rst_n变低的时候执行一次always里的语句
  12. begin
  13. if(!rst_n)
  14. cnt_p<=0;
  15. else if (cnt_p==(N-1))
  16. cnt_p<=0;
  17. else cnt_p<=cnt_p+1; //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器
  18. end
  19. //上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
  20. always @ (posedge clk or negedge rst_n)
  21. begin
  22. if(!rst_n)
  23. clk_p<=0;
  24. else if (cnt_p<(N>>1)) //N>>1表示右移一位,相当于除以2去掉余数
  25. clk_p<=0;
  26. else
  27. clk_p<=1; //得到的分频时钟正周期比负周期多一个clk时钟
  28. end
  29. //下降沿触发时计数器的控制
  30. always @ (negedge clk or negedge rst_n)
  31. begin
  32. if(!rst_n)
  33. cnt_n<=0;
  34. else if (cnt_n==(N-1))
  35. cnt_n<=0;
  36. else cnt_n<=cnt_n+1;
  37. end
  38. //下降沿触发的分频时钟输出,和clk_p相差半个时钟
  39. always @ (negedge clk)
  40. begin
  41. if(!rst_n)
  42. clk_n<=0;
  43. else if (cnt_n<(N>>1))
  44. clk_n<=0;
  45. else
  46. clk_n<=1; //得到的分频时钟正周期比负周期多一个clk时钟
  47. end
  48. assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p; //条件判断表达式
  49. //当N=1时,直接输出clk
  50. //当N为偶数也就是N的最低位为0,N(0=0,输出clk_p
  51. //当N为奇数也就是N最低位为1,N(0=1,输出clk_p&clk_n。正周期多所以是相与
  52. endmodule

1.3  debounce.v

  1. module debounce (clk,rst,key,key_pulse);
  2. parameter N = 1; //要消除的按键的数量
  3. input clk;
  4. input rst;
  5. input [N-1:0] key; //输入的按键
  6. output [N-1:0] key_pulse; //按键动作产生的脉冲
  7. reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值
  8. reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值
  9. wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲
  10. //利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
  11. always @(posedge clk or negedge rst)
  12. begin
  13. if (!rst) begin
  14. key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1,{}中表示N个1
  15. key_rst_pre <= {N{1'b1}};
  16. end
  17. else begin
  18. key_rst <= key; //第一个时钟上升沿触发之后key的值赋给key_rst,
  19. //同时key_rst的值赋给key_rst_pre
  20. key_rst_pre <= key_rst; //非阻塞赋值。
  21. //相当于经过两个时钟触发,
  22. //key_rst存储的是当前时刻key的值,
  23. //key_rst_pre存储的是前一个时钟的key的值
  24. end
  25. end
  26. assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。
  27. //key检测到下降沿时,
  28. //key_edge产生一个时钟周期的高电平
  29. reg [17:0] cnt; //产生延时所用的计数器,系统时钟12MHz,
  30. //要延时20ms左右时间,至少需要18位计数器
  31. //产生20ms延时,当检测到key_edge有效是计数器清零开始计数
  32. always @(posedge clk or negedge rst)
  33. begin
  34. if(!rst)
  35. cnt <= 18'h0;
  36. else if(key_edge)
  37. cnt <= 18'h0;
  38. else
  39. cnt <= cnt + 1'h1;
  40. end
  41. reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量
  42. reg [N-1:0] key_sec;
  43. //延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
  44. always @(posedge clk or negedge rst)
  45. begin
  46. if (!rst)
  47. key_sec <= {N{1'b1}};
  48. else if (cnt==18'h3ffff)
  49. key_sec <= key;
  50. end
  51. always @(posedge clk or negedge rst)
  52. begin
  53. if (!rst)
  54. key_sec_pre <= {N{1'b1}};
  55. else
  56. key_sec_pre <= key_sec;
  57. end
  58. assign key_pulse = key_sec_pre & (~key_sec);
  59. endmodule

二.管脚分配

三.实验效果

数码管显示24秒倒计时,倒计时结束后所有LED灯亮起。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/796599
推荐阅读
相关标签
  

闽ICP备14008679号