当前位置:   article > 正文

FPGA开发——呼吸灯的设计

FPGA开发——呼吸灯的设计

一、原理

       呼吸灯的原理主要基于‌PWM(脉冲宽度调制)技术,通过控制LED灯的占空比来实现亮度的逐渐变化。这种技术通过调整PWM信号的占空比,即高电平在一个周期内所占的比例,来控制LED灯的亮度。当占空比从0%逐渐变化到100%,再从100%变化回0%,就实现了灯光亮度由暗到亮,再由亮到暗的循环变化,模拟了人的呼吸效果。‌

       具体来说,PWM信号的周期是固定的,通过改变高电平的时间长度(即占空比),可以控制LED灯的亮度。例如,当占空比为0%时,LED灯不亮;当占空比为100%时,LED灯最亮。通过编程或微电脑控制,可以实时调整这些参数,从而实现灯光亮度的动态变化。‌

       此外,还有一些非PWM的实现方式,例如通过编程控制亮和灭的时间比例,虽然这种方法较为复杂且可能不如PWM技术普及,但它提供了一种不同的实现思路。总的来说,PWM技术因其简单有效和广泛的应用支持,是实现呼吸灯的主要技术手段。‌

二、实现思路

       这里我们在设计的时候采用三个周期计数器,分别是us级,ms级以及s级计数器,通过对开发板系统时钟的20ns进行分频,接着实现us计数器的设计,最后利用us计数器实现毫秒计数器,利用ms计数器实现s计数器的方法逐一完成三个计数器,最后的占空比的调整是在ms计数器进行里面设置。在计数器设计好之后利用s级计数器对于状态标志进行一个设定,用于实现呼吸灯状态的改变标志。最后实现呼吸灯的相关功能。(这里实现的是2s的呼吸灯)

三、代码编写

设计文件

  1. module led(
  2. input clk,
  3. input rst_n,
  4. output reg [3:0] led_out
  5. );
  6. //参数定义
  7. parameter TIME_2us=1_000_000;
  8. parameter TIME_2ms=1000-1;
  9. parameter TIME_2s=1000-1;
  10. //内部信号定义
  11. reg [6:0] cnt_us;
  12. reg [9:0] cnt_ms;
  13. reg [26:0] cnt_s;
  14. reg flag;//呼吸灯亮灭标志位
  15. wire add_cnt_us;
  16. wire end_cnt_us;
  17. wire add_cnt_ms;
  18. wire end_cnt_ms;
  19. wire add_cnt_s;
  20. wire end_cnt_s;
  21. //2us计数器
  22. always @(posedge clk or negedge rst_n)begin
  23. if(!rst_n)
  24. cnt_us<= 0;
  25. else if(add_cnt_us)begin
  26. if(end_cnt_us)
  27. cnt_us<=0;
  28. else
  29. cnt_us<= cnt_us+1'b1;
  30. end
  31. end
  32. assign add_cnt_us = 1'b1;
  33. assign end_cnt_us = (cnt_us==7'd99) && add_cnt_us;
  34. //ms计数器
  35. always @(posedge clk or negedge rst_n)begin
  36. if(!rst_n)
  37. cnt_ms<= 0;
  38. else if(add_cnt_ms)begin
  39. if(end_cnt_ms)
  40. cnt_ms<=0;
  41. else
  42. cnt_ms<= cnt_ms+1'b1;
  43. end
  44. end
  45. assign add_cnt_ms = end_cnt_us;
  46. assign end_cnt_ms = add_cnt_ms && (cnt_ms==TIME_2ms);
  47. //s计数器
  48. always @(posedge clk or negedge rst_n)begin
  49. if(!rst_n)
  50. cnt_s<= 0;
  51. else if(add_cnt_s)begin
  52. if(end_cnt_s)
  53. cnt_s<=0;
  54. else
  55. cnt_s<= cnt_s+1'b1;
  56. end
  57. end
  58. assign add_cnt_s = end_cnt_ms;
  59. assign end_cnt_s = add_cnt_s && (cnt_s==TIME_2s);
  60. //flag亮灭状态描述
  61. always @(posedge clk or negedge rst_n)begin
  62. if(!rst_n)
  63. flag<= 0;
  64. else if(end_cnt_s)
  65. flag<=~flag;
  66. else
  67. flag<= flag;
  68. end
  69. //功能实现
  70. always @(posedge clk or negedge rst_n)begin
  71. if(rst_n==1'b0)
  72. led_out <= 4'b0000;
  73. // 由灭到亮
  74. else if((flag == 1'b0)&&(cnt_s <= cnt_ms))
  75. led_out <= 4'b0000;
  76. else if((flag == 1'b0)&&(cnt_s > cnt_ms))
  77. led_out <= 4'b1111;
  78. // 由亮到灭
  79. else if((flag == 1'b1)&&(cnt_s < cnt_ms))
  80. led_out <= 4'b1111;
  81. else if((flag == 1'b1)&&(cnt_s >= cnt_ms))
  82. led_out <= 4'b0000;
  83. else
  84. led_out <= led_out;
  85. end
  86. endmodule

测试文件的编写

  1. //定义时间尺度
  2. `timescale 1ns/1ps
  3. module led_tb();
  4. //重定义
  5. defparam led_inst.TIME_2us=10;
  6. defparam led_inst.TIME_2ms=10;
  7. defparam led_inst.TIME_2s=10;
  8. //内部变量定义
  9. reg clk;
  10. reg rst_n;
  11. wire led_out;
  12. //模块实例化
  13. led led_inst(
  14. /*input */ .rst_n (rst_n ),
  15. /*input */ .clk (clk ),
  16. /*output reg [3:0] */ .led_out (led_out )
  17. );
  18. //时钟
  19. parameter CLK_CLY =20;
  20. initial clk=0;
  21. always #(CLK_CLY/2) clk=~clk;
  22. //复位
  23. initial begin
  24. rst_n =1'b0;
  25. #(CLK_CLY*2);
  26. #3;
  27. rst_n =1'b1;
  28. end
  29. //激励
  30. endmodule

四、仿真波形图

由于我们设置的计数器技术周期和系统的周期相差过大,所以在测试文件中进行重定义来更好在波形途中观察ms周期中高低占空比的改变。

 通过波形图我们可以观察到低电平从最开始的100%慢慢变成0%,最后又会从0%变为100%,高电平从最开始的0%慢慢变成100%,最后又会从100%变为0%(这里,0000和1111的频率占空比),这里的波形图位置有限,没有拍完。

受格式的影响,这里就不放下板之后的效果,最终实现的效果就是4个LED会由暗变为亮,在由亮变暗的呼吸灯效果。

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

闽ICP备14008679号