FPGA进阶教程四--有限状态机的Verilog实现(已完结)

版权说明:未经许可,不得转载

 

一.目的

1.掌握复杂时序逻辑电路的设计方法

2.了解FPGA中有限状态机的工作原理和实现过程

3.学习用Verilog描述有限状态机的方法。

 

二.工具

1.Digilent Anvyl开发板

2.安装ISE Design Suite软件的PC机一台

3.USB数据线一根

 

三.简单上手实验

1.用Verilog HDL设计并实现一个10101串行序列检查器(可重叠)。

2.设计一个密码锁,检测密码为:30221。要求:以4个按钮作为输入,分别表示输入的数据0、1、2、3;当检测到有效的密码输入时,LED0被点亮。

 

四.实验原理

注:因为这两个实验设计到的代码量相对较多,为了方便后期修改和查看我把实验源码分为了几个部分,最后使用一个顶层文件进行调用处理。

这里给出开发板相关引脚信息和这两个实验的设计思路。

引脚信息:

FPGA进阶教程四--有限状态机的Verilog实现(已完结)_第1张图片
串行序列检测器设计如下:

FPGA进阶教程四--有限状态机的Verilog实现(已完结)_第2张图片
密码锁设计如下:

FPGA进阶教程四--有限状态机的Verilog实现(已完结)_第3张图片

五.实验步骤及结果分析

实验1

设计过程:

1.先对开发板的100Mhz时钟进行分频

2.然后对分频后的时钟进行处理,并获得一个稳定的时钟脉冲

3.画出实验的有限状态机(画的不好看,有强迫症的请不要介意FPGA进阶教程四--有限状态机的Verilog实现(已完结)):

FPGA进阶教程四--有限状态机的Verilog实现(已完结)_第4张图片
根据设计过程,便可写出如下源代码:

 

时钟分频.v

module clk_div(

    input mclk,

    input clr,

    output clk190

    );

 

reg [24:0] q;

 

always@(posedge mclk or posedge clr)

begin

if(clr==1)

q <= 0;

else 

q <= q + 1'b1;

end

 

assign clk190=q[17];

 

endmodule

 

时钟脉冲.v:

module clk_pause(

    input inp,

    input cclk,

    input clr,

    output outp

    );

reg delay1;

reg delay2;

reg delay3;

 

always@(posedge cclk or posedge clr)

begin

if(clr==1)

begin

delay1 <= 0;

delay2 <= 0;

delay3 <= 0;

end

else

begin

delay1 <= inp;

delay2 <= delay1;

delay3 <= delay2;

end

end

 

assign outp = delay1&delay2&~delay3;

 

endmodule

 

有限状态机.v:

module pg2(

    input wire clk,

input wire clr,

input wire din,

output reg dout

    );

reg [2:0] pre_state,next_state;

parameter S0=3'b000,S1=3'b001,S2=3'b010,S3=3'b011,S4=3'b100,S5=3'b101;

always@(posedge clk or posedge clr)

begin

if(clr==1)

pre_state <= S0;

else

pre_state <= next_state;

end

 

always@(*)

begin

case(pre_state)

S0:if(din==1)

next_state <= S1;

else

next_state <= S0;

S1:if(din==0)

next_state <= S2;

else

next_state <= S1;

S2:if(din==1)

next_state <= S3;

else

next_state <= S0;

S3:if(din==0)

next_state <= S4;

else

next_state <= S1;

S4:if(din==1)

next_state <= S5;

else

next_state <= S0;

S5:if(din==1)

next_state <= S1;

else

next_state <= S4;

default:next_state <= S0;

endcase

end

 

always@(*)

begin

if(pre_state==S5)

dout <= 1;

else

dout <= 0;

end

 

endmodule

 

顶层文件.v:

module clk_top(

    input mclk,

    input [2:0] btn,

    output led

    );

 

wire clr,clk190,clkp,btn01;

assign clr=btn[2];

assign btn01 = btn[0]|btn[1];

clk_div U1(.mclk(mclk),

.clr(clr),

.clk190(clk190)

 

);

clk_pause U2(.inp(btn01),

.cclk(clk190),

.clr(clr),

.outp(clkp)

);

pg2 U3(.clk(clkp),

.clr(clr),

.din(btn[1]),

.dout(led)

 

);

 

endmodule

 

.ucf文件:

NET mclk LOC=D11;

NET led LOC=W3;

NET btn<0> LOC=A3;

NET btn<1> LOC=AB9;

NET btn<2> LOC=E6;

 

实验结果截图如下:

FPGA进阶教程四--有限状态机的Verilog实现(已完结)_第5张图片

当输入10101序列(可重叠)后,LED灯亮

 

 

实验2

设计过程和上一题一样,唯一不同的就是该实验的有限状态机,如下:

FPGA进阶教程四--有限状态机的Verilog实现(已完结)_第6张图片
根据设计过程,可写出如下源代码:

 

时钟分频.v:

module clk_div(

    input mclk,

    input clr,

    output clk190

    );

 

reg [24:0] q;

 

always@(posedge mclk or posedge clr)

begin

if(clr==1)

q <= 0;

else 

q <= q + 1'b1;

end

 

assign clk190=q[17];

 

 

endmodule

 

时钟脉冲.v:

module clk_pause(

    input inp,

    input cclk,

    input clr,

    output outp

    );

reg delay1;

reg delay2;

reg delay3;

 

always@(posedge cclk or posedge clr)

begin

if(clr==1)

begin

delay1 <= 0;

delay2 <= 0;

delay3 <= 0;

end

else

begin

delay1 <= inp;

delay2 <= delay1;

delay3 <= delay2;

end

end

 

assign outp = delay1&delay2&~delay3;

 

endmodule

 

 

有限状态机.v:

module pg2(

    input wire clk,

input wire clr,

input wire [3:0] din,

output reg dout

    );

reg [2:0] pre_state,next_state;

parameter S0=3'b000,S1=3'b001,S2=3'b010,S3=3'b011,S4=3'b100,S5=3'b101;

always@(posedge clk or posedge clr)

begin

if(clr==1)

pre_state <= S0;

else

pre_state <= next_state;

end

 

always@(*)

begin

case(pre_state)

S0:if(din[3]==1)

next_state <= S1;

else

next_state <= S0;

S1:if(din[0]==1)

next_state <= S2;

else

next_state <= S0;

S2:if(din[2]==1)

next_state <= S3;

else

next_state <= S0;

S3:if(din[2]==1)

next_state <= S4;

else

next_state <= S0;

S4:if(din[1]==1)

next_state <= S5;

else

next_state <= S0;

default:next_state <= S0;

endcase

end

 

always@(*)

begin

if(pre_state==S5)

dout <= 1;

else

dout <= 0;

end

 

endmodule

 

顶层文件.v:

module clk_top(

    input mclk,

input sw,

    input [3:0] btn,

    output led

    );

 

wire clr,clk190,clkp,btn01;

assign clr=sw;

assign btn01 = btn[0]|btn[1]|btn[2]|btn[3];

clk_div U1(.mclk(mclk),

.clr(clr),

.clk190(clk190)

 

);

clk_pause U2(.inp(btn01),

.cclk(clk190),

.clr(clr),

.outp(clkp)

);

pg2 U3(.clk(clkp),

.clr(clr),

.din(btn),

.dout(led)

 

);

 

endmodule

 

.ucf文件:

NET mclk LOC=D11;

NET led LOC=W3;

NET sw LOC=V5;

NET btn<0> LOC=E6;

NET btn<1> LOC=D5;

NET btn<2> LOC=A3;

NET btn<3> LOC=AB9;

 

实验结果截图如下:

FPGA进阶教程四--有限状态机的Verilog实现(已完结)_第7张图片

上图为输入为30221的正确密码后,LED灯亮

 

六.实验总结

1.本实验的成功要点是要先对原始的100MHz的时钟进行分频和脉冲操作,这样就可以达到防抖的效果。

2.这次的实验可以用两种方法,一种是摩尔状态机,一种是米里状态机。两种方法都是没问题的,但是用不同的方法说对应的实验结果却有一些差异。前者若输入正确,LED则会一直亮着,直到下一个输入;而若后者输入正确,LED则会只闪一下就灭了。大家注意下这点就行了。

 

 

ps:这是最后一篇教程了,今天一下写完两篇,呼~~~心力憔悴啊FPGA进阶教程四--有限状态机的Verilog实现(已完结)FPGA进阶教程四--有限状态机的Verilog实现(已完结)  -----2016.12.02

pps:当志愿者去了,待会再来更    ----2016.12.02

ppps:这两天的志愿者活动太忙了,每天早起晚归,一会宿舍倒床就睡,都没来的及更新。今天终于写完啦!----2016.12.05

 

 

由于笔者的知识和水平有限,文中不足之处在所难免,恳请各位读者赐正

---------------------------------------@weekdawn 版权所有------------------------------------------------

你可能感兴趣的:(计算机大类)