FPGA——小梅哥视频学习之旅

1.3_8译码器编写

module decoder_3_8(
		input a,
		input b,
		input c,
		output reg [7:0] out
		);
		
	
		always @(*) begin
            case({a,b,c})//注意如何对多个输入进行要求
			3'd0: out = 8'b0000_0001;//这里输入采用十进制,输出采用2进制,方便观察
			3'd1: out = 8'b0000_0010;
			3'd2: out = 8'b0000_0100;
			3'd3: out = 8'b0000_1000;
			3'd4: out = 8'b0001_0000;
			3'd5: out = 8'b0010_0000;
			3'd6: out = 8'b0100_0000;
			3'd7: out = 8'b1000_0000;
			endcase
		end
endmodule
//测试文件编写
`timescale 1ns/1ns  //这个是必须加的,第一个1ns是步进,第二个1ns是精度

module decoder_3_8_tb();

reg t_a;
reg t_b;
reg t_c;
wire [7:0]t_out;

 decoder_3_8 tb(
		 .a(t_a),
		 .b(t_b),
		 .c(t_c),
         .out(t_out)
 );//这里是调用之前写的模块

 initial begin//这里是形成一个从“000”到“111”以“10ns”为间隔的连续输入
 t_a=0;t_b=0;t_c=0;
 #10;
 t_a=0;t_b=0;t_c=1;
 #10;
 t_a=0;t_b=1;t_c=0;
 #10;
 t_a=0;t_b=1;t_c=1;
 #10;
 t_a=1;t_b=0;t_c=0;
 #10;
 t_a=1;t_b=0;t_c=1;
 #10;
 t_a=1;t_b=1;t_c=0;
 #10;
 t_a=1;t_b=1;t_c=1;
 #10;
 $stop;
 
 end
 

endmodule

2.计数器+D触发器(10KHz的闪烁灯,50M的板子频率)

一、模型部分:

  1. 10KHz的闪烁灯,也就是每50us电平翻转一次,因为板子频率为50MHz,则周期为20ns,因此需要计数50us/20ns=2500次以后进行一次电平翻转

  2. 注意“2500-1”的原因,是最后从(2499-0)也需要计数一次,因此需要-1;

  3. 同时counter的位宽需要根据2^n>2500,即n=12可以实现,所以定义[11:0]的counter;

  4. 注意每个always块中尽量只对一个变量操作,方便后续修改和综合;

  5. 注意always块中的赋值对象必须为reg类型,同时赋值必须为“<=”,不可以为“=”

module counter_50M_10K(
		input clk,
		input Reset_n,
		output reg led
 );

reg [11:0] counter;

	always@(posedge clk or negedge Reset_n)
	if(!Reset_n)
		counter <= 0;
		else if(counter == 2500-1)
		counter <=0;
		else
		counter <= counter+1'd1;
		
		
	always@(posedge clk or negedge Reset_n)
	if(!Reset_n)
		led <= 0;
		else if(counter==2500-1)
		led <= ~led;
		else
		led <= led;
		



endmodule

二、测试部分:

  1. 需要写两个信号的测试激励:时钟信号;复位信号
  2. 时钟信号:10ns翻转一次
  3. 复位信号:短暂复位(但是需要包括至少一次翻转,同时要多一点,防止跟clk的上升沿重合),长时间无效(需要包含两个周期差不多)
`timescale 1ns/1ns

module counter_10M_10K_tb;

//需要对两个信号进行测试输入:时钟信号;复位信号
reg clk_t;
reg Reset_n_t;
wire led_t;

	 counter_50M_10K tb(
		.clk(clk_t),
	   .Reset_n(Reset_n_t),
		.led(led_t)
 );
 
 //时钟信号:t=20ns,也就是每10ns翻转一次
 initial clk_t=0;
 always#10 clk_t=~clk_t;
 
 //复位信号:初始电位为0,经过短暂复位后,保持长时间的1
initial begin
Reset_n_t=0;
#21;
Reset_n_t=1;
//因为我们得到的信号是每50us翻转一次,那么我们需要看到两个周期也就是0.2ms=200000ns
#200000;
$stop;
end
 
 
 
 endmodule

3. 8个LED灯50us速率循环跑马灯

通过计数器+LED控制实现;

其中LED控制部分可以有三种方式,分别为:1.移位 2.拼接 3.调用3_8译码器

tb部分与之前同,这里不重复

1.移位

module led_run(
				input clk,
				input rst_n,
				output reg[7:0] led
);

parameter MCN=2500-1;

	reg [24:0] counter;
	
	//计数器部分
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
	counter<=0;
	else if(counter==MCN)
	counter<=0;
	else 
	counter<=counter+1'b1;
	
	//led部分
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
	led<=8'b0000_0001;
	else if(counter==MCN)begin
	
	if(led==8'b1000_0000)
	led<=8'b0000_0001;
	else
	led<=led<<1;
	end


	
	else 
	led <= led;
	
	

endmodule

2.拼接

module led_run2(
				input clk,
				input rst_n,
				output reg[7:0] led
);

parameter MCN=2500-1;

	reg [24:0] counter;
	
	//计数器部分
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
	counter<=0;
	else if(counter==MCN)
	counter<=0;
	else 
	counter<=counter+1'b1;
	
	//led部分
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
	led<=8'b0000_0001;
	else if(counter==MCN)
        led<={led[6:0],led[7]};//这个地方需要理解~
	else 
	led <= led;
	
	

endmodule

3.调用3_8译码器

module led_run3(
				input clk,
				input rst_n,
    			output [7:0] led
    //首先注意led此时不能再为reg类型,因为定义的底层模块decoder中已经声明,因此这里只能是默认wire
);

parameter MCN=2500-1;

	reg [24:0] counter;
	
	//计数器部分
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
	counter<=0;
	else if(counter==MCN)
	counter<=0;
	else 
	counter<=counter+1'b1;
	
	//led部分
	reg [2:0] counter_led;
	always@(posedge clk or negedge rst_n)
	if(!rst_n)
	counter_led<=0;
	else if(counter==MCN)
	counter_led<=counter_led+1'b1;
    //这里的调用不包含在always块中,而是在每次always块之后调用一次,注意always块中是不能调用模块的!!!
	decoder_3_8 led_run(
		.a(counter_led[2]),
		.b(counter_led[1]),
		.c(counter_led[0]),
        .out(led)//注意位次的排布a-2,b-1,c-0
		);
	
	
	
	

endmodule

4.线性序列状态机

1.一个LED灯,先亮0.25s,再灭0.75s

	//基本逻辑在于控制计数时间,从而控制状态变化,将一个长的时间段划分成两个状态
module LED_counter_1(
		input clk,
		input rst_n,
		output reg led

);

		reg [25:0] counter;
		parameter CNM=12500;
		
		//计数器部分
		always@(posedge clk or negedge rst_n )
		if(!rst_n)
		counter<=0;
		else if (counter==(4*CNM)-1)
		counter<=0;
		else
		counter<=counter+1'b1;
		
		//led部分
		always@(posedge clk or negedge rst_n )
		if(!rst_n)
			led<=1'b1;
		else if(counter==CNM-1)
			led<=1'b0;
		else if(counter==(CNM*4)-1)
			led<=1'b1;
		
		
		
endmodule
		
	
			
			

2.一个LED灯,亮0.25s,灭0.75s,亮1.5s,灭2s

//此时加入了多个状态,但是方法与之前相同,这里只是将一个周期变成(0.25+0.75+1.5+2),并划分为四个状态
module LED_counter_2(
				input clk,
				input rst_n,
				output reg led

);
			reg [26:0] counter;
			parameter MCN=12500000;
			
			//计数器
			always@(posedge clk or negedge rst_n)
			if(!rst_n)
				counter<=0;
			else if (counter==MCN*10-1)
				counter<=0;
			else 
				counter<=counter+1'b1;
				
			//led
			always@(posedge clk or negedge rst_n)
			if(!rst_n)
				led<=1;
			else case(counter)
				MCN-1:led<=~led;
				MCN*3-1:led<=~led;
				MCN*6-1:led<=~led;
				MCN*10-1:led<=~led;
				default: led<=led;
				endcase
				
			
			endmodule 

3.一个LED灯,一个周期内有8个状态,这8个状态的亮灭未知(外部输入),每个状态的持续时间为0.25s

//关键在于引入了外部输入来控制灯的亮灭情况,而周期划分还是没变
module LED_counter_3(
					input clk,
					input rst_n,
					input [7:0] ctrl,
					output reg led
);


		reg [26:0] counter;
		parameter MCN=12500000;
		
		//计数器
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			counter<=0;
		else if (counter==MCN*8-1)
			counter<=0;
		else 
			counter<=counter+1;
			
		//led
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			led<=1;
		else case(counter)
			MCN-1:led<=ctrl[7];
			MCN*2-1:led<=ctrl[6];
			MCN*3-1:led<=ctrl[5];
			MCN*4-1:led<=ctrl[4];
			MCN*5-1:led<=ctrl[3];
			MCN*6-1:led<=ctrl[2];
			MCN*7-1:led<=ctrl[1];
			MCN*8-1:led<=ctrl[0];
			default:led<=led;
			endcase
			
		

endmodule 

4.一个LED灯,一个周期内有8个状态,这8个状态的亮灭未知(外部输入),每个状态的持续时间为未知(外部输入)

//关键在于“状态持续时间未知”,此时不方便再进行周期的状态划分,而且需要两个计数器,一个用于每个状态的持续时间计数(counter),一个用于状态次数的计数(8次:counter_time),这里通过counter来控制counter_time的计数即可
module LED_counter_4(
				input clk,
				input rst_n,
				input [7:0] ctrl,
				input [31:0]Time,//已经÷了20
				output reg led
);
		reg [31:0] counter;
		
		//计数器
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			counter<=0;
		else if (counter==Time-1)
			counter<=0;
		else 
			counter<=counter+1;
			
	  reg [2:0] counter_time;//用于状态变化
	  
	   //counter_time:本质在于两段计数器的控制,一段用于控制时间,一段用于控制状态,最后把控制状态的counter给到led来控制即可
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			counter_time<=0;
		else if(counter==Time-1)
			counter_time<=counter_time+1;
		else 
			counter_time<=counter_time;
		
		//led
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			led<=1;
		else case(counter_time)
			3'd0: led<=ctrl[7]; 
			3'd1: led<=ctrl[6]; 
			3'd2: led<=ctrl[5]; 
			3'd3: led<=ctrl[4]; 
			3'd4: led<=ctrl[3]; 
			3'd5: led<=ctrl[2]; 
			3'd6: led<=ctrl[1]; 
			3'd7: led<=ctrl[0]; 
			default:led<=led;
		endcase
	
			
endmodule 

5.一个LED灯,一个周期内有8个状态,这8个状态的亮灭未知(外部输入),每个状态的持续时间为未知(外部输入),且每次经历完一个周期之后进行延缓,延缓的时间与状态时间之和为10ms。

//这里的关键在与延缓的与状态的控制,其实可以将8个状态看作一个整体,再将延缓看作一个整体,通过一个标志位来控制10ms这个大周期内控制状态的计数器的计数情况;
//但是我这里是直接看作9个状态
module LED_counter_5(
				input clk,
				input rst_n,
				input [7:0] ctrl,
				input [31:0]Time,//已经÷了20
				output reg led
);

	parameter MCN=500000;//10ms
		reg [18:0] counter_Per;
		reg [31:0] counter_Time;
		reg [3:0]  counter_Num;
		
		//周期计数器10ms
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			counter_Per<=0;
		else if (counter_Per==MCN-1)
			counter_Per<=0;
		else
			counter_Per<=counter_Per+1;
			
		//状态时间计数器Time
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			counter_Time<=0;
		else if (counter_Time==Time-1)
			counter_Time<=0;
		else
			counter_Time<=counter_Time+1;
		
		//状态次数计数器Num
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			counter_Num<=0;
        else if (counter_Num==4'b1000)//这里变成到9置零
			counter_Num<=0;
		else if (counter_Num==4'b0111) begin
			    if(counter_Per==MCN-1)
					 counter_Num<=counter_Num+1;
				 else
					 counter_Num<=counter_Num;
				 end
		else if (counter_Time==Time-1)
			    counter_Num<=counter_Num+1;
		else
			counter_Num<=counter_Num;
			

			
		//led
		always@(posedge clk or negedge rst_n)
		if(!rst_n)
			led<=0;
		else case(counter_Num)
			4'd0: led<=ctrl[7];
			4'd1: led<=ctrl[6];
			4'd2: led<=ctrl[5];
			4'd3: led<=ctrl[4];
			4'd4: led<=ctrl[3];
			4'd5: led<=ctrl[2];
			4'd6: led<=ctrl[1];
			4'd7: led<=ctrl[0];
			4'd8: led<=0;
			default:led<=led;
		endcase
			

endmodule 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值