FPGA入门学习——呼吸灯

本文介绍了如何通过控制PWM的占空比实现LED的呼吸灯效果,包括理论描述、实战思路、编程实现(使用Verilog)以及仿真测试。详细展示了从熄灭到点亮,再到熄灭的过程及其代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

呼吸灯

理论学习

呼吸灯在我们的生活中很常见,在手机上多作为消息提醒指示灯而被广泛使用,其效果是小灯在一段时间内从完全熄灭的状态逐渐变到最亮,再在同样的时间段内逐渐达到完全熄灭的状态,并循环往复。这种效果就像“呼吸”一样,有张有弛,而且给人一种很舒服的感觉。

实战思路

呼吸灯的实现可以分为两个过程,第一个过程为:完全熄灭->完全点亮
第二个过程为:完全点亮->完全熄灭
要实现“呼吸”一样的点亮效果,可以通过控制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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值