首页 > 代码库 > 永远的流水灯(Verilog)
永远的流水灯(Verilog)
1. 为了更好地学习FPGA和深入理解Verilog语法,首先从最简单的流水灯做起。虽然简单,但是也包含了不少知识。通过这次实验项目,可以了解开发软件的使用及Verilog的编程方法,熟悉模块化设计的方法。
2. 该项目主要实现的功能为:
(1)10位的流水灯
(2)中间两个led灯每隔100ms闪烁一次
(3)两边的led灯每隔100ms流动一下,从中间向两边流水。
3. 具体实现如下
(1)首先定义一个时间计数寄存器counter,每当达到预定的100ms时,计数寄存器就清零,否则的话寄存器就加1。然后计算计数器计数的最大值。时钟频率为50MHZ,也就是周期为1/50M 为20ns,要计数的最大值为T100MS= 100ms/20ns-1 = 4999_999。
代码实现为
always @ (posedge clk or negedge rst)
if(!rst) //高电平复位
counter<=25‘d0;
else if(counter==T100ms)
counter<=25‘d0;
else
counter<=counter+1‘b1;
(2)如何控制led的亮灭呢,无非就是给端口赋高低电平,有的是高电平亮,有的是低电平亮,我用的FPGA学习板为高电平亮。每隔100ms对其端口值取反就可以实现闪烁的led
(3)流水灯的实现。在FPGA中实现流水灯的方法有很多种,我只列取了三种供参考学习。首先是运用FPGA的并行处理特点,建立四个always模块分别对每隔led分别控制,所对应的时序图如图1-a,每一个模块控制相应的led灯,彼此之间互不影响,依靠总的时钟进行工作。
图1-a
这种方法能够充分体现FPGA并行处理的特点,实现起来也很容易。
顶层代码为
moduletop_module(CLK, RSTn, LED_Out);
input CLK;
input RSTn;
output [3:0]LED_Out;
wire LED1_Out;
led1_module U1
(
.CLK(CLK),
.RSTn(RSTn),
.LED_Out(LED1_Out)
);
wire LED2_Out;
led2_module U2
(
.CLK(CLK),
.RSTn(RSTn),
.LED_Out(LED2_Out)
);
wire LED3_Out;
led3_module U3
(
.CLK(CLK),
.RSTn(RSTn),
.LED_Out(LED3_Out)
);
wire LED4_Out;
led4_module U4
(
.CLK(CLK),
.RSTn(RSTn),
.LED_Out(LED4_Out)
);
assign LED_Out = {LED4_Out, LED3_Out,LED2_Out, LED1_Out};
第二种方法为循环移位法。通过给led赋初值,然后循环左移或者循环右移,但是需要设置一个条件。否则就会出现溢出的情况。如图2-a设置一个条件当要出现溢出的时候让它回到初始的状态,这样就可以实现流水了。
图2-a
代码实现为
always @(posedge clk or negedge rst)
if(!rst)
led<=4‘b0001; //初值,最低位led[0]灯亮
else if(counter==T100ms)
begin
if(led==4‘b0000) //当溢出最高位时
led<=4‘b0001; //回到复位时的状态
else
led<=led<<1; //循环左移一位
end
第三种数据拼接法,所谓的数据拼接就把原来的数据拆成一位一位的,在特定位置上拼接上一个数。例如在4位的led的低位拼接一个1. Led[3:0]<={led[2:0],1’b1};接即实现了数据的拼接,当然可以实现任意位,任意bit数的拼。和循环移位类似,数据拼接的实现只是把移位命令改成拼接的命令即可。
永远的流水灯(Verilog)