crazybird

【原创】FPGA应用(一)——流水灯

0
阅读(4796)

一、设计需求

    设计一个功能模块使红色飓风E45板上的8盏led灯流动起来,像流水一样。

二、设计思路

    首先,有一点要明确的是led灯的每一次流动都是需要时间间隔的。也就是说,8盏led灯所对应的状态只有经过一段时间延迟后才能发生改变。根据这种思路,在开始设计之前提出两个问题:第一,led灯的状态需要多久发生一次改变;第二,led灯的状态根据什么发生改变。对于第一个问题,可以通过设计计时器来控制时间,如每0.5秒(即2Hz)就产生一个周期的时钟或时钟使能信号;对于第二个问题,led灯的状态可以在生成的2Hz时钟上升沿发生改变,也可以在时钟使能信号下发生改变。但在FPGA设计技巧中推荐同步设计,于是本设计放弃采用产生时钟信号的方案,而是选择时钟使能信号。其对应的时序如图1所示。

1

图1 流水灯时序图

三、设计实现

    在计时器的作用下,每隔0.5秒就产生一个高电平的时钟使能信号cnt_flag,而当检测到时钟使能信号为高电平时,led灯状态led_data发生改变,这样就实现了流水灯的效果。其对应Verilog HDL实现如下所示:

`timescale 1ns/1ps
module water_led(
    rst_n,
    clk,
    led_data
    );
    //  参数定义
    parameter   DATA_WIDTH = 8;                          //  通过修改该参数可应用于led盏数不同的场合
    
    //  端口定义
    input                           rst_n;               //  全局异步复位
    input                           clk;                 //  50MHz
    output reg  [DATA_WIDTH-1:0]    led_data;
    
    //  实现每0.5秒就产生一个时钟使能信号
    parameter   DELAY_CNT = 25'd25_000_000;              //  0.5s
    reg         [24:0]              cnt;                 //  计数器变量
    
    wire    cnt_flag = (cnt==DELAY_CNT-1'b1);            //  时钟使能信号
    
    always @(posedge clk or negedge rst_n)
    begin
        if(rst_n==1'b0)
            cnt <= 0;
        else if(cnt_flag==1'b1)
            cnt <= 0;
        else
            cnt <= cnt + 1'b1;
    end
    
    //  led灯状态的控制
    always @(posedge clk or negedge rst_n)
    begin
        if(rst_n==1'b0)
            led_data <= {{(DATA_WIDTH-1){1'b0}},1'b1};   //  复位初始化
        else if(cnt_flag==1'b1)
            led_data <= {led_data[DATA_WIDTH-2:0],led_data[DATA_WIDTH-1]};  //  左移
        else
            led_data <= led_data;
    end

endmodule

    其modelsim功能仿真如图2所示(为了使仿真节省大量时间,将参数DELAY_CNT改小,如本设计改为DELAY_CNT=25'd250):

2

图2 流水灯modelsim功能仿真

    功能仿真正确之后,便可进行综合(综合之前记得把DELAY_CNT改为25'd25_000_000)、管脚约束、实现、生成bit流、下载到板子,最后可在板子上看到8盏led灯像流水一样流动起来。