当前位置:   article > 正文

【FPGA学习】按键切换呼吸灯实验_呼吸灯按键切换速率

呼吸灯按键切换速率

目录

项目要求:

实现原理:

 主代码

仿真效果:

 加入按键切换呼吸速度

按键切换呼吸速率代码

 实验总结:



项目要求:

        完成一个呼吸灯,要求从亮到灭的时间位2s,从灭到亮的时间为2s,完成呼吸灯的一个过程需要四秒。

实现原理:

        呼吸灯的实现主要是利用人眼视觉差来实现“呼”“吸”过程的效果,我们只需产生一个逐渐改变占空比的方波即可,即PWM。我们可以将2秒等分为1000份,这样每一个份即为2/1000s,假设第一份2/1000s为高电平(占空比100%),然后逐渐减少占空比,经过1000次以后,该方波占空比变为0,我们设定方波为高电平时,led灯亮,否则灭,这样我们就实现了从亮到灭的“”呼“”过程,类似的对于“吸”这个过程,我们需要设置一个flag_r标志信号,使其亮灭与“呼”过程相反即可。下图给出了该方波占空比的波形图。

整个呼吸效果的时序图如如下:

         由上图可见有两个“1000”和一个“100”,要注意的是这三者间的关系,pwm_cyc_cnt的1000指的是将亮--->灭的整个2s的过程分为1000份(2/1000s),clk50mcnt_1000中的1000指的是(2/1000s)的“小块”进一步分1000份(2/1000/1000s)=2000ns,这个2000ns需要频率为50mhz的晶振抖动100次,故clk50mcnt中的100表示此含义。需要注意的是clk50mcnt使在基准时钟的基础上产生的,clk50mcnt_1000是在clk50mcnt的基础上产生的,pwm_cyc_cnt是在clk50mcnt_1000的基础上产生的。

        进行1000次等分的就是为了在短时间内快速变化,由于人眼的视觉差,使得整个过程平滑流畅。

        用我们所期望的pwm波形对比可发现,当clk50mcnt_1000<pwm_cyc_cnt时将led电平拉低/高就能产生我们所需要的由亮到暗/由暗到亮的呼吸效果。

 主代码

  1. module led_breath(
  2. input wire clk,
  3. input wire rst_n,
  4. output wire [3:0]led
  5. );
  6. reg [6:0] clk50mcnt;
  7. reg [9:0] clk50mcnt_1000;
  8. reg [9:0] pwm_cyc_cnt;
  9. reg flag_r;
  10. wire rst;
  11. wire [3:0]led_wave;
  12. assign rst = ~rst_n;
  13. //lk50mcnt counter
  14. always@(posedge clk)begin
  15. if(rst == 1'b1)begin
  16. clk50mcnt <= 'd0;
  17. end
  18. else if (clk50mcnt == 'd99)begin
  19. clk50mcnt <= 'd0;
  20. end
  21. else begin
  22. clk50mcnt <= clk50mcnt + 1'b1;
  23. end
  24. end
  25. //clk50mcnt_1000 counter
  26. always@(posedge clk)begin
  27. if(rst == 1'b1)begin
  28. clk50mcnt_1000 <= 'd0;
  29. end
  30. else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999)begin
  31. clk50mcnt_1000 <= 'd0;
  32. end
  33. else if (clk50mcnt == 'd99)begin
  34. clk50mcnt_1000 <= clk50mcnt_1000 + 1'b1;
  35. end
  36. end
  37. //pwm_cyc_cnt counter
  38. always@(posedge clk)begin
  39. if(rst == 1'b1)begin
  40. pwm_cyc_cnt <= 'd0;
  41. end
  42. else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
  43. pwm_cyc_cnt <= 'd0;
  44. end
  45. else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999)begin
  46. pwm_cyc_cnt <= pwm_cyc_cnt + 1'b1;
  47. end
  48. end
  49. always@(posedge clk)begin
  50. if(rst == 1'b1)begin
  51. flag_r <= 1'b0;
  52. end
  53. else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
  54. flag_r <= ~flag_r;
  55. end
  56. else begin
  57. flag_r <= flag_r;
  58. end
  59. end
  60. assign led_wave = ( clk50mcnt_1000 < pwm_cyc_cnt)?4'b0000:4'b1111;
  61. assign led = (flag_r <= 4'b0000)?led_wave:~led_wave;
  62. endmodule

仿真效果:

 加入按键切换呼吸速度

        由于呼吸的速度是由clk50mcnt控制的,若两个呼吸单程分别为2s和1s,故我们需要重新设定一个7位宽的now_cnt变量来储存不同速率的clk50mcnt(us_2s_cnt、us_1s_cnt),和一个两位宽的输入信号(key_in).

  1. input [1:0] key_in;
  2. reg [6:0] now_cnt;
  3. parameter us_2s_cnt = 'd99;
  4. parameter us_1s_cnt = 'd49;

         最后利用key_in来切换呼吸速率

  1. always@(posedge clk)begin
  2. if(rst == 1'b1)begin
  3. now_cnt <= 7'd0;
  4. end
  5. else if (key_in[0]==1&&key_in[1]==0) begin
  6. now_cnt <= us_2s_cnt ;
  7. end
  8. else if (key_in[1]==1&&key_in[0]==0) begin
  9. now_cnt <= us_1s_cnt ;
  10. end
  11. end

按键切换呼吸速率代码

  1. module led_breath(
  2. input wire clk,
  3. input wire rst_n,
  4. input [1:0] key_in,
  5. output wire [3:0]led
  6. );
  7. reg [6:0] clk50mcnt;
  8. reg [9:0] clk50mcnt_1000;
  9. reg [9:0] pwm_cyc_cnt;
  10. reg flag_r;
  11. reg [6:0] now_cnt;
  12. wire rst;
  13. wire [3:0] led_wave;
  14. assign rst = ~rst_n;
  15. parameter us_2s_cnt = 'd99;
  16. parameter us_1s_cnt = 'd49;
  17. //lk50mcnt counter
  18. always@(posedge clk)begin
  19. if(rst == 1'b1)begin
  20. clk50mcnt <= 'd0;
  21. end
  22. else if (clk50mcnt == now_cnt-1)begin
  23. clk50mcnt <= 'd0;
  24. end
  25. else begin
  26. clk50mcnt <= clk50mcnt + 1'b1;
  27. end
  28. end
  29. //clk50mcnt_1000 counter
  30. always@(posedge clk)begin
  31. if(rst == 1'b1)begin
  32. clk50mcnt_1000 <= 'd0;
  33. end
  34. else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999)begin
  35. clk50mcnt_1000 <= 'd0;
  36. end
  37. else if (clk50mcnt == now_cnt-1)begin
  38. clk50mcnt_1000 <= clk50mcnt_1000 + 1'b1;
  39. end
  40. end
  41. //pwm_cyc_cnt counter
  42. always@(posedge clk)begin
  43. if(rst == 1'b1)begin
  44. pwm_cyc_cnt <= 'd0;
  45. end
  46. else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
  47. pwm_cyc_cnt <= 'd0;
  48. end
  49. else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999)begin
  50. pwm_cyc_cnt <= pwm_cyc_cnt + 1'b1;
  51. end
  52. end
  53. // flag_r
  54. always@(posedge clk)begin
  55. if(rst == 1'b1)begin
  56. flag_r <= 1'b0;
  57. end
  58. else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
  59. flag_r <= ~flag_r;
  60. end
  61. else begin
  62. flag_r <= flag_r;
  63. end
  64. end
  65. //key control
  66. always@(posedge clk)begin
  67. if(rst == 1'b1)begin
  68. now_cnt <= 7'd0;
  69. end
  70. else if (key_in[0]==1&&key_in[1]==0) begin
  71. now_cnt <= us_2s_cnt ;
  72. end
  73. else if (key_in[1]==1&&key_in[0]==0) begin
  74. now_cnt <= us_1s_cnt ;
  75. end
  76. end
  77. assign led_wave = ( clk50mcnt_1000 < pwm_cyc_cnt)?4'b0000:4'b1111;
  78. assign led = (flag_r <= 4'b0000)?led_wave:~led_wave;
  79. endmodule

        如需按键消抖,加入按键消抖模块即可。

 实验总结:

        在代码编写中flag标志信号没有理解到位导致实验现象只有“吸”没有“呼”的现象。

错误示范:

  1. always@(posedge clk)begin
  2. if(rst == 1'b1)begin
  3. flag_r <= 1'b0;
  4. end
  5. else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
  6. flag_r <= 1'b1;
  7. end
  8. else begin
  9. flag_r <= 1'b0;
  10. end
  11. end

修改后:

  1. always@(posedge clk)begin
  2. if(rst == 1'b1)begin
  3. flag_r <= 1'b0;
  4. end
  5. else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
  6. flag_r <= ~flag_r;
  7. end
  8. else begin
  9. flag_r <= flag_r;
  10. end
  11. end

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

闽ICP备14008679号