FPGA入门之三 Verilog实现LED流水灯 计数器+状态机+分频

如果点亮四个LED呢

LED位宽为4,

`timescale 1ns / 1ps
module myled(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)
    led <= 4'b0000;
else
    led <= 4'b1111;
end
endmodule

同样,调整测试tb文件。

wire [3:0] led ;

结果如下:

 

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

代码:

`timescale 1ns / 1ps
module myled(clk,rst_n,led,state);
input clk;
input rst_n;
output reg [3:0]led;
output reg[1:0] state;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
    begin
        led <= 4'b0000;
        state <= 0;
    end
else
    begin
        case (state)
            0:begin    
                led <= 4'b1011;
                state <= 1;
            end
            1:begin    
                led <= 4'b1101;
                state <= 2;
            end
            2:begin    
                led <= 4'b1110;
                state <= 3;
            end
            3:begin    
                led <= 4'b0111;
                state <= 0;
            end
            default:    
                state <= 0;
        endcase
    end
end
endmodule

测试代码:

`timescale 1 ns/ 1 ps
module test_tb();
reg clk;
reg rst_n;                                             
wire [3:0]led;    
wire[1:0] state;             
myled i1 (
	.clk(clk),
	.led(led),
	.rst_n(rst_n),
	.state(state)
);
initial                                                
begin                                                                                            
    $display("Running testbench");      
    clk=0;
    rst_n=0;
    #20 rst_n=1;
end                                                    
always #10 clk=~clk;    
                                                
endmodule

仿真波形

 

(3)设计要点

注意state变量的赋初值。

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

改善方法1:

状态机中增加计数器。

`timescale 1ns / 1ps
module myled(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'b0000;
        state <= 0;
        counter<=0;
    end
else
    begin
        case (state)
            0:begin   
                
                if(counter<12)
                    counter <= counter+1;
                else
                    begin    
                        led <= 4'b1011;
                        state <= 1;
                        counter <=0;
                    end
            end
            1:begin    
                
                if(counter<12)
                    counter <= counter+1;
                else
                    begin  
                        led <= 4'b1101;
                        state <= 2;
                        counter <=0;
                    end
            end
            2:begin    
                
                if(counter<12)
                    counter <= counter+1;
                else
                    begin  
                        led <= 4'b1110;
                        state <= 3;
                        counter <=0;
                    end
            end
            3:begin    
                
                if(counter<12)
                    counter <= counter+1;
                else
                    begin 
                        led <= 4'b0111;
                        state <= 0;
                        counter <=0;
                    end
            end
            default:    
                state <= 0;
        endcase
    end
end
endmodule

测试代码:

`timescale 1 ns/ 1 ps
module myled_tb();
reg clk;
reg rst_n;                                             
wire [3:0]led;            
myled i1 (
	.clk(clk),
	.led(led),
	.rst_n(rst_n)
);
initial                                                
begin                                                                                            
    $display("Running testbench");      
    clk=0;
    rst_n=0;
    #20 rst_n=1;
end                                                    
always #10 clk=~clk;    
                                                
endmodule

波形结果:

 

符合我们的要求。

仔细检查代码,case条件下时,应该直接给赋值,case (state)

即led <= 4'b1011;由原来的位置放在begin:后面,这才符合我们的设计。

0:begin   
    led <= 4'b1011;
    if(counter<12)
        counter <= counter+1;
    else
        begin    
            
            state <= 1;
            counter <=0;
        end
end

仿真波形:

三、分频

问题来了,如上图所示:state 一次是260ns,即counter0~12是260ns,led在counter12的位置,延后了一个节拍变化 。这是因为是寄存器,等于是一个触发器,led输出端等于get输入端 在上升沿来的时候,代码(posedge clk or negedge rst_n),在counter=12的下一个节拍,counter=0,state=1,在state=1的下个clk的上升沿,led更新为1101。

怎么解决??

分频,控制上升沿。

所谓分频,即新增加一个信号,如clk_show,在一个state状态下,完成上升下降时序,从而保证在下一个state变化以后,直接clk_show出现上升沿。即在state开始为1时,clk_show直接为上升沿,从而实现实时变化。即1101和state=1同步。

state一次提到520ns,一个state有两个counter循环,

设计思路:

先设计一个信号,clk_show根据clk和counter计数,13次变化一次,循环一次得26*10ns,再在clk_show上升沿时,变化led和state状态。即并行执行的“always @ ( posedge clk_show or negedge rst_n)”,在clk_show上升沿时,即变化 。

 

module myled2(clk,rst_n,led,state,counter,clk_show);
 
input clk ;
input rst_n ;
output reg [3:0]led ;
 
output reg[1:0] state;
output reg [3:0] counter;
output 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 ns/ 1 ps
module myled2_tb();
reg clk;
reg rst_n;                                            
wire [3:0]led;
wire[1:0] state;
wire [3:0] counter;
wire clk_show;                       
myled2 i1 (
	.clk(clk),
	.led(led),
	.rst_n(rst_n),
	.state(state),
	.counter(counter),
	.clk_show(clk_show)
);
initial                                                
begin                                                  
                                         
$display("Running testbench");      
clk=0;
rst_n=0;
#20 rst_n=1;                
end                                                    
 always #10 clk=~clk;                                                    
endmodule

最多仿真波形:

 

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值