FPGA学习笔记——呼吸灯(PWM)

一、PWM

要实现PWM调呼吸灯,就要知道PWM怎么构成。

PWM是由计数器和比较器构成。通过改变计数器的大小,来实现呼吸灯的闪烁速度(详细的PWM说明可以去找其他博主的博客)。因此,示例代码如下。

parameter		cnt_1us_max = 6'd49     ;
parameter	  	cnt_1ms_max = 10'd999   ;
parameter		cnt_1s_max  = 10'd999	;

reg 	[9:0]	cnt_1s		;
reg 	[9:0]	cnt_1ms		;
reg  	[5:0]	cnt_1us		;
reg             cnt_en      ;//使能信号  到1s的时候使能

// 1us 计数器
always@(posedge sys_clk)	 
		if(rst_n == 1'b0)
			cnt_1us <= 6'd0;
		else if(cnt_1us == cnt_1us_max)
			cnt_1us <= 6'd0;
		else
			cnt_1us <= cnt_1us + 1;
			
//	1ms 计数器		 
always@(posedge sys_clk)	 
		if(rst_n == 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 + 1;
		else
			cnt_1ms <= cnt_1ms  ;

// 1s 计数器			
always@(posedge sys_clk)	 
		if(rst_n == 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 + 1;
		else 
			cnt_1s <= cnt_1s    ;	

//使能信号
always@(posedge sys_clk)
	if (!rst_n)
		cnt_en <= 0		    ;
	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    ;


//PWM
always@(posedge sys_clk)
	if (!rst_n)
		led_out <= 0;
	else if ((cnt_1s >= cnt_1ms) && (cnt_en == 0))
		led_out <= ~led_out;
	else if ((cnt_1s < cnt_1ms) && (cnt_en == 1))
		led_out <= ~led_out;
	else
		led_out <= led_out;

我这里定义了三个计数器,可以让现象更加的细腻。  

在第一个周期时,只有1/10的周期,让LED保持点亮,每个周期增加1/10的LED保持带点亮的时间,在第10个周期时被完全点亮。同理,然后再依次减少1/10的周期时间,直至熄灭。然后重复。就实现了PWM调呼吸灯。

二、画visio图

三、写代码

module breath_led(
	input 	wire	sys_clk         ,
	input 	wire	rst_n           ,
	output 	reg   	led_out
);


parameter		cnt_1us_max = 6'd49     ; //最大值
parameter	  	cnt_1ms_max = 10'd999   ; //最大值
parameter		cnt_1s_max  = 10'd999	; //最大值

reg 	[9:0]	cnt_1s		;
reg 	[9:0]	cnt_1ms		;
reg  	[5:0]	cnt_1us		;
reg             cnt_en      ;//使能信号  到1s的时候使能

// 1us 计数器
always@(posedge sys_clk)	 
		if(rst_n == 1'b0)
			cnt_1us <= 6'd0;
		else if(cnt_1us == cnt_1us_max)
			cnt_1us <= 6'd0;
		else
			cnt_1us <= cnt_1us + 1;
			
//	1ms 计数器		 
always@(posedge sys_clk)	 
		if(rst_n == 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 + 1;
		else
			cnt_1ms <= cnt_1ms  ;

// 1s 计数器			
always@(posedge sys_clk)	 
		if(rst_n == 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 + 1;
		else 
			cnt_1s <= cnt_1s    ;	

//使能信号
always@(posedge sys_clk)
	if (!rst_n)
		cnt_en <= 0		    ;
	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    ;


//PWM
always@(posedge sys_clk)
	if (!rst_n)
		led_out <= 0;
	else if ((cnt_1s >= cnt_1ms) && (cnt_en == 0))
		led_out <= ~led_out;
	else if ((cnt_1s < cnt_1ms) && (cnt_en == 1))
		led_out <= ~led_out;
	else
		led_out <= led_out;


endmodule

        根据visio图可以定义输入和输出变量,呼吸灯是由从灭到亮,再从亮到灭。因此呢,我们还需要一个变量cnt_en来使能,就是为0的时候,是从灭到亮这个过程,为1的时候是从亮到灭这个过程。

        我这里是用1us计数器,来给1ms计数器,1s计数器来计数,可以很好的减少FPGA的缓存。

        当1us计数到最大值的时候,让1ms加一,等到1us计数到最大值和1ms计数到最大值,就让1s计数器加一,实现了一个周期的PWM。

        再经过比较器,可以控制输出高电平或者低电平的时间,就实现了PWM,就可以是实现LED呼吸灯。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值