呼吸灯
理论学习
呼吸灯在我们的生活中很常见,在手机上多作为消息提醒指示灯而被广泛使用,其效果是小灯在一段时间内从完全熄灭的状态逐渐变到最亮,再在同样的时间段内逐渐达到完全熄灭的状态,并循环往复。这种效果就像“呼吸”一样,有张有弛,而且给人一种很舒服的感觉。
实战思路
呼吸灯的实现可以分为两个过程,第一个过程为:完全熄灭->完全点亮
第二个过程为:完全点亮->完全熄灭
要实现“呼吸”一样的点亮效果,可以通过控制PWM的占空比来实现led灯越亮的效果。
第一个过程为:完全熄灭->完全点亮
如图所示,第一个T为熄灭状态;第二个T先点亮1/10T的时间,再熄灭;第三个T先点亮2/10T的时间,再熄灭;第四个T先点亮3/10T的时间,再熄灭…
第二个过程为:完全点亮->完全熄灭
将第一个过程取反即可
程序框图
波形图
图中,以1s为呼吸灯的完整过程周期,将1s分为1000份,则每份为1ms,再将1ms分为1000份,则每份为1us。那么每一个时间小段就是1us, 在逐渐变亮的过程中我们可以让led灯在第1个1ms的时间小段内亮0us,即全灭;第2个1ms的时间小段亮1us;第3个1ms的时间 小段亮2us,……,第998个1ms的时间小段亮997us,第999个1ms的时间小段亮998us,第1000个1ms的时间小段亮999us。
使能信号为低电平,则表示为呼吸灯的第一个过程,否则为呼吸灯的第二个过程。
呼吸灯第一个过程中的低电平时刻,可以通过判断cnt_1ms <= cnt_1s来实现,第二个过程中的高电平时刻同理。
代码
module breath_led
#(
parameter CNT_1US_MAX = 6'd49,
parameter CNT_1MS_MAX = 10'd999,
parameter CNT_1S_MAX = 10'd999
)
(
input clk,reset,
output reg led_out
);
reg[9:0] cnt_1s;
reg[9:0] cnt_1ms;
reg[5:0] cnt_1us;
reg cnt_en;
always @(posedge clk or negedge reset)
if(reset == 1'b0)
cnt_1us <= 6'd0;
else if(cnt_1us == CNT_1US_MAX)
cnt_1us <= 6'd0;
else
cnt_1us <= cnt_1us + 6'd1;
always @(posedge clk or negedge reset)
if(reset == 1'b0)
cnt_1ms <= 10'd0;
else if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
cnt_1ms <= 10'd0;
else if(cnt_1us == CNT_1US_MAX)
cnt_1ms <= cnt_1ms + 10'd1;
else
cnt_1ms <= cnt_1ms;
always @(posedge clk or negedge reset)
if(reset == 1'b0)
cnt_1s <= 10'd0;
else if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
cnt_1s <= 10'd0;
else if(cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
cnt_1s <= cnt_1s + 10'd1;
else
cnt_1s <= cnt_1s;
// 使能信号
always @(posedge clk or negedge reset)
if(reset == 1'b0)
cnt_en <= 1'b0;
else if(cnt_1s == CNT_1S_MAX && cnt_1ms == CNT_1MS_MAX && cnt_1us == CNT_1US_MAX)
cnt_en <= ~cnt_en;
else
cnt_en <= cnt_en;
// 输出信号
always @(posedge clk or negedge reset)
if(reset == 1'b0)
led_out <= 1'b1;
else if((cnt_en == 1'b0 && cnt_1ms <= cnt_1s) || (cnt_en == 1'b1 && cnt_1ms > cnt_1s))
led_out <= 1'b0;
else
led_out <= 1'b1;
endmodule
仿真测试
`timescale 1 ns/ 1 ns
module breath_led_vlg_tst();
reg clk;
reg reset;
wire led_out;
breath_led
#(
.CNT_1US_MAX(6'd4),
.CNT_1MS_MAX(10'd9),
.CNT_1S_MAX(10'd9)
)
i1 (
.clk(clk),
.led_out(led_out),
.reset(reset)
);
initial
begin
clk = 1'b1;
reset <= 1'b0;
#20
reset <= 1'b1;
end
always #10 clk = ~clk;
endmodule