zl程序教程

您现在的位置是:首页 >  后端

当前栏目

重温FPGA开发8

开发 FPGA 重温
2023-09-14 09:09:12 时间

从计数器到可控线性序列机——LED实验进化六部曲

  1. 让LED灯按照亮0.25s,灭0.25s的状态循环亮灭
  2. 让LED灯按照亮0.25s,灭0.25s,亮0.75s,灭1s的状态循环亮灭
  3. 让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以0.25s为一个变化周期,8个变化状态为一个循环
  4. 让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。8个变化状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择
  5. 让多个LED灯按照设置的模式各自在一个变化循环内独立亮灭变化
  6. 每隔10ms,让LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试,比如设置10us)

让LED灯按照亮0.5s,灭0.5s的状态循环亮灭
设计一个计数器,计数周期为0.5s,每当计数周期满,就让LED翻转一次

在这里插入图片描述

让LED灯按照亮0.25s,灭0.25s的状态循环亮灭

counter_led_0.v:

module counter_led_0(
clk,
reset,
led
);

input clk;
input reset;
output reg led;  // 在always块中 所以是reg类型


reg [25:0] counter
parameter MCNT = 50000000;


always@(posedge clk or negedge reset)
if(!reset)
	counter <= 0;
else if(counter == MCNT - 1)
	counter = counter + 1'b1;

always@(posedge clk or negedge reset)
if(!reset)
	led <= 0;
else if(counter == MCNT/2 - 1)  // 这里后面再说,如过MCNT是个变量 后面就会有问题
	led <= 1;
else if(counter == MCNT - 1)
	led <= 0;

endmodule

led_flash_tb.v

module led_flash_tb;
	
	reg clk;
	reg reset;
	wire led;

	counter_led_0
	#(
		.MCNT(50000)
	)

	counter_led_0(
		.clk(clk),
		.reset(reset),
		.led(led)
	)

	initial clk = 1;
	always #10 clk = !clk;
	
	initial begin
		reset = 0;
		#201;
		reset = 1;
		#2000000000;
		$stop;
	end

endmodule


在这里插入图片描述

第一题:

在这里插入图片描述
所以将 这一句话: else if(counter == MCNT/2 - 1) 改成 else if(counter == (MCNT/2+MCNT/4) - 1)

 第一个案例
所以第一个问题解决了!

第二个问题:让LED灯按照亮0.25s,灭0.25s,亮0.75s,灭1s的状态循环亮灭

counter_led_2.v:

module counter_led_2(
clk,
reset,
led
);

input clk;
input reset;
output reg led;  // 在always块中 所以是reg类型


reg [26:0] counter
parameter MCNT = 125000000;


always@(posedge clk or negedge reset)
if(!reset)
	counter <= 0;
else if(counter == MCNT - 1)
	counter = counter + 1'b1;

always@(posedge clk or negedge reset)
if(!reset)
	led <= 1;
else if(counter == MCNT/10 - 1)  // 这里后面再说,如过MCNT是个变量 后面就会有问题
	led <= 0;
else if(counter == (MCNT/10+MCNT/5) - 1)
	led <= 1;
else if(counter == (MCNT/10 + MCNT/5)*2 - 1)
	led <= 0;
else if(counter == MCNT - 1)
	led <= 1;

endmodule

testbench 使用上一个一样的,只需要把文件名修改一下

在这里插入图片描述

第三题:让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。以0.25s为一个变化周期,8个变化状态为一个循环

思考:什么是指定的亮灭模式?8个变化状态可以由用户随机指定。1. 2s为一个循环周期,2. 有一个指定亮灭状态的端口,来指定亮灭
在这里插入图片描述

counter_led_3.v:

module counter_led_3(
clk,
reset,
ctrl,
led
);

input clk;
input reset;
input [7:0] ctrl;
output reg led;  // 在always块中 所以是reg类型


reg [26:0] counter
parameter MCNT = 100000000;


always@(posedge clk or negedge reset)
if(!reset)
	counter <= 0;
else if(counter == MCNT - 1)
	counter = counter + 1'b1;

always@(posedge clk or negedge reset)
if(!reset)
	led <= 0;
// else if(counter == MCNT/8 - 1)  // 这里后面再说,如过MCNT是个变量 后面就会有问题
	//led <= ctrl[0];
//else if(counter == (MCNT*2/8 - 1)
//	led <= ctrl[1];
//else if(counter == (MCNT*3/8 - 1)//
//	led <= ctrl[2];
//else if(counter == (MCNT*4/8 - 1)
//	led <= ctrl[3];
//else if(counter == (MCNT*5/8 - 1)
//	led <= ctrl[4];
//else if(counter == (MCNT*6/8 - 1)
//	led <= ctrl[5];
//else if(counter == (MCNT*7/8 - 1)
//	led <= ctrl[6];
//else if(counter == (MCNT - 1)
//	led <= ctrl[7];

else case(counter)

	MCNT*1/8 - 1; led <= ctrl[0];
	MCNT*2/8 - 1; led <= ctrl[1];
	MCNT*3/8 - 1; led <= ctrl[2];
	MCNT*4/8 - 1; led <= ctrl[3];
	MCNT*5/8 - 1; led <= ctrl[4];
	MCNT*6/8 - 1; led <= ctrl[5];
	MCNT*7/8 - 1; led <= ctrl[6];
	MCNT*8/8 - 1; led <= ctrl[7];
	default: led <= led;
endcase

endmodule

counter_led_3_tb.v:

module led_flash_tb;

	reg clk;
	reg reset;
	reg [7:0]ctrl;
	reg led;

	counter_led_3
	#(
		.MCNT(100000)
	)

	counter_led_2(
		.clk(clk),
		.reset(reset),
		.ctrl(ctrl),
		.led(led)
	)

	initial clk = 1;
	always #10 clk = !clk;

	initial begin
		reset = 0;
		ctrl = 0;
		#201;
		reset = 1;
		#2000;
		ctrl = 8'b10100010;
		#2000000000;
		$stop;
	end

endmodule 

在这里插入图片描述

第四题:让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。8个变化状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择

思考:现在以多少时间为一个周期,未知没有指定。时间值需要用户指定,需要指定parameter
在这里插入图片描述

module counter_led_4(
clk,
reset,
ctrl,
time,
led
);

input clk;
input reset;
input [7:0] ctrl;
input [31:0] time;


output reg led;  // 在always块中 所以是reg类型


reg [31:0] counter


always@(posedge clk or negedge reset)
if(!reset)
	counter <= 0;
else if(counter == Time - 1)
	counter = counter + 1'b1;

reg [2:0] counter2;
always@(posedge clk or negedge reset)
if(!reset)
	counter2 <= 0;
else if (counter == Time - 1)    
	counter2 <= counter2 +1'b1;

always@(posedge clk or negedge reset)
if(!reset)
	led <= 0;
else case(counter2)
	0; led <= ctrl[0];
	1; led <= ctrl[1];
	2; led <= ctrl[2];
	3; led <= ctrl[3];
	4; led <= ctrl[4];
	5; led <= ctrl[5];
	6; led <= ctrl[6];
	7; led <= ctrl[7];
	default: led <= led;
endcase

endmodule

testbench 使用3的 文件,修改文件名即可,还要加入 time的端口,定义一个reg类型的输入

counter_led_4_tb.v:

module led_flash_tb;

	reg clk;
	reg reset;
	reg [7:0]ctrl;
	reg [31:0]time;
	reg led;

	counter_led_4
	#(
		.MCNT(100000)
	)

	counter_led_4 counter_led_4(
		.clk(clk),
		.reset(reset),
		.ctrl(ctrl),
		.time(time),
		.led(led)
	)

	initial clk = 1;
	always #10 clk = !clk;

	initial begin
		reset = 0;
		ctrl = 0;
		time =0;
		#201;
		reset = 1;
		#2000;
		time = 2500;
		ctrl = 8'b10100010;
		#2000000000;
		$stop;
	end

endmodule 

在这里插入图片描述
通过两个计数器嵌套的方式,可以实现指定的时间,设置time的值即可
在这里插入图片描述

第五题:让多个LED灯按照设置的模式各自在一个变化循环内独立亮灭变化

思考:就是多个LED等和第四题相同
在这里插入图片描述
同时控制多个信号。

第六题:每隔10ms,让LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试,比如设置10us)

思考:这是图的解释,每隔10ms。10ms怎么来?执行一次怎么做?
在这里插入图片描述