FPGA流水灯的实现

今天是11号,他妈的,有时候我也搞不懂自己为什么要抱着侥幸心理去做这种乱七八糟没有把握的事情。之后只好硬着头皮弄了。总之先把频率计和AD采样给实现了吧

使用Quartus II建立第一个工程

首先要先新建一个文件夹来存放Quartus的工程文件,要注意的是不要怕存在中文路径,如图

doc文件夹用于存放项目相关的文档,par文件夹用于存放Quartus软件的工程文件,rtl文件夹用于存放源代码,sim文件夹用于存放项目的仿真文件。

之后启动Quartus软件

Quartus软件默认由菜单栏、工具栏、工程文件导航窗口、编译流程窗口、主编辑窗口以及信息提示窗口组成。在菜单栏上选择【File】→【New Project Wizard…】来新建一个工程。

新建工程向导说明页面如图,单击NEXT按键进入下一集菜单

第一栏用于指定工程所在的路径(就是之前专门新建的文件夹用来存放工程文件的);

第二栏用于指定工程名,这里建议直接使用顶层文件的实体名作为工程名;

第三栏用于指定顶层文件的实体名。

这里我们设置的工程路径为E:/Verilog/flow_led/par文件夹,工程名与顶层文件的实体名同为Flow_LED。文件名和路径设置完毕后,单击【Next】按钮,可以进入下一个页面

在该页面中,可以通过点击【…】符号按钮添加已有的工程设计文件(Verilog或 VHDL文件),由于这里是一个完全新建的工程,没有任何预先可用的设计文件,所以不用添加,直接单击【Next】按钮进入下一级菜单

这里要根据实际所用的FPGA型号来选择目标器件,我使用的是凌智电子的FPGA开发板主芯片是Cyclone IV E系列的“EP4CE10E22C8”

在“EDA Tool Settings”页面中,可以设置工程各个开发环节中需要用到的第三方EDA工具,比如:仿真工具Modelsim、综合工具Synplify。这里暂不添加任何工具。点击【NEXT】进入下一级菜单

从该页面中,可以看到工程文件配置信息报告,接下来我们点击【Finish】完成工程的创建。

1625994559917

设计输入

​ 这里使用Verilog HDL语言来作为工程的输入设计文件,所以在Design Files一栏中选择Verilog HDL File,然后点击【OK】按钮。

之后就可以看到出现了一个Verilog1.v文件的设计界面,用于输入Verilog代码


流水灯代码的编写

模块的输入与输出定义

module Flow_LED(
        input               sys_clk,              //系统时钟
        input               sys_res_n,          //系统复位,低电平有效

        output reg      [2:0]       led        //定义一个3位的输出寄存器,对应着三个LED灯
);//模块的定义,并且定义了它的输入输出口

这里定义了 LED流水灯模块的 系统时钟输入 和 复位时钟输入 并且也定义了 一个3位的输出寄存器 用于控制LED灯的IO口

这里有个要注意的,模块的名称要与工程的名称相同

always块的定义

always块是用来干什么的?

​ always块是Verilog中用来描述组合逻辑以及时序逻辑的语法。一个设计中可以有多个always块,或者说一定有很多个always块。

​ 这些硬件块都是相互独立同时工作的。每个块之间的连接是决定数据流的原因。为了模拟这种行为,一个always块被做成一个连续的过程(硬件不可能断断续续工作),当敏感列表中的一个信号变化时,它就会被触发并执行一些动作(always块内的语句)。

定时器块

该定时器定时时长为1.5s,由于晶振是50MHz,所以每次时钟上升沿间隔为20ns,而这里需要设计的是每500ms LED灯改变一次,所以以25000000为一个周期,即500ms。

首先需要定义一个32位的计数寄存器

reg     [31:0]      counter;//定义了一个32位的计数器寄存器

这是一个时序逻辑电路,考虑到有时钟的输入,所以要采用非阻塞式幅值

always @(posedge sys_clk or negedge sys_res_n)begin
        if(!sys_res_n)
            counter <= 32'd0;
        else if(counter < 32'd74999999)
                counter <= counter + 1'b1;
        else
                counter <= 32'd0;
end

LED控制块

这是一个时序逻辑电路,考虑到有时钟的输入,所以要采用非阻塞式幅值

always @(posedge sys_clk or negedge sys_res_n)begin
    if(!sys_res_n)                            //当检测到复位信号的时候将所有LED灯熄灭
            led <= 3'b111;
    else if(counter == 32'd24999999)        //当计数值到了25000000,改变一次LED的状态其余同理
            led <= 3'b011;
    else if(counter ==  32'd49999999)
            led <= 3'b101;
       else if(counter ==  32'd74999999)
            led <= 3'b110;
       else
      ;
end

整体代码

module Flow_LED(
        input               sys_clk,              //系统时钟
        input               sys_res_n,          //系统复位,低电平有效

        output reg      [2:0]       led        //定义一个3位的输出寄存器,对应着三个LED灯
);//模块的定义,并且定义了它的输入输出口

reg     [31:0]      counter;//定义了一个24位的计数器寄存器


//main code

//定时器模块
always @(posedge sys_clk or negedge sys_res_n)begin
        if(!sys_res_n)
            counter <= 32'd0;
        else if(counter < 32'd74999999)
                counter <= counter + 1'b1;
        else
                counter <= 32'd0;
end

//LED控制模块
always @(posedge sys_clk or negedge sys_res_n)begin
        if(!sys_res_n)
            led <= 3'b111;
        else if(counter == 32'd24999999)
            led <= 3'b011;
        else if(counter ==  32'd49999999)
            led <= 3'b101;
        else if(counter ==  32'd74999999)
            led <= 3'b110;
        else
        ;
end

endmodule

管脚分配

在程序块编写好了之后还需要再为FPGA分配管脚

双击Location即可为IO口配置管脚,具体管脚参考FPGA开发板的原理图

程序下载

如图所示,首先得设置用于下载的硬件

选择需要下载的文件

选中文件后,连接好USB-Blaster即可开始下载程序,不顾需要注意的是,该程序的下载是存放在SRAM中的,在此过程中如果芯片掉电,程序将不会保存。如何固化程序见另一篇文章。

小结

  1. 要注意的是所有always块是并行运行的,并且要注意阻塞式赋值与非阻塞式的区别
  2. 在描述组合逻辑电路的时候,使用阻塞赋值;在描述时序逻辑电路额的时候,使用非阻塞式赋值。
  3. 刚开始解除FPGA,以LED流水灯为例,这也算是一个工程编写的基本步骤