FPGA学习altera系列: 第十一篇 流水灯设计

2020-12-29 16:47:13 浏览数 (1)

大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。

今天给大侠带来“FPGA学习系列 altera"系列,持续更新。此学习心得是本人之前所写,所用设计软件为Quartus II 13.1,现Quartus II 新版本已更新到19 ,以下仅供初学者学习参考。后续会更新其他系列,敬请关注。话不多说,上货。

流水灯设计

对于每一个的小实验,我们都可以把它看作是一个小项目,逐步的去分析,设计,调试,最后完成功能。下面我们就开始我们的“小项目”。

项目名称:流水灯。

具体要求:复位时,四个灯全亮。正常工作时,四个灯做流水。每一个灯亮一秒钟。用状态机实现。

状态机的结构如下:

在实际的应用中,根据有限状态机是否使用输入信号,设计人员经常将其分为Moore型有限状态机和Mealy型有限状态机两种类型。

Moore型和Mealy型有限状态机的区别:Moore型有限状态机仅与当前状态有关,而与输入信号无关;Mealy型有限状态机不但与当前状态有关,而且还与状态机的输入信号有关。

Moore状态机是Mealy状态机的一种独特类型。

通过分析上述的“项目名称”和“具体要求”,我们可以设计出如下的架构:

系统设计

1. 工程的名称:ledrun。

2. 在项目中,四个灯做流水,故而设置为四个状态。

3. 用一个计数器,计数一秒钟。

4. 状态转移图如下:

设计代码如下:

代码语言:javascript复制
/*
模块名称:ledrun
模块功能:四个灯做流水,每一个灯亮一秒钟 
作者:郝旭帅
邮箱:746833924@qq.com
*/
module ledrun (clk, rst_n, led);

  input clk;
  input rst_n; //低电平有效

  output reg [3:0] led;

  parameter T1s = 50_000_000;//参数设置

  reg [25:0] count;//计数器(需要计数50M个周期)
  reg [1:0] state;//四个状态

  localparam s0 = 2'b00,//定义四个状态机参数
         s1 = 2'b01,
         s2 = 2'b10,
         s3 = 2'b11;

  always @ (posedge clk or negedge rst_n)
    begin
      if (!rst_n)
        begin
          state <= s0;
          count <= 26'd0;
          led <= 4'b0000;
        end
      else
        begin//状态机的关键字case()···endcase
        case(state) //按照设计的状态转移图进行描述
            s0 : begin
                if (count < T1s - 1)
                  begin
                    led <= 4'b0111;
                    state <= s0;
                    count <= count   1;
                  end
                else
                  begin
                    count <= 0;
                    state <= s1;
                  end
              end

            s1 : begin
                if (count < T1s - 1)
                  begin
                    led <= 4'b1011;
                    state <= s1;
                    count <= count   1;
                  end
                else
                  begin
                    count <= 0;
                    state <= s2;
                  end
              end

            s2 : begin
                if (count < T1s - 1)
                  begin
                    led <= 4'b1101;
                    state <= s2;
                    count <= count   1;
                  end
                else
                  begin
                    count <= 0;
                    state <= s3;
                  end
              end

            s3 : begin
                if (count < T1s - 1)
                  begin
                    led <= 4'b1110;
                    state <= s3;
                    count <= count   1;
                  end
                else
                  begin
                    count <= 0;
                    state <= s0;
                  end
              end

            default : state <= s0;

          endcase
        end
    end

endmodule

解析:

parameter T1s = 50_000_000;参数设置。我们可以在例化时改变它。下板时,我们让参数为50_000_000,仿真时,我们让参数为5.如果仿真50_000_000时间将会很长,我们只做一下简单的验证就可以。

计数器计数为什么到50_000_000 – 1? 我们的本地晶振是50MHz,周期为20ns。如果计数到1秒钟的话,应该需要计50_000_000个数。假设我们要计5个数,从0开始计,那么到4(5-1)就可以了。

下面在激励中,笔者给大家讲解怎么样在例化时改变参数。

激励代码如下:

代码语言:javascript复制
/*
模块名称:ledrun_tb
模块功能:为ledrun模块提供激励信号
作者:郝旭帅
邮箱:746833924@qq.com
*/
`timescale 1ns/1ps

module ledrun_tb;

  reg clk;
  reg rst_n; //低电平有效

  wire [3:0] led;

  parameter T1s = 5;//参数设置(仿真时)

  initial begin
    clk = 1'b1;
    rst_n = 1'b0;
    # 200.1//复位200.1ns

    rst_n = 1'b1;
    # 2000
    $stop;
  end

  always #10 clk = ~clk;//50M

  ledrun #(T1s)//参数传递
    ledrun_dut(
      .clk(clk), 
      .rst_n(rst_n), 
      .led(led)
    );

endmodule

仿真波形如下:

从仿真出来的波形来看,第一:led灯在流水(低电平在流水)。第二:每一个led灯亮5个周期(我们设置的仿真时是5个周期)。

设计正确,下板即可验证。如果小伙伴的电路原理和笔者的不一样,请自行更改设计。如果还是有不明白的小伙伴可以发邮件到我邮箱或者加群询问。

END

制作人:郝旭帅

0 人点赞