【FPGA零基础学习之旅#5】产生非等占空比信号

该文介绍了如何使用FPGA产生非等占空比信号,通过LED的亮灭展示了等占空比和非等占空比信号的区别。文中提供了VerilogHDL代码实现1秒和0.2秒定时器,并通过这两个定时器控制LED亮灭,实现了不同占空比的信号。此外,还设计了两个小项目,分别是不同间隔熄灭的流水灯,进一步巩固了定时器和非等占空比信号的应用。
摘要由CSDN通过智能技术生成

🎉欢迎来到FPGA专栏~产生非等占空比信号


  • ☆* o(≧▽≦)o *☆~我是小夏与酒🍹
  • 博客主页:小夏与酒的博客
  • 🎈该系列文章专栏:FPGA学习之旅
  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
  • 📜 欢迎大家关注! ❤️
    FPGQ2

CSDN

遇见未来

一、效果演示

🥝等占空比信号

1S亮灭

🥝非等占空比信号

亮0.2秒
同时进行

二、等占空比信号的产生

我们通过LED的亮灭来展现等占空比信号:LED循环亮灭,亮1秒,灭1秒。

50MHz的晶振,要实现1秒的定时,需要计数49_999_999次,RTL视图展示如下:
RTL1

Verilog HDL代码:

/
//模块作用:led亮一秒灭一秒
//作者:CSDN-小夏与酒

module led_plus1(
	input 			Clk,
	input 			Rst_n,
	output 	reg	led	
);
	
	reg [25:0]cnt;
	
	parameter cnt_max = 26'd49_999_999;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 26'd0;
		else if(cnt == cnt_max)
			cnt <= 26'd0;
		else 
			cnt <= cnt + 1'b1;
	end 
	
	always@(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)
			led <= 1'b1;
		else if(cnt == cnt_max)
			led <= ~led;
		else 
			led <= led;	
	end 
	
endmodule

测试激励文件代码:

`timescale 1ns/1ns
`define clock_period 20

module led_plus1_tb;
	
	reg Clk;
	reg Rst_n;
	
	wire led;
	
	led_plus Uled_plus1_0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.led(led)	
	);
	
	initial Clk = 1;
	always #(`clock_period/2) Clk = ~Clk;
	
	initial begin 
	Rst_n = 0;
	
	#100 Rst_n = 1;
	
	#(`clock_period*1000000);
	
	$stop;
		
	end

endmodule

三、非等占空比信号的产生

我们通过LED的亮灭来展现等占空比信号:LED循环亮灭,亮0.2秒,灭1.8秒。

实现的基本思路:当计时器从0开始计时到0.2秒的过程中,LED点亮;当计时器从0.2秒之后计时到2秒的过程中,LED熄灭;当计时器达到2秒时,计数清空。

50MHz的晶振,要实现0.2秒的定时,需要计数9_999_999次;要实现2秒的定时,需要计数99_999_999次,RTL视图展示如下:
RTL2
Verilog HDL代码:

/
//模块作用:led亮0.2秒,灭1.8秒
//作者:CSDN-小夏与酒

module led_plus2(
	input 			Clk,
	input 			Rst_n,
	output 	reg	led	
);
	
	reg [26:0]cnt;
	
	parameter cnt_max = 27'd99_999_999;
	parameter cnt_ON = 27'd0;
	parameter cnt_OFF = 27'd9_999_999;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 27'd0;
		else if(cnt == cnt_max)
			cnt <= 27'd0;
		else 
			cnt <= cnt + 1'b1;
	end 
	
	always@(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)
			led <= 1'b1;
		else if(cnt == cnt_ON)
			led <= 1'b0;
		else if(cnt == cnt_OFF)
			led <= ~led;
		else 
			led <= led;	
	end 
	
endmodule

测试激励文件代码:

`timescale 1ns/1ns
`define clock_period 20

module led_plus2_tb;
	
	reg Clk;
	reg Rst_n;
	
	wire led;
	
	led_plus Uled_plus2_0(
		.Clk(Clk),
		.Rst_n(Rst_n),
		.led(led)	
	);
	
	initial Clk = 1;
	always #(`clock_period/2) Clk = ~Clk;
	
	initial begin 
	Rst_n = 0;
	
	#100 Rst_n = 1;
	
	#(`clock_period*1000000000);
	
	$stop;
		
	end

endmodule

产生非等占空比信号的思路:规定一个时间段,然后把这个时间段分成不同时间长度的小时间段,在各个小时间段里进行不同的操作。如上述代码,规定一个LED闪烁周期为2秒,前0.2秒点亮,后1.8秒熄灭。而在等占空比信号的产生中,规定一个LED闪烁周期为2秒,前1秒点亮,后1秒熄灭。

为了更直观地看到不同占空比信号的效果,将上述代码整理并加入到顶层文件中:

/
//模块作用:信号占空比顶层文件
//作者:CSDN-小夏与酒

module led_plus(
	input 	Clk,
	input 	Rst_n,
	output 	led1,	
	output 	led2
);
	
	led_plus1 Uled_plus1(
	.Clk(Clk),
	.Rst_n(Rst_n),
	.led(led1)	
	);
	
	led_plus2 Uled_plus2(
	.Clk(Clk),
	.Rst_n(Rst_n),
	.led(led2)	
	);	
	
endmodule

RTL视图:
RTL3

其中,为了更好地理解本次项目的内容,led_plus1模块中也使用2秒为一个周期,前一秒LED亮,后一秒LED灭,写法思路和前述代码相同:

/
//模块作用:led亮一秒灭一秒
//作者:CSDN-小夏与酒

module led_plus1(
	input			Clk,
	input			Rst_n,
	output	reg		led	
);
	
	reg [26:0]cnt;
	
	parameter cnt_max = 27'd99_999_999;
	parameter cnt_ON = 27'd0;
	parameter cnt_OFF = 27'd49_999_999;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 27'd0;
		else if(cnt == cnt_max)
			cnt <= 27'd0;
		else 
			cnt <= cnt + 1'b1;
	end 
	
	always@(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)
			led <= 1'b1;
		else if(cnt == cnt_ON)
			led <= 1'b0;
		else if(cnt == cnt_OFF)
			led <= ~led;
		else 
			led <= led;	
	end 
	
endmodule

使用上述代码编写led_plus1模块得到的RTL视图如下:
新编写的模块

led_plus2模块的代码没有变化:

/
//模块作用:led亮0.2秒,灭1.8秒
//作者:CSDN-小夏与酒

module led_plus2(
	input 			Clk,
	input 			Rst_n,
	output 	reg	led	
);
	
	reg [26:0]cnt;
	
	parameter cnt_max = 27'd99_999_999;
	parameter cnt_ON = 27'd0;
	parameter cnt_OFF = 27'd9_999_999;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 27'd0;
		else if(cnt == cnt_max)
			cnt <= 27'd0;
		else 
			cnt <= cnt + 1'b1;
	end 
	
	always@(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)
			led <= 1'b1;
		else if(cnt == cnt_ON)
			led <= 1'b0;
		else if(cnt == cnt_OFF)
			led <= ~led;
		else 
			led <= led;	
	end 
	
endmodule

实现效果:
实现效果

四、小项目

把握对定时器的理解和掌握非等占空比信号的产生方法。

在这部分加入两个小项目:使用产生非等占空比信号的思路实现两种类型的流水灯。

🔸项目一

具体要求:流水灯的循环周期为2.5秒,四个LED灯在最初时刻全部点亮,以从左到右或者从右到左的顺序,四个LED灯以0.5秒为间隔依次熄灭。
实现效果:
项目一

项目代码:
📜写法一:

/
//led_prj_01
//CSDN-小夏与酒
/
module led_prj_01(
	input 		Clk,
	input 		Rst_n,
	output reg [3:0]led
);

	reg [26:0]cnt;
	
	parameter cnt_max = 27'd124_999_999;
	parameter cnt_period = 27'd24_999_999;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 27'd0;
		else if(cnt == cnt_max)
			cnt <= 27'd0;
		else 
			cnt <= cnt + 1'b1;
	end
		
	always@(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)
			led <= 4'b0000;
		else if(cnt == 1*cnt_period)
			led <= 4'b1000;
		else if(cnt == 2*cnt_period)
			led <= 4'b1100;
		else if(cnt == 3*cnt_period)
			led <= 4'b1110;
		else if(cnt == 4*cnt_period)
			led <= 4'b1111;
		else if(cnt == 5*cnt_period)
			led <= 4'b0000;
		else 
			led <= led;
	end 

endmodule

对应的RTL视图:
RTL1
📜写法二:

/
//led_prj_01
//CSDN-小夏与酒
/
module led_prj_01(
	input 		Clk,
	input 		Rst_n,
	output reg [3:0]led
);

	reg [26:0]cnt;
	
	parameter cnt_max = 27'd124_999_999;
	parameter cnt_period = 27'd24_999_999;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 27'd0;
		else if(cnt == cnt_max)
			cnt <= 27'd0;
		else 
			cnt <= cnt + 1'b1;
	end
	
	always@(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)
			led <= 4'b0000;
		else begin
			case(cnt)
				1*cnt_period:led <= 4'b1000;
				2*cnt_period:led <= 4'b1100;
				3*cnt_period:led <= 4'b1110;
				4*cnt_period:led <= 4'b1111;
				5*cnt_period:led <= 4'b0000;
				default:led <= led;
			endcase	
		end
	end 

endmodule

对应的RTL视图:
RTL2

注意:
通过上述项目可以看出,if-else语句和case语句虽然可以实现相同的功能,但是它们的RTL视图却是不一样的,即if-else语句和case语句在底层逻辑的实现上是存在差异的,并且case语句的优化效果更好。

🔸项目二

具体要求:流水灯的循环周期为3秒,四个LED灯在最初时刻全部熄灭,以从左到右或者从右到左的顺序,四个LED灯分别以0.25秒0.5秒0.75秒1秒为间隔依次点亮,全部点亮后持续0.25秒
实现效果:
项目二

项目代码:

/
//led_prj_02
//CSDN-小夏与酒
/
module led_prj_02(
	input 		Clk,
	input 		Rst_n,
	output reg [3:0]led
);
	
	reg [27:0]cnt;
	
	parameter cnt_max = 28'd149_999_999;
	parameter cnt_period = 28'd12_499_999;
	
	always@(posedge Clk or negedge Rst_n)begin
		if(!Rst_n)
			cnt <= 28'd0;
		else if(cnt == cnt_max)
			cnt <= 28'd0;
		else 
			cnt <= cnt + 1'b1;
	end
	
	always@(posedge Clk or negedge Rst_n)begin 
		if(!Rst_n)
			led <= 4'b1111;
		else begin
			case(cnt)
				1*cnt_period:led <= 4'b0111;
				3*cnt_period:led <= 4'b0011;
				6*cnt_period:led <= 4'b0001;
				10*cnt_period:led <= 4'b0000;
				11*cnt_period:led <= 4'b1111;
				default:led <= led;
			endcase	
		end
	end

endmodule

对应的RTL视图:
RTLPRJ2

csdn

🧸结尾


评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小夏与酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值