当前位置: 首页 > article >正文

FPGA 23 ,使用 Vivado 实现花式跑马灯( 使用 Vivado 实现花式流水灯,采用模块化编程,从按键消抖到LED控制 )

目录

前言
一. 模块化设计介绍
二. 模块设计
1. 按键消抖模块 (key.v)
模块功能:
注意事项:
2. LED控制模块 (led.v)
模块功能:
注意事项:
3. 模块工作流程
三. 模块化设计优势
四. 本文总结
五. 更多操作

前言

在FPGA开发中,跑马灯和流水灯是最基础且常见的实验项目之一。通过跑马灯和流水灯的设计,我们可以熟悉FPGA的基本开发流程、Verilog语言的使用以及模块化编程的思想。之前介绍过基本的跑马灯和流水灯的实现,这里将详细介绍如何使用Verilog语言,实现一个花式跑马灯和流水灯的设计,并通过模块化编程的方式,将按键消抖模块与LED控制模块分离,提升代码的可读性和可维护性(流水灯就是跑马灯)。

先看下使用模块化实现的花式跑马灯效果,当按下K2按键时,LED灯从右向左依此亮起,再次按下时LED灯从左向右依此亮起:

一. 模块化设计介绍

模块化设计是FPGA开发中非常重要的思想。通过将系统功能划分为多个独立的模块,每个模块负责完成特定的功能,可以显著提高代码的可读性、可维护性和可复用性。在本项目中,我们采用了模块化设计,将系统分为以下两个主要模块:

  1. 按键消抖模块 (key.v):负责检测按键的稳定状态,消除机械按键的抖动问题。

  2. LED控制模块 (led.v):负责根据按键状态切换LED的显示模式,实现跑马灯和流水灯效果。

通过模块化设计,我们可以将复杂的功能分解为简单的子模块,每个子模块独立开发、测试和优化,最后通过模块例化的方式将各个子模块组合成一个完整的系统。


二. 模块设计

1. 按键消抖模块 (key.v)

按键消抖模块用于检测按键的稳定状态。由于机械按键在按下和释放时会产生抖动,直接读取按键状态可能会导致误触发。因此,按键消抖模块通过延时计数的方式,确保按键状态稳定后再输出。

module key(
    input       clk,        // 时钟信号
    input       rst_n,      // 复位信号,低电平有效
    input       key,        // 按键输入信号
    output      flag        // 按键稳定状态标志,1表示按键稳定按下
);

parameter delay = 50_000;   // 消抖延时计数,根据时钟频率调整
reg [18:0] cnt;             // 计数器,用于延时

always @(posedge clk) begin
    if (!rst_n)             // 复位时计数器清零
        cnt <= 0;
    else if (key == 0) begin // 按键按下时开始计数
        if (cnt == delay - 1)
            cnt <= cnt;     // 计数达到最大值时保持
        else
            cnt <= cnt + 1; // 计数加1
    end else
        cnt <= 0;           // 按键释放时计数器清零
end

assign flag = (cnt == delay - 2) ? 1 : 0; // 当计数接近最大值时,输出稳定标志

endmodule

该模块(key.v)旨在解决机械按键的抖动问题,确保按键信号的稳定性。它通过一个计数器检测按键是否稳定按下一段时间(如1毫秒),从而输出一个稳定的标志位 flag 表示按键已被有效触发。此模块接收系统时钟 clk、复位信号 rst_n 和按键输入 key,为后续逻辑提供可靠的按键状态。

模块功能:
  1. 检测按键的稳定状态,消除抖动。

  2. 输出flag信号,表示按键是否稳定按下。

注意事项:
  1. delay参数需要根据实际的时钟频率进行调整,以确保消抖时间足够长。

  2. 按键消抖模块的输出flag在按键稳定按下时为1,否则为0。

2. LED控制模块 (led.v)

LED控制模块负责根据按键的状态切换LED的显示模式。模块内部包含两个状态机,分别控制跑马灯和流水灯的显示效果。

module led(
    input   sysclk,         // 系统时钟
    input   sys_rst_n,      // 系统复位信号,低电平有效
    input   key,            // 按键输入信号
    output reg [3:0] led    // LED输出信号,控制4个LED
);

parameter delay = 50_000_000; // LED状态切换延时计数
reg [27:0] cnt;              // 计数器,用于延时
wire flag;                   // 按键稳定状态标志
reg [3:0] led_0001;          // 跑马灯模式下的LED状态
reg [3:0] led_1000;          // 流水灯模式下的LED状态

// 延时计数器
always @(posedge sysclk) begin
    if (!sys_rst_n)
        cnt <= 0;
    else if (cnt == delay - 1)
        cnt <= 0;
    else
        cnt <= cnt + 1;
end

// 跑马灯模式下的LED状态切换
always @(posedge sysclk) begin
    if (!sys_rst_n)
        led_0001 <= 4'b0001; // 初始状态为0001
    else if (cnt == delay - 1)
        led_0001 <= {led_0001[2:0], led_0001[3]}; // 循环左移
    else
        led_0001 <= led_0001;
end

// 流水灯模式下的LED状态切换
always @(posedge sysclk) begin
    if (!sys_rst_n)
        led_1000 <= 4'b1000; // 初始状态为1000
    else if (cnt == delay - 1)
        led_1000 <= {led_1000[0], led_1000[3:1]}; // 循环右移
    else
        led_1000 <= led_1000;
end

// 状态机定义
parameter IDLE = 3'b001, // 空闲状态
          s0   = 3'b010, // 跑马灯模式
          s1   = 3'b100; // 流水灯模式

reg [2:0] cur_state;     // 当前状态
reg [2:0] next_state;    // 下一个状态

// 状态转移
always @(posedge sysclk) begin
    if (!sys_rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
end

// 状态机逻辑
always @(*) begin
    case (cur_state)
        IDLE: begin
            if (flag == 1)
                next_state = s0; // 按键按下,切换到跑马灯模式
            else
                next_state = IDLE;
        end
        s0: begin
            if (flag == 1)
                next_state = s1; // 按键按下,切换到流水灯模式
            else
                next_state = s0;
        end
        s1: begin
            if (flag == 1)
                next_state = IDLE; // 按键按下,切换到空闲状态
            else
                next_state = s1;
        end
        default: next_state = IDLE;
    endcase
end

// LED输出控制
always @(*) begin
    if (!sys_rst_n)
        led = 4'b0000; // 复位时LED全灭
    else case (cur_state)
        IDLE: led = 4'b0000; // 空闲状态,LED全灭
        s0:   led = led_0001; // 跑马灯模式
        s1:   led = led_1000; // 流水灯模式
        default: led = 4'b0000;
    endcase
end

// 按键消抖模块例化
key key_u(
    .clk(sysclk),
    .rst_n(sys_rst_n),
    .key(key),
    .flag(flag)
);

endmodule

该模块(led.v )负责生成动态的LED显示效果,例如跑马灯和流水灯。它根据来自 key.v 的按键有效信号 flag 来切换四个LED的不同显示模式。该模块包含延时计数器和状态机,用于管理LED模式之间的转换,提供视觉反馈给用户,并确保显示效果的流畅性和准确性。

模块功能:
  1. 根据按键状态切换LED显示模式。

  2. 实现跑马灯和流水灯效果。

注意事项:
  1. delay参数需要根据实际的时钟频率进行调整,以确保LED状态切换的速度合适。

  2. 状态机的设计使得系统能够在跑马灯模式和流水灯模式之间切换,按键每次按下都会切换到下一个模式。

3. 模块工作流程

  1. 复位状态:系统上电或复位时,LED全灭,状态机处于IDLE状态。

  2. 按键检测:按键消抖模块检测按键的稳定状态,输出flag信号。

  3. 状态切换:根据flag信号,状态机在IDLEs0(跑马灯模式)和s1(流水灯模式)之间切换。

  4. LED显示:根据当前状态,LED显示跑马灯或流水灯效果。


三. 模块化设计优势

  1. 代码复用性:模块化设计使得每个模块可以独立开发和测试,并且可以在其他项目中复用。例如,按键消抖模块可以用于其他需要按键输入的项目。

  2. 可维护性:将系统功能划分为多个模块后,每个模块的功能清晰明确,便于后续的维护和升级。

  3. 可读性:模块化设计使得代码结构清晰,便于理解和调试。

  4. 并行开发:多个开发者可以同时开发不同的模块,提高开发效率。


四. 本文总结

通过简单的项目模块设计与实现,我们掌握了如何使用Verilog语言进行FPGA开发,并通过模块化编程的方式将按键消抖模块与LED控制模块分离。这种设计方式不仅提高了代码的可读性和可维护性,还为后续更复杂的FPGA项目开发奠定了基础。希望本文对你理解FPGA开发、Verilog编程以及模块化设计有所帮助。


五. 更多操作

基本的跑马灯实现,请看

FPGA 18 ,使用 Xilinx Vivado 实现跑马灯和流水灯https://blog.csdn.net/weixin_65793170/article/details/144018031?ops_request_misc=%257B%2522request%255Fid%2522%253A%25222c89a542394575afd4e7c0f6a3b41aa7%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=2c89a542394575afd4e7c0f6a3b41aa7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144018031-null-null.nonecase&utm_term=%E8%B7%91%E9%A9%AC%E7%81%AF&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144018031?ops_request_misc=%257B%2522request%255Fid%2522%253A%25222c89a542394575afd4e7c0f6a3b41aa7%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=2c89a542394575afd4e7c0f6a3b41aa7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144018031-null-null.nonecase&utm_term=%E8%B7%91%E9%A9%AC%E7%81%AF&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144018031?ops_request_misc=%257B%2522request%255Fid%2522%253A%25222c89a542394575afd4e7c0f6a3b41aa7%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=2c89a542394575afd4e7c0f6a3b41aa7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144018031-null-null.nonecase&utm_term=%E8%B7%91%E9%A9%AC%E7%81%AF&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144018031?ops_request_misc=%257B%2522request%255Fid%2522%253A%25222c89a542394575afd4e7c0f6a3b41aa7%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=2c89a542394575afd4e7c0f6a3b41aa7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144018031-null-null.nonecase&utm_term=%E8%B7%91%E9%A9%AC%E7%81%AF&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144018031?ops_request_misc=%257B%2522request%255Fid%2522%253A%25222c89a542394575afd4e7c0f6a3b41aa7%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=2c89a542394575afd4e7c0f6a3b41aa7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144018031-null-null.nonecase&utm_term=%E8%B7%91%E9%A9%AC%E7%81%AF&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144018031?ops_request_misc=%257B%2522request%255Fid%2522%253A%25222c89a542394575afd4e7c0f6a3b41aa7%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=2c89a542394575afd4e7c0f6a3b41aa7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144018031-null-null.nonecase&utm_term=%E8%B7%91%E9%A9%AC%E7%81%AF&spm=1018.2226.3001.4450基本的状态机和按键消抖的实现,请看

FPGA 22 ,基于状态机的按键消抖设计与实现https://blog.csdn.net/weixin_65793170/article/details/144378347?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226d70fbf082f7f2ad78171a71effd1edf%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=6d70fbf082f7f2ad78171a71effd1edf&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144378347-null-null.nonecase&utm_term=%E7%8A%B6%E6%80%81%E6%9C%BA&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144378347?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226d70fbf082f7f2ad78171a71effd1edf%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=6d70fbf082f7f2ad78171a71effd1edf&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144378347-null-null.nonecase&utm_term=%E7%8A%B6%E6%80%81%E6%9C%BA&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144378347?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226d70fbf082f7f2ad78171a71effd1edf%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=6d70fbf082f7f2ad78171a71effd1edf&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144378347-null-null.nonecase&utm_term=%E7%8A%B6%E6%80%81%E6%9C%BA&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144378347?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226d70fbf082f7f2ad78171a71effd1edf%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=6d70fbf082f7f2ad78171a71effd1edf&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144378347-null-null.nonecase&utm_term=%E7%8A%B6%E6%80%81%E6%9C%BA&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144378347?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226d70fbf082f7f2ad78171a71effd1edf%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=6d70fbf082f7f2ad78171a71effd1edf&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144378347-null-null.nonecase&utm_term=%E7%8A%B6%E6%80%81%E6%9C%BA&spm=1018.2226.3001.4450https://blog.csdn.net/weixin_65793170/article/details/144378347?ops_request_misc=%257B%2522request%255Fid%2522%253A%25226d70fbf082f7f2ad78171a71effd1edf%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=6d70fbf082f7f2ad78171a71effd1edf&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-144378347-null-null.nonecase&utm_term=%E7%8A%B6%E6%80%81%E6%9C%BA&spm=1018.2226.3001.4450完整FPGA系列,请看

FPGA系列,文章目录https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501https://blog.csdn.net/weixin_65793170/article/details/144185217?spm=1001.2014.3001.5501


http://www.kler.cn/a/522868.html

相关文章:

  • 机器人基础深度学习基础
  • SpringCloud基础二(完结)
  • C++ unordered_map和unordered_set的使用,哈希表的实现
  • 面试经典150题——图
  • C# 与.NET 日志变革:JSON 让程序“开口说清话”
  • AI软件外包需要注意什么 外包开发AI软件的关键因素是什么 如何选择AI外包开发语言
  • Hive:基本查询语法
  • R语言机器学习算法实战系列(十九)特征选择之Monte Carlo算法(Monte Carlo Feature Selection)
  • 内存泄漏的通用排查方法
  • 《Vision Transformer》论文精读:在大量足够数据量的条件下纯Transformer也能在图像分类任务中比肩SOTA
  • 蓝桥杯例题四
  • 基于微信小程序的社团活动助手php+论文源码调试讲解
  • 电力晶体管(GTR)全控性器件
  • 【Qt】文件操作
  • 打造专业PPT幻灯片布局的实用策略
  • 深入浅出Linux操作系统大数据定制Shell编程(六)
  • 2000-2020年各省第二产业增加值占GDP比重数据
  • 在线免费快速无痕去除照片海报中的文字logo
  • 【面试】【前端】【微信小程序】微信小程序面试内容总结
  • 动态规划DP 数字三角型模型 方格取数(题目详解+C++代码实现)
  • Vue.js Vuex 模块化管理
  • 软件测试丨从自动化软件测试到自主测试,还差几步?
  • Beautiful Soup 入门指南:从零开始掌握网页解析
  • MySQL 用户相关的操作详解
  • 【深度学习入门_机器学习理论】K近邻法(KNN)
  • LLM推理优化:数据、模型与系统级策略