FPGA练习(带笔记)

Posted 贩卖星辰点点

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FPGA练习(带笔记)相关的知识,希望对你有一定的参考价值。

目录

板子型号:明德扬点拨开发板,芯片型号EP4CE6E22C8N

1.点灯

module led(
	output wire led0,
	output wire led1,
	output wire led2,
	output wire led3,
);

assign led0=0;
assign led1=0;
assign led2=0;
assign led3=0;


endmodule

2.与或非

module test(
		input				port_a			,	//input只有wire,没有reg
		input				port_b			,	
		input				port_c			,
		
		output	wire		port_d			,	//默认wire,也有reg
		output	wire		port_e			,
		output	wire		port_f			,
		output	wire		port_g			,
		output	wire		port_h			
);

//赋值语句 assign,always
//assign:对wire赋值;awlways:对reg赋值;

assign port_d		=		port_a & port_b;	//与
assign port_e		=		port_a | port_c;	//或
assign port_f		=		~port_a;			//反相器
assign port_g		=		port_b ^ port_c;	//异或
assign port_h		=		port_a ^~ port_c;	//同或
	
endmodule

2.1.TestBench例化模块

`timescale		1ns/1ps			//时间单位/时间精度

module tb_test;

reg			test_a;		
reg			test_b;
reg			test_c;

wire		relt_d;
wire		relt_e;
wire		relt_f;
wire		relt_g;
wire		relt_h;

//initial	赋值的信号,必须定义成reg,固有的规定
//initial用于赋值,/*--*/中的initial方法=begin和end

/*initial	test_a	=		1;		//在0时刻赋初始值
initial	test_b	=		0;
initial	test_c	=		1;*/

initial	begin	//其中begin和end,相当一C语言中的
		test_a	=		1;
		test_b	=		0;
		test_c	=		1;
		#5
		test_a	=		0;
		test_b	=		1;
		test_c	=		1;
		#5
		test_a	=		0;
		test_b	=		0;
		test_c	=		0;
end


test			test_inst(
		.port_a			(test_a		),	//input只有wire,没有reg
		.port_b			(test_b		),	
		.port_c			(test_c		),
				
		.port_d			(relt_d		),	//默认wire,也有reg
		.port_e			(relt_e		),
		.port_f			(relt_f		),
		.port_g			(relt_g		),
		.port_h			(relt_h		)
);


endmodule

2.2.modelsim波形

3.嵌套

module	switch(
		input				sel_a		,
		input				sel_b		,		
		input				data_a		,
		input				data_b		,
		
		output	reg			data_c	
);
//wire--->assign	赋值

//assign	data_c	=		(sel ==	0) ? data_a	: data_b	;

//值=(条件)?结果1:结果2		C语言
//assign	目标信号=(判断表达式)?判断表达式为真时执行 : 判断表达式为假时执行	;


//assign	data_c	=	(sel_a == 0) ? ((sel_b == 0) ? data_a : 0) : ((sel_b == 1)? data_b : 0)	;

//assign:对wire赋值;awlways:对reg赋值;


//()---敏感信号列表,需要将always中用到的信号全部写进去
always	@(sel_a or sel_b or data_a or data_b)	begin		//*---可以匹配到()内部的所有信号,可以直接替换
		if(sel_a == 0)
			if(sel_b == 0)
					data_c =		data_a;
			else
					data_c =		0;
		else 							//可忽略if(sel_a == 1)	//sel_a==1;
			if(sel_b == 1)
					data_c =		data_b;
			else
					data_c =		0;

end

endmodule

3.1.TestBench例化模块

`timescale		1ns/1ns

module	tb_switch;

	reg		sel_a;
	reg		sel_b;
	reg		data_a;
	reg		data_b;	
	wire	data_c;
	
	
initial	begin
	sel_a	=	0;
	sel_b	=	0;
    data_a  =	0;
    data_b  =	1;
	#5
	sel_a	=	1;
	sel_b	=	0;
    data_a  =	0;
    data_b  =	1;
	#5
	sel_a	=	0;
	sel_b	=	1;
    data_a  =	1;
    data_b  =	0;
	#5
	sel_a	=	1;
	sel_b	=	1;
    data_a  =	1;
    data_b  =	0;
end

switch		switch_inst(
		.sel_a				(sel_a	)	,
		.sel_b				(sel_b	)	,		
		.data_a				(data_a	)	,
		.data_b				(data_b	)	,
		.data_c				(data_c	)		
);

endmodule

3.2.modelsim波形

4.三八译码器

module	decode(
		input			[2:0]	pi_data	,		//[]表示位宽,可以理解为有多少根线		
		/*input	pi_A1	,
		input	pi_A2	,*/
		output	reg		[7:0]	po_data	

);

always	@(*)	begin
		case(pi_data)
			0:	po_data	=	8'b0000_0001	;		//1;	
			1:	po_data	=	8'b0000_0010	;		//2;	
			2:	po_data	=	8'b0000_0100	;		//4;	
			3:	po_data	=	8'b0000_1000	;		//8;	
			4:	po_data	=	8'b0001_0000	;		//16;	
			5:	po_data	=	8'b0010_0000	;		//32;	
			6:	po_data	=	8'b0100_0000	;		//64;	
			7:	po_data	=	8'b1000_0000	;		//128;

			default:po_data	=	8'b0000_0001	;
			//8'b1000_0000	8-->表示位宽,b-->表示二进制,这里的下划线只是为了方便标识二进制,对代码本身并没有影响
			//	d-->十进制	;h-->十六进制	;o-->
			
			
			//直接写数字,为十进制,位宽默认为32bit
		endcase
		
		
		/*if(pi_data == 0)
					po_data =	1;
		else if(pi_data == 1)
					po_data =	2;
		else if(pi_data == 1)
					po_data =	2;
		else if(pi_data == 1)
					po_data =	2;
		else if(pi_data == 1)
					po_data =	2;*/
end 


endmodule

4.1.TestBench例化模块

`timescale		1ns/1ns

module	tb_decode;
	reg		[2:0]	pi_data	;
	
	wire	[2:0]	po_data	;
	
initial	begin
	pi_data	=	0;
	#5
	pi_data	=	1;
	#5
	pi_data	=	2;
	#5
	pi_data	=	3;
	#5
	pi_data	=	4;
	#5
	pi_data	=	5;
	#5
	pi_data	=	6;
	#5
	pi_data	=	7;
	
end

decode		decode_inst(
		.pi_data		(pi_data),			
		
		.po_data		(po_data)
);

endmodule

5.LED闪烁

module	flash(
		input	sclk	 ,		//system clock
		input	s_rst_n	 ,		//system reset	,	active low
		
		output	reg		[3:0]	led		
);

//50MHz
//T=100/5=20ns

reg		[25:0]	cnt	;		//counter

//50_000_000-1=49_999_999
//0-49_999_999 0

//always用时钟沿进行工作,<=赋值


always	@(posedge sclk or negedge s_rst_n)	begin
	if(s_rst_n == 1'b0)
		cnt	<=	'd0		   ;
	else if(cnt	== 'd49_999_999)
		cnt	<=	'd0	   	   ;
	else
		cnt	<=	cnt	+ 1'b1 ;		
end

//0--1--0--1--0

always	@(posedge sclk or negedge s_rst_n)	begin
	if(s_rst_n == 1'b0)
		led	<=	4'b0000	;
	else if(cnt == 'd49_999_999)
		led	<=	~led	;
end

endmodule

5.1.TestBench例化模块

`timescale		1ns/1ns

module	tb_flash;

	reg			sclk	;		
	reg			s_rst_n	;
	
	wire	[3:0] 	 led;
	
initial	begin
	sclk	=	1	;
	s_rst_n	<=	0	;
	#100
	s_rst_n	<=	1	;	
end


always	#5	sclk =	~sclk	;		//高低电平转换

flash		flash_inst(
		.sclk		 (sclk		)	,		
		.s_rst_n	 (s_rst_n	)	,		
		.led		 (led		)
);

endmodule

5.2.modelsim波形

6.阻塞,非阻塞;组合,时序

`timescale		1ns/1ns

module	tb_ex;
		reg		a;
		reg		b;
		reg		c;
		reg		d;
		reg		e;
		reg		f;


initial	begin			//阻塞赋值:依次顺序执行
	a	=		0;
	b	=		1;
	c	=		a+b;

end

initial	begin			//非阻塞赋值:每次信号的实现,都在执行时间的最后一刻,在这之前没有信号,而这里的最后一个信号f,在modelsim中因为时间和显示的问题,会导致信号f,显示未定义

//总结一下就是,非阻塞赋值有延迟
	d	<=		0;
	e	<=		1;
	f	<=		d+e;

end

//	=	多用于组合逻辑电路
//	<=	多用于数据逻辑电路

//时序逻辑和组合逻辑之间的区分,是否使用时钟沿。

endmodule



6.1.modelsim波形

7.流水灯

module	shift(
	input	sclk		,
	input	s_rst_n		,
	
	input	[3:0]	led	
);

	localparam		delay_1s	=	'd49	;

	reg		[25:0]	cnt	;
	
always	@(posedge sclk	or	negedge	s_rst_n)	begin
	if(s_rst_n	==	1'b0)
			cnt		<=	'd0	;
		
	else if(cnt	==	delay_1s)
			cnt		<=	'd0	;
	else
			cnt		<=	cnt+1'b1 ;
			
end

always	@(posedge sclk or negedge s_rst_n)	begin
	if(s_rst_n	==	1'b0)
			led		<=		4'b1110	;
			
	else if(cnt	==	delay_1s)				//1110	=>	110,1	循环	位移操作
			led	<=	led[2:0],led[3]; 

end

endmodule

7.1.TestBench例化模块

`timescale		1ns/1ns

module	tb_shift;

	reg	sclk;
	reg	s_res_n;
	
	wire	[3:0]	led;	

initial	begin
	sclk	=	1;
	s_res_n	<=	0;
	#100
	s_res_n	<=	1;

end	

always	#5	sclk	=	~sclk	;

shift		shift_inst(
	.sclk			(sclk				),	
	.s_res_n		(s_res_n			), 
    .led			(led				)
);


endmodule

8.呼吸灯

module	breath(
	input			sclk	,
	input			s_rst_n	,
	
	output	reg		[3:0]	led	
	
);

	localparam	delay_2us	=	'd99	;
	localparam	delay_2ms	=	'd999	;
	localparam	delay_2s	=	'd999	;
	
	reg	[7:0]	cnt_2us	;
	reg	[9:0]	cnt_2ms	;
	reg	[9:0]	cnt_2s	;
		
always	@(posedge sclk or negedge s_rst_n)	begin
	if(s_rst_n == 1'b0)
									cnt_2us	<=	'd0;
	else if(cnt_2us == delay_2us)
									cnt_2us	<=	'd0;
	else
									cnt_2us	<=	cnt_2us+1'b1;
end

always	@(posedge sclk or negedge s_rst_n)begin
	if(s_rst_n	==	1'b0)
											cnt_2ms	<=	'd0	;
	else if(/*cnt_2ms == delay_2ms  && */ cnt_2us == delay_2us)
											cnt_2ms	<=cnt_2ms+1'b1;
	else if(cnt_2ms == delay_2ms/*cnt_2us == delay_2us*/)
											cnt_2ms	<= 'd0;
end


always	@(posedge sclk or negedge s_rst_n)	begin
	if(s_rst_n	==	1'b0)
		cnt_2s	<=	'd0	;
	else if(/*cnt_2s == delay_2s	&&	cnt_2us == delay_2us && */cnt_2ms == delay_2ms)
		cnt_2s	<=	cnt_2s+1'b1;
	else if(cnt_2s == delay_2s	/*&&	cnt_2us == delay_2us*/)
		cnt_2s	<= 	'd0	;
end

always	@(posedge sclk or negedge s_rst_n)	begin
	if(s_rst_n	==	1'b0)
		led <= 4'b1111;
	else if(cnt_2s >= cnt_2ms)
		led <= 4'b0000;
	else 
		led <= 4'b1111;
end

endmodule

8.1.TestBench例化模块

`timescale	1ns/1ns
module	tb_breath;
	reg		sclk	;
	reg		s_rst_n	;
	
	wire	[3:0]	led;
	
initial	begin
	sclk		=	1	;
	s_rst_n		=	0	;
	#100
	s_rst_n		<=	1	;
end

always	#5	sclk	=	~sclk	;

breath		breath_inst(
	.sclk					(sclk		),
	.s_rst_n				(s_rst_n	),
	.led					(led		)
);
endmodule

8.2.modelsim波形

8.3.呼吸灯原理

FPGA中,控制输出只能输出 0 或 1 ,要想实现呼吸灯只能依靠PWM波控制电压输出实现,
上边代码中,假设给led一个2s的时间,先把这2s分为1000个2ms等份,在这个基础上再把2ms再分为1000个2us等份,(这里主要是为了在开发板上方便我们观察led的变化),呼吸灯的闪烁规律是,慢慢变亮。所以在一千个ms时间段中,我们让他一段一段的变亮,规律如下图,依照这样的规律我们就可以实现呼吸灯

然后开发板上的晶振是50Hz,对应输出时间为20ms,即100us,代码中用计时器实现这个规律就是2us从0–99,然后2ms+1,2ms从0–999,2s+1,led先不亮,然后设置一个if条件,实现led灯随时间的亮灭,综上所述,就用FPGA实现了呼吸灯效果

以上是关于FPGA练习(带笔记)的主要内容,如果未能解决你的问题,请参考以下文章

FPGA练习(带笔记)

明德扬FPGA模块划分方法1(转)

FPGA培训专家 V3学院带你学习 按键消抖 和 边缘检测

一个神奇多功能的FPGA设计模板!!

fpgaip核最多

FPGA培训专家 V3学院带你学习 使用modesim仿真工具