FPGA学习篇之呼吸灯
前言
用单片机产生占空比渐变的PWM波控制LED可以产生呼吸灯的效果,单片机能做到,FPGA同样能做到。
一、参数指定
在编写代码之前,首先要明确以下几个概念:
- 呼吸周期:也就是LED灯完成一次呼吸循环的时间,期间LED灯从灭到亮再到灭,代码中定义呼吸周期为2S,从灭到亮1S,从亮到灭1S。
- PWM周期:调整一次LED亮灭的时间。本代码中PWM周期为1MS,PWM周期越小,每个呼吸周期内调整的次数就越多,LED呼吸效果就越丝滑。
- PWM精度:一个PWM周期内PWM占空比能改变的最小值,同样的PWM精度越小,LED呼吸效果也越丝滑,本代码中PWM精度为1US。
二、代码编写
本代码时钟频率为50MHz,呼吸周期为2S。如果要修改呼吸周期和PWM周期,可以修改参数。
module breath_led #(
parameter CNT_1S_MAX = 999 , //
parameter CNT_1MS_MAX = 999 , //
parameter CNT_1US_MAX = 49 //
)(
input clk_in,
input rst_n,
output reg led
);
reg [9:0] cnt_1s;
reg [9:0] cnt_1ms;
reg [5:0] cnt_1us;
reg [0:0] led_dir;
always@(posedge clk_in or negedge rst_n)
if(!rst_n)
cnt_1us <= 'h0;
else if(cnt_1us == CNT_1US_MAX)
cnt_1us <= 'h0;
else
cnt_1us <= cnt_1us + 1'b1;
always@(posedge clk_in or negedge rst_n)
if(!rst_n)
cnt_1ms <= 'h0;
else if((cnt_1us == CNT_1US_MAX) && (cnt_1ms == CNT_1MS_MAX))
cnt_1ms <= 'h0;
else if(cnt_1us == CNT_1US_MAX)
cnt_1ms <= cnt_1ms + 1'b1;
always@(posedge clk_in or negedge rst_n)
if(!rst_n)
cnt_1s <= 'h0;
else if((cnt_1us == CNT_1US_MAX) && (cnt_1ms == CNT_1MS_MAX) && (cnt_1s == CNT_1S_MAX))
cnt_1s <= 'h0;
else if((cnt_1us == CNT_1US_MAX) && (cnt_1ms == CNT_1MS_MAX))
cnt_1s <= cnt_1s + 1'b1;
always@(posedge clk_in or negedge rst_n)
if(!rst_n)
led_dir <= 1'b0;
else if((cnt_1us == CNT_1US_MAX) && (cnt_1ms == CNT_1MS_MAX) && (cnt_1s == CNT_1S_MAX))
led_dir <= ~led_dir;
always@(posedge clk_in or negedge rst_n)
if(!rst_n)
led <= 1'b0;
else if(((led_dir == 1'b0) && (cnt_1ms < cnt_1s)) || ((led_dir == 1'b1) && (cnt_1ms > cnt_1s)))
led <= 1'b1;
else
led <= 1'b0;
endmodule
三、总结
呼吸灯是计数器的简单应用,通过呼吸灯我们可以理解PWM的控制原理与思想。