本文最后更新于 2024年8月31日 中午
FPGA呼吸灯
PWM( Pulse Width Modulation),即脉冲宽度调制,它是利用微处理器输出的 PWM 信号对模拟电路进行控制的一种非常有效的技术,广泛应用于测量、通信功率控制等领域。在由计数器产生固定周期的 PWM 信号下,如果其占空比为 0,则 LED 灯不亮;如果其占空比为100%,则 LED 灯最亮。将占空比从 0 到100%,再从 100%到 0 不断变化,就可以实现 LED 灯的“ 呼吸”效果。
PWM 占空比调节示意图如下图所示:
2、绘制波形图 根据呼吸灯的实际效果我们可知,呼吸灯是由两个部分组成,一个是由亮到暗的过程,一个是由暗到亮的过程,再由简介可知我们是在固定的频率下通过调整 高电平的占空比来调控 led 灯的亮度。LED 灯的亮度由亮到暗变化,就是 led 灯信号的高电平占空比开始递减,如图 所示; LED 灯的亮度由暗到亮变化,就是 led 灯信号的高电平占空比开始递增,如图所示;因此,我们需要定义一个 led 灯高电平占空比递增/递减信号 inc_dec_flag 。
本实验中我们将由暗到亮的渐变过程定义为 2s,接下来我们将这 2s 分成 1000 份,就是由暗到亮的渐变过程中有 1000 个亮度过渡,每一份过渡时间为 2ms;接下开我们再将每一份过渡时间 2ms 均分为 1000份,每份时间为 2us,我们以 2us 为单位递减 2ms 中的高电平的占空比,随着高电平占空比的不断减少,led 灯的亮度不断变暗。
通过观察上面的波形图我们发现 cnt_2s 计数值为 0 时, cnt_2ms 有一个计数值 0 小于等于 cnt_2s 计数值 0; cnt_2s 计数值为 1 时, cnt_2ms 有两个计数值 0 与 1 都小于等于 cnt_2s 计数值 1; cnt_2s 计数值为 2时, cnt_2ms 有三个计数值 0、 1 与 2 都小于等于 cnt_2s 计数值 2;随着 cnt_2s 计数值从 0 到 999 增加,直到 cnt_2s 计数值为 999 时, cnt_2ms 的 1000 个计数值都是小于等于 cnt_2s 的计数值 999。由上面的分析总结可知, cnt_2ms 计数值小于等于 cnt_2s 计数值的个数从 1 到 1000 在逐渐增多,并且每次是以 2us 的时间增加的。由此我们可以定义 cnt_2ms 值小于等于 cnt_2s 计数值时,我们给 led 灯高电平,否则给 led 低电平。cnt_2s 计数的 1000 个值等价于 led 从暗到亮的 1000 个过渡期的编号,那么每个过渡期的时长是 2ms。第一个暗到亮的过渡期即 cnt_2s 计数值为 0 时, 我们在第一个 2ms 的时间内给 led 一个 2us 时间的高电平,其余时间全部赋值低电平; cnt_2s 计数值为 1 时,我们在第二个 2ms 的时间内给 led 灯两个 2us 时间的高电平,其余时间全部赋值低电平; cnt_2s 计数值为 2 时,我们在第三个 2ms 的时间内给 led 灯三个 2us 时间的高电平,其余时间全部赋值低电平;直到 cnt_2s 计数值为 999 时,我们在第一千个 2ms 的时间内给 led灯一千个 2us 的高电平,即此时 led 灯 2ms 内全部高电平, led 灯最亮。由上面的分析我们可以绘制呼吸灯由暗变亮过程的波形图如下所示:
3、编写代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 module breath_led( input sys_clk , input sys_rst_n , output reg led );parameter CNT_2US_MAX = 7'd100 ; parameter CNT_2MS_MAX = 10'd1000 ; parameter CNT_2S_MAX = 10'd1000 ; reg [6 :0 ] cnt_2us; reg [9 :0 ] cnt_2ms; reg [9 :0 ] cnt_2s ; reg inc_dec_flag; always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt_2us <= 7'b0 ; else if (cnt_2us == (CNT_2US_MAX - 7'b1 )) cnt_2us <= 7'b0 ; else cnt_2us <= cnt_2us + 7'b1 ;end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt_2ms <= 10'b0 ; else if (cnt_2ms == (CNT_2MS_MAX - 10'b1 ) && cnt_2us == (CNT_2US_MAX - 7'b1 )) cnt_2ms <= 10'b0 ; else if (cnt_2us == CNT_2US_MAX - 7'b1 ) cnt_2ms <= cnt_2ms + 10'b1 ; else cnt_2ms <= cnt_2ms;end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) cnt_2s <= 10'b0 ; else if (cnt_2s == (CNT_2S_MAX - 10'b1 ) && cnt_2ms == (CNT_2MS_MAX - 10'b1 ) && cnt_2us == (CNT_2US_MAX - 7'b1 )) cnt_2s <= 10'b0 ; else if (cnt_2ms == (CNT_2MS_MAX - 10'b1 ) && cnt_2us == (CNT_2US_MAX - 7'b1 )) cnt_2s <= cnt_2s + 10'b1 ; else cnt_2s <= cnt_2s; end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) inc_dec_flag <= 1'b0 ; else if (cnt_2s == (CNT_2S_MAX - 10'b1 ) && cnt_2ms ==( CNT_2MS_MAX - 10'b1 ) && cnt_2us == (CNT_2US_MAX - 7'b1 )) inc_dec_flag <= ~inc_dec_flag; else inc_dec_flag <= inc_dec_flag;end always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) led <= 1'b0 ; else if ((inc_dec_flag == 1'b1 && cnt_2ms >= cnt_2s) || (inc_dec_flag == 1'b0 && cnt_2ms <= cnt_2s)) led <= 1'b1 ; else led <= 1'b0 ;end endmodule
仿真文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 `timescale 1ns / 1ns module tb_breath_led();parameter CLK_PERIOD = 20 ; parameter CNT_2US_MAX = 6'd2 ;parameter CNT_2MS_MAX = 11'd10 ;parameter CNT_2S_MAX = 11'd10 ;reg sys_clk;reg sys_rst_n;wire led;initial begin sys_clk <= 1'b0 ; sys_rst_n <= 1'b0 ; #200 sys_rst_n <= 1'b1 ;end always #(CLK_PERIOD/2) sys_clk = ~sys_clk; breath_led #( .CNT_2US_MAX (CNT_2US_MAX), .CNT_2MS_MAX (CNT_2MS_MAX), .CNT_2S_MAX (CNT_2S_MAX) )u_breath_led( .sys_clk (sys_clk), .sys_rst_n (sys_rst_n), .led (led) );endmodule
本文作者:
zhangJinLong
本文链接:
https://zhang426fly.github.io/2025/07/05/fpga/FPGA呼吸灯/
版权声明:
本博客所有文章除特别声明外,均采用BY-NC-SA许可协议。转载请注明出处!