【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
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实验目的: 通过 FPGA 实现按键控制 LED 灯的亮灭,加深对 FPGA 的理解和应用。 实验器材: - FPGA 开发板(例如 DE10-Lite) - USB 线 - 按键模块 - LED 灯模块 实验步骤: 1. 搭建硬件电路 将按键模块和 LED 灯模块插入 FPGA 开发板的相应引脚上,并将 FPGA 开发板与电脑连接。 按键模块连接方式: - K1 和 K2 分别连接到 FPGA 引脚的 PIN_23 和 PIN_25 上。 - GND 连接到 FPGA 引脚的 PIN_19 上。 LED 灯模块连接方式: - VCC 连接到 FPGA 引脚的 PIN_3 上。 - GND 连接到 FPGA 引脚的 PIN_1 上。 - LED1 和 LED2 分别连接到 FPGA 引脚的 PIN_10 和 PIN_12 上。 2. 新建 Quartus 工程 打开 Quartus 软件,选择 File -> New Project Wizard,新建一个工程。 3. 添加 Verilog 文件 在工程目录下新建一个 Verilog 文件,将以下代码复制进去: ```verilog module key_led( input clk, input k1, input k2, output led1, output led2 ); reg [1:0] state; always @(posedge clk) begin case(state) 2'b00: begin led1 <= 1'b0; led2 <= 1'b0; if(k1) state <= 2'b01; if(k2) state <= 2'b10; end 2'b01: begin led1 <= 1'b1; led2 <= 1'b0; if(!k1) state <= 2'b00; end 2'b10: begin led1 <= 1'b0; led2 <= 1'b1; if(!k2) state <= 2'b00; end default: state <= 2'b00; endcase end endmodule ``` 这段 Verilog 代码实现了按键控制 LED 灯的功能,在上升沿时检测按键的状态,根据按键的状态控制 LED 灯的亮灭。 4. 设计约束文件 在工程目录下新建一个 SDC 文件,将以下代码复制进去: ```tcl create_clock -name clk -period 10.0 -waveform {0 5.0} [get_ports clk] set_input_delay -clock clk -max 2.0 [get_ports k1] set_input_delay -clock clk -max 2.0 [get_ports k2] set_output_delay -clock clk -max 2.0 [get_ports led1] set_output_delay -clock clk -max 2.0 [get_ports led2] ``` 这段 SDC 代码定义了时钟和输入输出的时序约束。 5. 编译工程 在 Quartus 软件中,选择 Processing -> Start Compilation,编译工程。 6. 下载到 FPGA 开发板 编译成功后,在 Quartus 软件中选择 Tools -> Programmer,将编译好的文件下载到 FPGA 开发板。 7. 运行实验FPGA 开发板接通电源,按下 K1 按键,LED1 灯亮起;按下 K2 按键,LED2 灯亮起。松开按键后,LED 灯熄灭。 实验效果: 通过按键控制 LED 灯的亮灭,实现了简单的数字逻辑电路的设计和实现。 实验总结: 本实验通过 FPGA 实现按键控制 LED 灯的亮灭,加深了对 FPGA 的理解和应用。在设计数字逻辑电路时,需要注意时序约束的设置,确保电路能够正常工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值