【FPGA学习】按键切换呼吸灯实验

目录

项目要求:

实现原理:

 主代码

仿真效果:

 加入按键切换呼吸速度

按键切换呼吸速率代码

 实验总结:



项目要求:

        完成一个呼吸灯,要求从亮到灭的时间位2s,从灭到亮的时间为2s,完成呼吸灯的一个过程需要四秒。

实现原理:

        呼吸灯的实现主要是利用人眼视觉差来实现“呼”“吸”过程的效果,我们只需产生一个逐渐改变占空比的方波即可,即PWM。我们可以将2秒等分为1000份,这样每一个份即为2/1000s,假设第一份2/1000s为高电平(占空比100%),然后逐渐减少占空比,经过1000次以后,该方波占空比变为0,我们设定方波为高电平时,led灯亮,否则灭,这样我们就实现了从亮到灭的“”呼“”过程,类似的对于“吸”这个过程,我们需要设置一个flag_r标志信号,使其亮灭与“呼”过程相反即可。下图给出了该方波占空比的波形图。

整个呼吸效果的时序图如如下:

         由上图可见有两个“1000”和一个“100”,要注意的是这三者间的关系,pwm_cyc_cnt的1000指的是将亮--->灭的整个2s的过程分为1000份(2/1000s),clk50mcnt_1000中的1000指的是(2/1000s)的“小块”进一步分1000份(2/1000/1000s)=2000ns,这个2000ns需要频率为50mhz的晶振抖动100次,故clk50mcnt中的100表示此含义。需要注意的是clk50mcnt使在基准时钟的基础上产生的,clk50mcnt_1000是在clk50mcnt的基础上产生的,pwm_cyc_cnt是在clk50mcnt_1000的基础上产生的。

        进行1000次等分的就是为了在短时间内快速变化,由于人眼的视觉差,使得整个过程平滑流畅。

        用我们所期望的pwm波形对比可发现,当clk50mcnt_1000<pwm_cyc_cnt时将led电平拉低/高就能产生我们所需要的由亮到暗/由暗到亮的呼吸效果。

 主代码

module led_breath(

	input wire clk,
	input wire rst_n,
	
	output wire [3:0]led
);
	reg [6:0]	clk50mcnt;
	reg [9:0]	clk50mcnt_1000;
	reg [9:0]	pwm_cyc_cnt;
	reg 		flag_r;
	wire rst;
	wire [3:0]led_wave;
	assign rst = ~rst_n;
	
	//lk50mcnt counter
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			clk50mcnt <= 'd0;
		end
		else if (clk50mcnt == 'd99)begin
			clk50mcnt <= 'd0;
		end
		else begin
			clk50mcnt <= clk50mcnt + 1'b1;
		end
	end
	
	//clk50mcnt_1000 counter
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			clk50mcnt_1000 <= 'd0;
		end
		else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999)begin
			clk50mcnt_1000 <= 'd0;
		end
		else if (clk50mcnt == 'd99)begin
			clk50mcnt_1000 <= clk50mcnt_1000 + 1'b1;
		end
	end
	
	//pwm_cyc_cnt counter
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			pwm_cyc_cnt <= 'd0;
		end
		else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
			pwm_cyc_cnt <= 'd0;
		end
		else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999)begin
			pwm_cyc_cnt <= pwm_cyc_cnt + 1'b1;
		end
	end
	
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			flag_r <= 1'b0;
		end
		else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
			flag_r <= ~flag_r;
		end
		else begin
			flag_r <= flag_r;
		end
	end
	
	assign led_wave = ( clk50mcnt_1000 <  pwm_cyc_cnt)?4'b0000:4'b1111;
	assign led = (flag_r <= 4'b0000)?led_wave:~led_wave;
	
endmodule 

仿真效果:

 加入按键切换呼吸速度

        由于呼吸的速度是由clk50mcnt控制的,若两个呼吸单程分别为2s和1s,故我们需要重新设定一个7位宽的now_cnt变量来储存不同速率的clk50mcnt(us_2s_cnt、us_1s_cnt),和一个两位宽的输入信号(key_in).

    input [1:0] key_in;

    reg [6:0] now_cnt;

    parameter us_2s_cnt = 'd99;
	parameter us_1s_cnt = 'd49;

         最后利用key_in来切换呼吸速率

always@(posedge clk)begin
		if(rst == 1'b1)begin
			now_cnt <= 7'd0;
		end
		else if (key_in[0]==1&&key_in[1]==0) begin
			now_cnt <= us_2s_cnt ;
		end
		else if (key_in[1]==1&&key_in[0]==0) begin
			now_cnt <= us_1s_cnt ;
		end

	end

按键切换呼吸速率代码

module led_breath(

	input wire clk,
	input wire rst_n,
	input	[1:0] key_in,
	
	output wire [3:0]led
);
	reg [6:0]	clk50mcnt;
	reg [9:0]	clk50mcnt_1000;
	reg [9:0]	pwm_cyc_cnt;
	reg 		flag_r;
	reg [6:0]	now_cnt;
	
	wire rst;
	wire [3:0]	led_wave;
	assign rst = ~rst_n;
	
	parameter us_2s_cnt = 'd99;
	parameter us_1s_cnt = 'd49;
	
	//lk50mcnt counter
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			clk50mcnt <= 'd0;
		end
		else if (clk50mcnt == now_cnt-1)begin
			clk50mcnt <= 'd0;
		end
		else begin
			clk50mcnt <= clk50mcnt + 1'b1;
		end
	end
	
	//clk50mcnt_1000 counter
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			clk50mcnt_1000 <= 'd0;
		end
		else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999)begin
			clk50mcnt_1000 <= 'd0;
		end
		else if (clk50mcnt == now_cnt-1)begin
			clk50mcnt_1000 <= clk50mcnt_1000 + 1'b1;
		end
	end
	
	//pwm_cyc_cnt counter
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			pwm_cyc_cnt <= 'd0;
		end
		else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
			pwm_cyc_cnt <= 'd0;
		end
		else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999)begin
			pwm_cyc_cnt <= pwm_cyc_cnt + 1'b1;
		end
	end
	
    // flag_r 
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			flag_r <= 1'b0;
		end
		else if (clk50mcnt == now_cnt-1 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
			flag_r <= ~flag_r;
		end
		else begin
			flag_r <= flag_r;
		end
	end
	
	//key control
	always@(posedge clk)begin
		if(rst == 1'b1)begin
			now_cnt <= 7'd0;
		end
		else if (key_in[0]==1&&key_in[1]==0) begin
			now_cnt <= us_2s_cnt ;
		end
		else if (key_in[1]==1&&key_in[0]==0) begin
			now_cnt <= us_1s_cnt ;
		end

	end
	
	
	assign led_wave = ( clk50mcnt_1000 <  pwm_cyc_cnt)?4'b0000:4'b1111;
	assign led = (flag_r <= 4'b0000)?led_wave:~led_wave;
	
endmodule 
 


        如需按键消抖,加入按键消抖模块即可。

 实验总结:

        在代码编写中flag标志信号没有理解到位导致实验现象只有“吸”没有“呼”的现象。

错误示范:

always@(posedge clk)begin
		if(rst == 1'b1)begin
			flag_r <= 1'b0;
		end
		else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
			flag_r <= 1'b1;
		end
		else begin
			flag_r <= 1'b0;
		end
	end

修改后:

always@(posedge clk)begin
		if(rst == 1'b1)begin
			flag_r <= 1'b0;
		end
		else if (clk50mcnt == 'd99 && clk50mcnt_1000 == 'd999 && pwm_cyc_cnt == 'd999)begin
			flag_r <= ~flag_r;
		end
		else begin
			flag_r <= flag_r;
		end
	end

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值