FPGA实现LED流水灯

发布于:2025-04-15 ⋅ 阅读:(25) ⋅ 点赞:(0)

目录

一、VScode以及Verilog-HDL/SystemVerilog插件安装下载

1.1 VScode下载安装

1.2 HDL/SystemVerilog插件安装下载

二、LED流水灯

三、模块化代码

四、总结


一、VScode以及Verilog-HDL/SystemVerilog插件安装下载

1.1 VScode下载安装

官网: 下载地址

在首页找到对应的版本(Windows)点击下载

双击下载好的安装包,弹出以下界面,点击我同意此协议,下一步

接下来就是选择安装路径,默认是安装在C盘,点击浏览可以选择自己的安装路径,下一步

继续下一步,这里选择自己想要的功能,下一步

点击安装,开始安装VScode

1.2 HDL/SystemVerilog插件安装下载

安装好之后,在VScode的商店中搜索Verilog,安装插件

下载、安装完成之后,可以实现Verilog代码的语法高亮和自动补全

二、LED流水灯

在DE2-115开发板上,用Verilog设计一个LED流水灯实验:用6个LED完成周期为1秒的跑马灯效果

代码如下

module led_test #(parameter TIME_1S = 50_000_000)(
    input               sys_clk     ,
    input               sys_rst_n   ,
    output  reg [5:0]   led         // 控制 6 个 LED
);
    reg     [25:0]      cnt     ;   // 增加位宽以支持更大的计数值
    wire                add_cnt ;
    wire                end_cnt ;
    reg     [2:0]       cnt1;
    wire                add_cnt1;
    wire                end_cnt1;
​
    always @(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n) begin
            cnt <= 26'b0;
        end
        else if(add_cnt) begin
            if(end_cnt) begin
                cnt <= 26'b0;
            end
            else begin
                cnt <= cnt + 1'b1;
            end
        end
        else begin
            cnt <= cnt;
        end
    end
​
    // 异步复位
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)begin
            cnt1 <= 3'b0;
        end
        else if(add_cnt1) begin
            if(end_cnt1)begin
                cnt1 <= 3'b0;
            end
            else begin
                cnt1 <= cnt1 + 1'b1;
            end
        end
    end
    always @(posedge sys_clk or negedge sys_rst_n)begin
        if(!sys_rst_n)begin
            led <= 6'b0;
        end
        else begin
            case (cnt1)
                3'b000 : led <= 6'b000001; // 第 1 个灯亮
                3'b001 : led <= 6'b000010; // 第 2 个灯亮
                3'b010 : led <= 6'b000100; // 第 3 个灯亮
                3'b011 : led <= 6'b001000; // 第 4 个灯亮
                3'b100 : led <= 6'b010000; // 第 5 个灯亮
                3'b101 : led <= 6'b100000; // 第 6 个灯亮
                default: led <= led;       // 保持当前状态
            endcase
        end
    end
​
    assign add_cnt = 1'b1;
    assign end_cnt = add_cnt && cnt == TIME_1S - 1;
    assign add_cnt1 = (cnt == TIME_1S-1);
    assign end_cnt1 = add_cnt1 && cnt1 == 3'b101; // 6 个状态(0 到 5)
endmodule
  • 计数器cnt

    用于计时,控制每个LED状态的持续时间;当cnt计数到TIME_1S-1时,表示1秒时间到,触发状态切换。

  • 计数器cnt1

    用于记录当前 LED 的状态(即哪个 LED 亮);当 cnt 计数到 TIME_1S - 1 时,cnt1 加 1,切换到下一个状态;

    cnt1是一个 3 位宽的寄存器,可以表示 8 个状态(3'b0003'b111);在本设计中,只使用了 6 个状态(3'b0003'b101),分别对应 6 个 LED 的状态;每个状态持续 1 秒,由 cnt 计数器控制。

    cnt 计数到 TIME_1S - 1 时,cnt1 加 1,切换到下一个状态;当 cnt1 达到 3'b101(即第 6 个状态)时,cnt1 复位为 3'b000,重新开始循环。

引脚配置

实验效果如下:

三、模块化代码

顶层模块代码(LedBlink.v)

module LedBlink (
    input  wire clk,       // 系统时钟(50 MHz)
    input  wire rst_n,     // 复位信号(低电平有效)
    output wire [5:0] led  // 6 个 LED 输出
);
​
    wire clk_1s; // 1 Hz 时钟信号
​
    // 实例化分频模块
    fenpin u_fenpin (
        .clk(clk),
        .rst_n(rst_n),
        .clk_1s(clk_1s)
    );
​
    // 实例化显示模块
    display u_display (
        .clk_1s(clk_1s),
        .rst_n(rst_n),
        .led(led)
    );
​
endmodule

实例化分频模块和显示模块,并将它们连接起来;提供系统时钟、复位信号和LED输出的接口

分频模块(fenpin.v)

module fenpin (
    input  wire clk,       // 系统时钟(50 MHz)
    input  wire rst_n,     // 复位信号(低电平有效)
    output reg  clk_1s     // 分频后的 1 Hz 时钟信号
);
​
    reg [25:0] cnt; // 26 位计数器,用于分频
​
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt <= 26'd0;
            clk_1s <= 1'b0;
        end
        else if (cnt == 26'd49_999_999) begin // 50 MHz / 50,000,000 = 1 Hz
            cnt <= 26'd0;
            clk_1s <= ~clk_1s; // 翻转时钟信号
        end
        else begin
            cnt <= cnt + 1'b1;
        end
    end
​
endmodule

将50MHz的系统时钟分频为1Hz的时钟信号,通过一个26位计数器实现分频

显示模块(display.v)

module display (
    input  wire clk_1s,    // 1 Hz 时钟信号
    input  wire rst_n,     // 复位信号(低电平有效)
    output reg  [5:0] led  // 6 个 LED 输出
);
​
    reg [2:0] state; // 状态寄存器,用于表示当前 LED 状态
​
    always @(posedge clk_1s or negedge rst_n) begin
        if (!rst_n) begin
            state <= 3'b000;
            led <= 6'b000001; // 初始状态:第 1 个 LED 亮
        end
        else begin
            case (state)
                3'b000 : led <= 6'b000001; // 第 1 个 LED 亮
                3'b001 : led <= 6'b000010; // 第 2 个 LED 亮
                3'b010 : led <= 6'b000100; // 第 3 个 LED 亮
                3'b011 : led <= 6'b001000; // 第 4 个 LED 亮
                3'b100 : led <= 6'b010000; // 第 5 个 LED 亮
                3'b101 : led <= 6'b100000; // 第 6 个 LED 亮
                default: led <= 6'b000001; // 默认回到第 1 个 LED
            endcase
            state <= state + 1'b1; // 切换到下一个状态
            if (state == 3'b101) begin
                state <= 3'b000; // 回到初始状态
            end
        end
    end
​
endmodule

根据1Hz的时钟信号,控制6个LED的流水灯效果,使用一个3位状态机表示当前LED状态

四、总结

本次实验学习了Verilog硬件描述语言的基本语法和模块化设计方法,学习使用计数器实现定时功能,并通过状态机控制LED流水灯的效果,计数器用于实现1秒的定时状态,状态机用于控制LED灯的状态切换,代码编写完成后在DE2-115开发板上下载烧录程序,实现“跑马灯”效果,不仅加深了对Verilog语言的理解,还培养了硬件设计的规范化思维。


网站公告

今日签到

点亮在社区的每一天
去签到