FPGA学习(第3节)-Verilog实现LED流水灯+基础入门语法+Modelsim仿真技巧+计数器+状态机+分频

FPGA设计的一个难点,就是设计技巧和规则的掌握,下面来看一个简单例子的实现过程,作为初级入门案例。

一、按键按下实现LED点亮

当LED引脚输出低电平时LED点亮,

(1)代码实现如下

module test(clk,rst_n,led);

input clk ;
input rst_n ;
output reg led ;

always @ ( posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			led<=0;
		end
	else
	begin
			led<=1;
	end
end
endmodule


(2)基础语法要点

在always里面被赋值必须是reg变量。

凡是在时序电路中被赋值的变量 必须是非阻塞赋值。always @ ( posedge clk or negedge rst_n)

凡是在组合电路中被赋值的变量 必须是阻塞赋值always @ ( *)

(3)Modelsim仿真测试文件。

`timescale 1 ps/ 1 ps
module test_tb();
reg clk;
reg rst_n;                                             
wire led;                 
test i1 (
	.clk(clk),
	.led(led),
	.rst_n(rst_n)
);
initial                                                
begin                                                                                            
$display("Running testbench");      
clk=0;
rst_n=0;
#1000 rst_n=1;
end                                                    
always #10 clk=~clk;                                                    
endmodule
测试文件设计要点(点击生成测试文件)

  • 输入都改为reg(系统产生)
  • 输出都改为wire:连线(系统产生)
  • 实例化模块并连接导线。(系统产生)
  • initial中初始化变量。(自己修改)
  • always产生时钟。(自己修改)

(4)Modelsim仿真

仿真中常用命令:

do wave.do

restart

run 0.1ms

(5)如果点亮四个LED呢?

改变led输出变量的位宽:

module test(clk,rst_n,led);

input clk ;
input rst_n ;
output reg [3:0]]led ;

always @ ( posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			led<=4'b1111;
		end
	else
	begin
			led<=4'b0000;
	end
end
endmodule

同样改变测试文件位宽

wire [3:0] led ;

二、状态机设计实现流水灯

(1)模块代码

reg[1:0] state;

module test(clk,rst_n,led);

input clk ;
input rst_n ;
output reg [3:0]led ;

reg[1:0] state;

always @ ( posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			led<=4'b1111;
			state<=0;
		end
	else
	begin
		case(state)
			0:begin
				led<=4'b0111;
				state<=1;
			end
			1:begin
				led<=4'b1011;
				state<=2;			
			end
			2:begin
				led<=4'b1101;	
				state<=3;				
			end
			3:begin
				led<=4'b1110;
				state<=0;			
			end
			default: 
				state<=0;
			endcase
	end
end
endmodule

(2)状态机正确仿真:



(3)设计要点

注意state变量的赋初值。

(4)频率反转太快、看不出LED效果。

改善方法1:

状态机中增加计数器。

module test(clk,rst_n,led);

input clk ;
input rst_n ;
output reg [3:0]led ;

reg[1:0] state;
reg [3:0] counter;
always @ ( posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			led<=4'b1111;
			state<=0;
			counter<=0;
		end
	else
	begin
		case(state)
			0:begin
				led<=4'b0111;
				if(counter<12)
					counter<=counter+1;
				else
					begin
						counter<=0;
						state<=1;
					end
			end
			1:begin
				led<=4'b1011;
				if(counter<12)
					counter<=counter+1;
				else
					begin
						counter<=0;
						state<=2;
					end		
			end
			2:begin
				led<=4'b1101;	
				if(counter<12)
					counter<=counter+1;
				else
					begin
						counter<=0;
						state<=3;
					end				
			end
			3:begin
				led<=4'b1110;
				if(counter<12)
					counter<=counter+1;
				else
					begin
						counter<=0;
						state<=0;
					end			
			end
			default: 
				state<=0;
			endcase
	end
end
endmodule


12的时候应该反转为什么延时一个周期呢?

因为是寄存器,等于是一个触发器,Q输出端等于get输入端 在上升沿来的时候

改善方法2:

分频,控制上升沿。

module test(clk,rst_n,led);

input clk ;
input rst_n ;
output reg [3:0]led ;

reg[1:0] state;
reg [3:0] counter;
reg clk_show;

always @ ( posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
			clk_show<=0;
			counter<=0;
		end
	else
		if(counter<12)
			counter<=counter+1;
		else
			begin
				counter<=0;			
				clk_show=~clk_show;
			end
end

always @ ( posedge clk_show or negedge rst_n)
begin
	if(!rst_n)
		begin
			led<=4'b1111;
			state<=0;
		end
	else
	begin
		case(state)
			0:begin
				led<=4'b0111;
				state<=1;
			end
			1:begin
				led<=4'b1011;
				state<=2;	
			end
			2:begin
				led<=4'b1101;	
				state<=3;			
			end
			3:begin
				led<=4'b1110;
				state<=0;	
			end
			default: 
				state<=0;
			endcase
	end
end
endmodule


测试:

`timescale 1 ps/ 1 ps
module test_tb();
// constants                                           
// general purpose registers
// test vector input registers
reg clk;
reg rst_n;
// wires                                               
wire [3:0]led;

// assign statements (if any)                          
test i1 (
// port map - connection between master ports and signals/registers   
	.clk(clk),
	.led(led),
	.rst_n(rst_n)
);
initial                                                
begin                                                  
// code that executes only once                        
// insert code here --> begin                          
                                                       
// --> end                                             
$display("Running testbench");      
clk=0;
rst_n=0;
#1000 rst_n=1;
                 
end                                                    

 always #10 clk=~clk;                                                    
endmodule


(5)设计要点:

同一变量不能同时在两个always块内复制,如分频和状态机的两个always块,复位时复位什么变量由本块内用到的变量决定。

基础十分重要,是FPGA设计的前提。通过以上学习我们学会了状态机  计数器  时钟分频电路的设计。

以上代码中包含了分频,LED状态机等多个功能模块。

下一节我们来讲这个程序改善为:层次化设计自顶向下的设计模式。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页