FPGA实现LED流水灯(开发板为DE2-115)

本次实验所使用的软件有Quartus Prime 18.1和Visual Studio Code,VScode可以实现Verilog代码的语法高亮/自动补全,帮助初学者更快的完成代码编写。

一、软件准备

1.VScode安装

下载地址:Visual Studio Code - Code Editing. Redefined

点击蓝色按钮,下载好后安装即可。

  1. Quartus Prime 18.1和VScode软件的关联

打开 Quartus,点击Tools,选择Options...

在"Text editor"栏中选择Custom,在"Command-line"栏中点击右边三个点,定位到"Code. exe"文件(在VScode安装的文件中),再在后缀上加入-g %f:%l,最后点击OK就完成了两者的关联。

二、LED流水灯的实现

1.流水灯(无按键控制)

新建工程,起名为led,创建Verilog HDL File文件

Verilog代码如下:

复制代码
module led_flow(
    input        clk,     // 50MHz时钟输入
    input        rst_n,   // 复位信号(低电平有效)
    output reg [5:0] led  // 6个LED输出(高电平有效)
);

// 定义1秒计数器(50MHz时钟下需计数50,000,000次)
reg [25:0] counter;

// 计数器逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        counter <= 26'd0;
    end else begin
        counter <= (counter == 26'd49_999_999) ? 26'd0 : counter + 1;
    end
end

// LED移位逻辑(循环左移)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 6'b000001; // 初始状态:第一个LED亮(高电平有效)
    end else if (counter == 26'd49_999_999) begin
        led <= {led[4:0], led[5]}; // 循环左移一位
    end
end

endmodule

在VScode中保存并退出,由于创建文件时自动打开VScode,文件名默认为Verilog1,会与你的module名不同,你可以重新保存为你的module名,然后点击1处,选择Files,右击2处选择Add/Remove...

点击三个点处选择你保存的.v文件,点击Add,点击OK,就成功添加到了项目中

右键点击刚才添加的.v文件,选择Set as...将其设置为顶层实体(创建项目时你设置的顶层实体名和你代码中的一样的话可以不进行这个操作,不然运行会报错)

然后点击编译(此处单纯进行代码编译,检查代码是否错误,整体运行时间较久)点击1或者2处均可,编译成功无报错后点击3处或者在菜单栏点击Assignments->Pin Planner配置引脚

引脚配置如下图所示(红线划掉的不管,是没有的),配置好后退出就行

然后对整个程序进行运行,点击框出的按钮或者点击Processing->Start Compilation

运行成功后进行烧录(板子提前插好电源线和烧录程序的线),点击下图框选的两处均可进行烧录

第一次烧录可先点击Hardware Setup...,然后在Currently...处选择接入的USB线(第一次做的或许会找不到,可能是因为没有安装驱动,打开设备管理器,可以看到Altera USB-Blaster,图标下方有个黄色三角形警告,点击它选择下载驱动就行)

注意1,2处的选择,默认一般是这样,然后就可以点击Start,进度条为100%就成功了

最终效果:

led1

2.流水灯(按键控制开始暂停)

和上面的步骤一样不再过多赘述,就是多了两个按键,引脚配置图如下

代码如下(用deeoseek写的):

复制代码
module led_flow(
    input        clk,      // 50MHz时钟(PIN_Y2)
    input        rst_n,    // 复位信号(PIN_M23,低有效)
    input        key1,     // 启动按键(PIN_M21,按下低电平)
    input        key2,     // 停止按键(PIN_N21,按下低电平)
    output reg [5:0] led   // 高电平有效LED(PIN_E21~G20)
);

// 参数定义
parameter CLK_FREQ = 50_000_000;   // 50MHz时钟
parameter DEBOUNCE_CYCLES = 1_000_000; // 20ms消抖(50MHz*0.02)

// 按键处理模块
reg [1:0] key1_sync, key2_sync;    // 同步寄存器
reg key1_stable, key2_stable;      // 消抖后稳定信号
reg [19:0] key1_cnt, key2_cnt;     // 消抖计数器
reg run_enable;                    // 运行状态标志

// 按键同步与消抖逻辑(低电平有效按键)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        // KEY1初始化
        key1_sync <= 2'b11;
        key1_stable <= 1'b1;
        key1_cnt <= 0;
        // KEY2初始化
        key2_sync <= 2'b11;
        key2_stable <= 1'b1;
        key2_cnt <= 0;
    end else begin
        // KEY1处理(启动)
        key1_sync <= {key1_sync[0], key1};
        if (key1_sync[1] != key1_stable) begin
            key1_cnt <= (key1_cnt == DEBOUNCE_CYCLES) ? 0 : key1_cnt + 1;
            if (key1_cnt == DEBOUNCE_CYCLES) key1_stable <= key1_sync[1];
        end else begin
            key1_cnt <= 0;
        end

        // KEY2处理(停止)
        key2_sync <= {key2_sync[0], key2};
        if (key2_sync[1] != key2_stable) begin
            key2_cnt <= (key2_cnt == DEBOUNCE_CYCLES) ? 0 : key2_cnt + 1;
            if (key2_cnt == DEBOUNCE_CYCLES) key2_stable <= key2_sync[1];
        end else begin
            key2_cnt <= 0;
        end
    end
end

// 控制逻辑(上升沿检测)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        run_enable <= 1'b0; // 初始停止状态
    end else begin
        // KEY1按下(下降沿->低电平)启动
        if (key1_stable && !key1_sync[1]) begin
            run_enable <= 1'b1;
        end
        // KEY2按下(下降沿->低电平)停止
        if (key2_stable && !key2_sync[1]) begin
            run_enable <= 1'b0;
        end
    end
end

// 1秒计数器
reg [25:0] counter;
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        counter <= 0;
    end else if (run_enable) begin
        counter <= (counter == CLK_FREQ-1) ? 0 : counter + 1;
    end
end

// LED移位逻辑
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        led <= 6'b000001;  // 初始状态
    end else if (run_enable && (counter == CLK_FREQ-1)) begin
        led <= {led[4:0], led[5]}; // 左移
    end
end

endmodule

最终效果:

led2

三、总结

本次实验并不难,但在过程中也踩了不少坑,比如流水灯顺序不对,烧录时USB找不到等,每次做实验都会出很多错,但是通过查资料,看不同博主的文章尝试各种方法最后成功还是很开心的。由于Verilog编程不熟悉,在实验中借助了deepseek的帮助,希望以后可以变成直接手搓的不菜鸡。最后博客有什么问题请各位多加指点。

相关推荐
黑不拉几的小白兔11 小时前
stm32:PWM原理 及 呼吸灯实现
stm32·嵌入式硬件·fpga开发
kanhao10017 小时前
【Vitis AIE】FPGA图像处理 11 双线性插值 Bilinear Interpolation
fpga开发·性能优化·边缘计算
我爱C编程19 小时前
基于FPGA的16QAM+帧同步系统verilog开发,包含testbench,高斯信道,误码统计,可设置SNR
fpga开发·verilog·16qam·帧同步·误码统计·高斯信道
早睡身体好~20 小时前
FPGA原型验证,从零开始直到入门全过程
fpga开发·verilog·soc
国科安芯2 天前
汽车芯片成本控制:挑战、策略与未来趋势
嵌入式硬件·fpga开发·汽车
kanhao1002 天前
Super Logic Region (SLR) 在Xilinx FPGA架构
fpga开发·架构
Water_Sounds2 天前
【FPGA开发】Cordic原理推导、Xilinx PG105手册解读
java·开发语言·fpga开发
国科安芯2 天前
从汽车 BCM 方案看国产 MCU 芯片的突围与挑战
嵌入式硬件·fpga开发·架构
kanhao1002 天前
MLIR:高层次综合(HLS)与设计自动化(EDA)的新范式
fpga开发·自动化·mlir