当前位置:   article > 正文

小梅哥Xilinx FPGA学习笔记8——从计数器到可控线性序列机_小梅哥笔记

小梅哥笔记

目录

一、功能介绍

二、任务1的代码编写

1.设计文件

2.激励文件

3.仿真图

三、任务2的代码编写

实现思路一:

1.设计文件

2.激励文件

3.仿真图

实现思路二:

1.设计文件

2.激励文件

3.仿真图

四、任务3的代码编写

1.设计文件

2.激励文件

3.仿真图

五、任务4的代码编写

1.设计文件

2.激励文件

3.仿真图​编辑

六、总结


一、功能介绍

任务1:LED灯按照亮0.25秒,灭0.75秒的状态循环亮灭

任务2:让LED灯按照亮0.25秒,灭0.5秒,亮0.75秒,灭1秒的状态循环亮灭

任务3:以0.25为基本的LED状态变化间隔(最小时间单元)以8小段·为一个循环周期(参考任务二10个小段);LED在每一小段该点亮还是该熄灭由8个输入端口决定。

任务4:在任务三的基础上,实现每隔一定时间,比如1秒钟,执行一轮LED8个状态的切换控制。

二、任务1的代码编写

实现思路:计数器相当于一个刻度时间尺,在一秒的时间内,首先led应该是高电平,即计数器开始计数时LED电平就是高电平,然后当计数器计到0.25s后,LED就变成低电平了,什么时候又变成高电平呢?当然是1秒结束后,也就是计数器重新从0计数时LED变为高电平,此时第一个1秒循环结束,开始下一循环。

1.设计文件

  1. //功能实现led亮0.25s,灭0.75s
  2. module LED_ctrl0(
  3. input Clk,
  4. input Reset_n,
  5. output reg Led
  6. );
  7. reg [25:0]counter;//定义计数器位数,板上时钟资源是20ns为一个周期,所以要用计时数除以20ns来计算计时次数。最后将次数转化成二进制位,有几位就定义几位计时器
  8. //计数器计数
  9. always@(posedge Clk or negedge Reset_n)
  10. if(!Reset_n)//可见Reset_n复位是低电平有效
  11. counter <= 0;
  12. else if(counter == 50_000_000-1)
  13. counter <= 0;
  14. else
  15. counter <= counter + 1'd1;
  16. always@(posedge Clk or negedge Reset_n)
  17. if(!Reset_n)//可见Reset_n复位是低电平有效
  18. Led <= 0;
  19. else if(counter == 0)
  20. Led <= 1;
  21. else if(counter == 12_500_000-1)
  22. Led <= !Led;
  23. else
  24. Led <= Led;
  25. endmodule

2.激励文件

  1. `timescale 1ns / 1ns
  2. module LED_ctrl0_tb();
  3. reg Clk;
  4. reg Reset_n;
  5. wire Led;
  6. LED_ctrl0 LED_ctrl0(
  7. .Clk(Clk),
  8. .Reset_n(Reset_n),
  9. .Led(Led)
  10. );
  11. initial Clk = 1;//初始信号为高电平
  12. always #10 Clk = ~Clk;//延时10ns以后初始信号取反,这句话是总是执行的。
  13. //产生激励复位信号
  14. initial begin
  15. Reset_n = 0;//开始复位信号为0,有效复位
  16. #201 Reset_n = 1;//201ns以后复位信号变为高电平,无效电平。开始仿真
  17. #2000000000;//两秒仿真
  18. $stop;//停止仿真
  19. end
  20. endmodule

3.仿真图

三、任务2的代码编写

实现思路一:

计数器相当于一个刻度时间尺,在2.5s的时间内,首先led应该是高电平,保持0.25s,然后是低电平并保持0.5s,然后是高电平保持0.75s,最后是低电平保持1s。即计数器开始计数时LED电平就是高电平,然后当计数器计到0.25s后,LED就变成低电平了,什么时候又变成高电平呢?当然是0.75s秒后,那什么时候又变成低电平呢?当然是1.5s后啦,最后就是2s也就是计数器变为0时led重新拉高,一个循环结束。

1.设计文件

  1. //功能实现led亮0.25s,灭0.5s,亮0.75s,灭1s
  2. module LED_ctrl1(
  3. input Clk,
  4. input Reset_n,
  5. output reg Led
  6. );
  7. parameter MCNT = 1000;
  8. reg [26:0]counter;//定义计数器位数,板上时钟资源是20ns为一个周期,所以要用计时数除以20ns来计算计时次数。最后将次数转化成二进制位,有几位就定义几位计时器
  9. //计数器计数
  10. always@(posedge Clk or negedge Reset_n)
  11. if(!Reset_n)//可见Reset_n复位是低电平有效
  12. counter <= 0;
  13. else if(counter == 125_000*MCNT -1)
  14. counter <= 0;
  15. else
  16. counter <= counter + 1'd1;
  17. always@(posedge Clk or negedge Reset_n)
  18. if(!Reset_n)//可见Reset_n复位是低电平有效
  19. Led <= 0;
  20. else if(counter == 0)
  21. Led <= 1;
  22. else if(counter == 12_500*MCNT)
  23. Led <= !Led;
  24. else if(counter == 37_500*MCNT)
  25. Led <= !Led;
  26. else if(counter == 75_000*MCNT)
  27. Led <= !Led;
  28. else
  29. Led <= Led;
  30. endmodule

2.激励文件

  1. `timescale 1ns / 1ns
  2. module LED_ctrl0_tb();
  3. reg Clk;
  4. reg Reset_n;
  5. wire Led;
  6. LED_ctrl1 LED_ctrl3_inst0(
  7. .Clk(Clk),
  8. .Reset_n(Reset_n),
  9. .Led(Led)
  10. );
  11. defparam LED_ctrl3_inst0.MCNT = 1;
  12. initial Clk = 1;//初始信号为高电平
  13. always #10 Clk = ~Clk;//延时10ns以后初始信号取反,这句话是总是执行的。
  14. //产生激励复位信号
  15. initial begin
  16. Reset_n = 0;//开始复位信号为0,有效复位
  17. #201 Reset_n = 1;//201ns以后复位信号变为高电平,无效电平。开始仿真
  18. #2000000;//两毫秒仿真
  19. #2000000;//两毫秒仿真
  20. $stop;//停止仿真
  21. end
  22. endmodule

3.仿真图

实现思路二:

可以将2.5S等分为10份,每一份做不同的事情。此时使用两个计数器来实现,其中一个计数器用来计时0.25S另外一个计时器用来计算计数器1计满0.25S的次数。这样就可以在不同的时刻做不同的事情了。框图如下图所示,有助于理解。

1.设计文件

  1. //功能实现led亮0.25s,灭0.5s,亮0.75s,灭1s
  2. module LED_ctrl2(
  3. input Clk,
  4. input Reset_n,
  5. output reg Led
  6. );
  7. reg [23:0]counter0;//定义计数器位数,板上时钟资源是20ns为一个周期,所以要用计时数除以20ns来计算计时次数。最后将次数转化成二进制位,有几位就定义几位计时器
  8. reg [3:0]counter1;
  9. parameter MCNT = 1000;
  10. //计数器计数
  11. always@(posedge Clk or negedge Reset_n)
  12. if(!Reset_n)//可见Reset_n复位是低电平有效
  13. counter0 <= 0;
  14. else if(counter0 == 12_500*MCNT -1)
  15. counter0 <= 0;
  16. else
  17. counter0 <= counter0 + 1'd1;
  18. always@(posedge Clk or negedge Reset_n)
  19. if(!Reset_n)//可见Reset_n复位是低电平有效
  20. counter1 <= 0;
  21. else if(counter0 == 12_500*MCNT-1)
  22. begin
  23. if(counter1 == 9)
  24. counter1 <= 0;
  25. else
  26. counter1 <= counter1+1'd1;
  27. end
  28. else
  29. counter1 <= counter1;
  30. //使用if else语句实现
  31. // always@(posedge Clk or negedge Reset_n)
  32. // if(!Reset_n)//可见Reset_n复位是低电平有效
  33. // Led <= 0;
  34. // else if(counter1 == 0)
  35. // Led <= 1;
  36. // else if(counter1 == 1||counter1 == 2)
  37. // Led <= 0;
  38. // else if(counter1 == 3||counter1 == 4||counter1 == 5)
  39. // Led <= 1;
  40. // else if(counter1 == 6||counter1 == 7||counter1 == 8||counter1 == 9)
  41. // Led <= 0;
  42. // else
  43. // Led <= Led;
  44. //使用case语句实现
  45. always@(posedge Clk or negedge Reset_n)
  46. if(!Reset_n)//可见Reset_n复位是低电平有效
  47. Led <= 0;
  48. else begin
  49. case(counter1)
  50. 0:Led <= 1;
  51. 1:Led <= 0;
  52. 2:Led <= 0;
  53. 3:Led <= 1;
  54. 4:Led <= 1;
  55. 5:Led <= 1;
  56. 6:Led <= 0;
  57. 7:Led <= 0;
  58. 8:Led <= 0;
  59. 9:Led <= 0;
  60. default:Led <= Led ;
  61. endcase
  62. end
  63. endmodule

2.激励文件

同实现思路一

3.仿真图

同实现思路一

四、任务3的代码编写

实现思路二:可以将2S等分为8份,每一份做不同的事情。此时使用两个计数器来实现,其中一个计数器用来计时0.25S另外一个计时器用来计算计数器1计满0.25S的次数。这样就可以在不同的时刻做不同的事情了。

1.设计文件

  1. //功能实现led亮0.25s,灭0.5s,亮0.75s,灭1s
  2. module LED_ctrl3(
  3. input Clk,
  4. input Reset_n,
  5. input [7:0]SW,
  6. output reg Led
  7. );
  8. reg [23:0]counter0;//定义计数器位数,板上时钟资源是20ns为一个周期,所以要用计时数除以20ns来计算计时次数。最后将次数转化成二进制位,有几位就定义几位计时器
  9. reg [2:0]counter1;
  10. parameter MCNT = 12500000-1;
  11. //计数器计数
  12. always@(posedge Clk or negedge Reset_n)
  13. if(!Reset_n)//可见Reset_n复位是低电平有效
  14. counter0 <= 0;
  15. else if(counter0 == MCNT)
  16. counter0 <= 0;
  17. else
  18. counter0 <= counter0 + 1'd1;
  19. //8个数计数计到7自动清零。
  20. always@(posedge Clk or negedge Reset_n)
  21. if(!Reset_n)//可见Reset_n复位是低电平有效
  22. counter1 <= 0;
  23. else if(counter0 == MCNT)
  24. counter1 <= counter1+1;
  25. else
  26. counter1 <= counter1;
  27. //使用case语句实现
  28. always@(posedge Clk or negedge Reset_n)
  29. if(!Reset_n)//可见Reset_n复位是低电平有效
  30. Led <= 0;
  31. else begin
  32. case(counter1)
  33. 0:Led <= SW[0];
  34. 1:Led <= SW[1];
  35. 2:Led <= SW[2];
  36. 3:Led <= SW[3];
  37. 4:Led <= SW[4];
  38. 5:Led <= SW[5];
  39. 6:Led <= SW[6];
  40. 7:Led <= SW[7];
  41. default:Led <= Led ;
  42. endcase
  43. end
  44. endmodule

2.激励文件

  1. `timescale 1ns / 1ns
  2. module LED_ctrl0_tb();
  3. reg Clk;
  4. reg Reset_n;
  5. reg [7:0]SW;
  6. wire Led;
  7. LED_ctrl3 LED_ctrl3_inst0(
  8. .Clk(Clk),
  9. .Reset_n(Reset_n),
  10. .Led(Led),
  11. .SW(SW)
  12. );
  13. defparam LED_ctrl3_inst0.MCNT = 12500-1;
  14. initial Clk = 1;//初始信号为高电平
  15. always #10 Clk = ~Clk;//延时10ns以后初始信号取反,这句话是总是执行的。
  16. //产生激励复位信号
  17. initial begin
  18. Reset_n = 0;//开始复位信号为0,有效复位
  19. SW = 8'b0010_1010;
  20. #201 Reset_n = 1;//201ns以后复位信号变为高电平,无效电平。开始仿真
  21. #2_000_000;//仿真2ms
  22. SW = 8'b0000_0001;
  23. #2_000_000;//仿真2ms
  24. $stop;//停止仿真
  25. end
  26. endmodule

3.仿真图

五、任务4的代码编写

实现思路一:可以将3S等分为12份,每一份做不同的事情。此时前4份为空闲状态,后8位为动态变化状态,其中一个计数器用来计时0.25S,另外一个计时器用来计算计数器1计满0.25S的次数。这样就可以在不同的时刻做不同的事情了。

实现思路二(百用):计数器是一个刻度尺,写一个周期为3S的计数器,将这个计数器作为一个时间刻度尺,找到1S,1.25S,1.5S,1.75S,2S,2.25S,2.5S,2.75S,3S对应的计数器的值1。分别在计数器到达这些值的时候,控制LED输出SW的位,或者空闲态的0值。

实现思路三:使用3个计时器counter0,counter1,counter2;他们各自的作用是如下图:

counter1用于计时counter计满的次数,所以代码不用修改。

上面counter0和counter2中的en_counter0和en_counter2都是控制各个计时器是否开始计数的开关。en_counter2什么时候计数,什么时候不计数的框图如下图所示。

本文仅使用思路三进行实验。

1.设计文件

  1. //功能实现led亮0.25s,灭0.5s,亮0.75s,灭1s
  2. module LED_ctrl5(
  3. input Clk,
  4. input Reset_n,
  5. input [7:0]SW,
  6. output reg Led
  7. );
  8. reg [23:0]counter0;//定义计数器位数,板上时钟资源是20ns为一个周期,所以要用计时数除以20ns来计算计时次数。最后将次数转化成二进制位,有几位就定义几位计时器
  9. reg [2:0]counter1;//定时7个状态
  10. reg [25:0]counter2;//定时1s用来表示空闲状态
  11. reg encounter2;
  12. reg encounter0;
  13. parameter MCNT0 = 12500000-1;
  14. parameter MCNT2 = 50000000-1;
  15. always@(posedge Clk or negedge Reset_n)
  16. if(!Reset_n)//可见Reset_n复位是低电平有效
  17. encounter2 <= 1'd1;//一开始就给一个有效值,等复位结束后就保持为有效值,然后题目要求就是一开始就是开始1S空闲,所以一开始counter2就开始计时。
  18. else if((counter1 == 7) && (counter0 == MCNT0))
  19. encounter2 <= 1'd1;
  20. else if(counter2 == MCNT2)
  21. encounter2 <= 1'd0;
  22. else
  23. encounter2 <= encounter2;
  24. //assign encounter0 = !encounter2;
  25. always@(posedge Clk or negedge Reset_n)
  26. if(!Reset_n)//可见Reset_n复位是低电平有效
  27. encounter0 <= 1'd0;//一开始就给一个有效值,等复位结束后就保持为有效值,然后题目要求就是一开始就是开始1S空闲,所以一开始counter2就开始计时。
  28. else if(counter2 == MCNT2)
  29. encounter0 <= 1'd1;
  30. else if((counter1 == 7) && (counter0 == MCNT0))
  31. encounter0 <= 1'd0;
  32. else
  33. encounter0 <= encounter0;
  34. //计数器计数
  35. always@(posedge Clk or negedge Reset_n)
  36. if(!Reset_n)//可见Reset_n复位是低电平有效
  37. counter0 <= 0;
  38. else if(encounter0)
  39. begin
  40. if(counter0 == MCNT0)
  41. counter0 <= 0;
  42. else
  43. counter0 <= counter0 + 1'd1;
  44. end
  45. else
  46. counter0 <= 0;//counter0未使能不计数
  47. always@(posedge Clk or negedge Reset_n)
  48. if(!Reset_n)//可见Reset_n复位是低电平有效
  49. counter1 <= 0;
  50. else if(counter0 == MCNT0)
  51. counter1 <= counter1+1;
  52. else
  53. counter1 <= counter1;
  54. always@(posedge Clk or negedge Reset_n)
  55. if(!Reset_n)//可见Reset_n复位是低电平有效
  56. counter2 <= 0;
  57. else if(encounter2)
  58. begin
  59. if(counter2 == MCNT2)
  60. counter2 <= 0;
  61. else
  62. counter2 <= counter2 + 1'd1;
  63. end
  64. else
  65. counter2 <= 0;//counter0未使能不计数
  66. //使用case语句实现
  67. always@(posedge Clk or negedge Reset_n)
  68. if(!Reset_n)//可见Reset_n复位是低电平有效
  69. Led <= 0;
  70. else if(encounter2 == 1)
  71. Led <= 0;
  72. else //if(encounter2 == 0)
  73. begin
  74. case(counter1)
  75. 0:Led <= SW[0];
  76. 1:Led <= SW[1];
  77. 2:Led <= SW[2];
  78. 3:Led <= SW[3];
  79. 4:Led <= SW[4];
  80. 5:Led <= SW[5];
  81. 6:Led <= SW[6];
  82. 7:Led <= SW[7];
  83. default:Led <= Led ;
  84. endcase
  85. end
  86. endmodule

2.激励文件

  1. `timescale 1ns / 1ns
  2. module LED_ctrl0_tb();
  3. reg Clk;
  4. reg Reset_n;
  5. reg [7:0]SW;
  6. wire Led;
  7. LED_ctrl5 LED_ctrl5(
  8. .Clk(Clk),
  9. .Reset_n(Reset_n),
  10. .Led(Led),
  11. .SW(SW)
  12. );
  13. defparam LED_ctrl5.MCNT0 = 12500-1;
  14. defparam LED_ctrl5.MCNT2 = 50000-1;
  15. initial Clk = 1;//初始信号为高电平
  16. always #10 Clk = ~Clk;//延时10ns以后初始信号取反,这句话是总是执行的。
  17. //产生激励复位信号
  18. initial begin
  19. Reset_n = 0;//开始复位信号为0,有效复位
  20. SW = 8'b1010_1001;
  21. #201 Reset_n = 1;//201ns以后复位信号变为高电平,无效电平。开始仿真
  22. #40000000;//仿真40ms
  23. $stop;//停止仿真
  24. end
  25. endmodule

3.仿真图

六、总结

1.case语句,没有列举完的情况,需要加一个默认项列举完

  1. case(counter)
  2. MCNT*1/8 -1:led <= ctrl[0];//语句1
  3. MCNT*2/8 -1:led <= ctrl[1];
  4. MCNT*3/8 -1:led <= ctrl[2];
  5. MCNT*4/8 -1:led <= ctrl[3];
  6. MCNT*5/8 -1:led <= ctrl[4];
  7. MCNT*6/8 -1:led <= ctrl[5];
  8. MCNT*7/8 -1:led <= ctrl[6];
  9. MCNT*8/8 -1:led <= ctrl[7];
  10. default:led <= led;
  11. endcase

2.计数器可以用作时间刻度尺,每个时间都可以进行断点,然后在不同的时间点去做不同的事情。

  1. always@(posedge Clk or negedge Reset_n)
  2. if(!Reset_n)//可见Reset_n复位是低电平有效
  3. Led <= 0;
  4. else if(counter == 0)
  5. Led <= 1;
  6. else if(counter == 12_500*MCNT)
  7. Led <= !Led;
  8. else if(counter == 37_500*MCNT)
  9. Led <= !Led;
  10. else if(counter == 75_000*MCNT)
  11. Led <= !Led;
  12. else
  13. Led <= Led;
  14. endmodule

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

闽ICP备14008679号