DE2-115板子上用 Verilog编程实现一个分秒计数器

一、实验目的

  1. 掌握 Verilog 语言在硬件描述中的应用,通过编程实现分秒计数器的逻辑功能。

  2. 学习并实践按键消抖的原理与实现方法,提升对硬件电路中信号处理的理解。

  3. 熟悉在 DE2-115 开发板上进行 Verilog 程序的开发、调试及下载验证流程,将理论知识与实际硬件相结合 。

二、实验环境

  1. 硬件平台:DE2-115 开发板,该开发板搭载 Altera Cyclone IV E 系列 FPGA 芯片,提供丰富的外设资源,包括按键、数码管等,便于进行各类数字逻辑实验。

  2. 软件工具:Quartus Prime 开发套件,用于 Verilog 代码的编写、综合、布局布线以及下载到 FPGA 芯片中;ModelSim 用于 Verilog 代码的功能仿真,验证设计逻辑的正确性。

三、实验原理

3.1 分秒计数器原理

分秒计数器本质是一个多级计数器。秒计数器以 1Hz 的时钟信号作为计数脉冲,当秒计数器计数到 59 时,产生一个进位信号,触发分计数器加 1。分计数器同样在接收到进位信号时进行计数,当分计数器计数到 59 时,可根据需求选择是否继续进位或循环归零。

3.2 按键消抖原理

机械按键在按下和释放时,由于触点的弹性作用,会产生短暂的抖动,导致信号不稳定。按键消抖通过在检测到按键状态变化后,启动一个计数器,当计数器达到一定时间(如 10ms)且按键状态未再变化时,才认为按键状态有效,从而消除抖动带来的干扰。

四、模块设计与实现

4.1 按键消抖模块(debounce.v)
verilog 复制代码
module debounce (
    input wire clk,
    input wire rst_n,
    input wire btn_in,
    output reg btn_out
);

    parameter DEBOUNCE_TIME = 16'd250000; // 10ms @ 25MHz

    reg [15:0] cnt;
    reg btn_reg1, btn_reg2;

    // 同步输入信号到时钟域
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            btn_reg1 <= 1'b0;
            btn_reg2 <= 1'b0;
        end
        else begin
            btn_reg1 <= btn_in;
            btn_reg2 <= btn_reg1;
        end
    end

    // 消抖计数器
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt <= 16'd0;
            btn_out <= 1'b0;
        end
        else begin
            if (btn_reg2 != btn_out) begin
                cnt <= cnt + 1'b1;
                if (cnt >= DEBOUNCE_TIME) begin
                    btn_out <= btn_reg2;
                    cnt <= 16'd0;
                end
            end
            else
                cnt <= 16'd0;
        end
    end

endmodule

该模块通过两级触发器将按键输入信号同步到时钟域,然后使用一个计数器在检测到按键状态变化时开始计数,当计数达到设定的消抖时间且按键状态稳定时,输出稳定的按键信号。

4.2 分秒计数器模块(counter.v)
verilog 复制代码
	module counter (
    input wire clk,
    input wire rst_n,
    input wire pause,
    output reg [5:0] sec,
    output reg [5:0] min
);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            sec <= 6'd0;
            min <= 6'd0;
        end
        else if (!pause) begin
            if (sec == 6'd59) begin
                sec <= 6'd0;
                if (min == 6'd59)
                    min <= 6'd0;
                else
                    min <= min + 1'b1;
            end
            else
                sec <= sec + 1'b1;
        end
    end
endmodule

在时钟上升沿或复位信号有效时,对分秒计数器进行操作。当暂停信号无效时,秒计数器在计数到 59 后归零并使分计数器加 1,分计数器计数到 59 后归零,实现循环计数;当暂停信号有效时,计数器停止计数。

4.3 顶层模块(top_module.v)
verilog 复制代码
module top_module (
    input wire clk,
    input wire rst_n,
    input wire pause_btn,
    output reg [6:0] seg,
    output reg [3:0] an
);

    wire clean_pause;
    wire [5:0] sec;
    wire [5:0] min;

    debounce u1 (
      .clk(clk),
      .rst_n(rst_n),
      .btn_in(pause_btn),
      .btn_out(clean_pause)
    );

    counter u2 (
      .clk(clk),
      .rst_n(rst_n),
      .pause(clean_pause),
      .sec(sec),
      .min(min)
    );

    always @(*) begin
        case({an})
            4'b1110: begin
                an = 4'b1110;
                case(min[5:4])
                    2'b00: seg = 7'b0000001;
                    2'b01: seg = 7'b1001111;
                    2'b10: seg = 7'b0010010;
                    2'b11: seg = 7'b0000110;
                endcase
            end
            4'b1101: begin
                an = 4'b1101;
                case(min[3:0])
                    4'b0000: seg = 7'b0000001;
                    4'b0001: seg = 7'b1001111;
                    4'b0010: seg = 7'b0010010;
                    4'b0011: seg = 7'b0000110;
                    4'b0100: seg = 7'b1001100;
                    4'b0101: seg = 7'b0100100;
                    4'b0110: seg = 7'b0100000;
                    4'b0111: seg = 7'b0001111;
                    4'b1000: seg = 7'b0000000;
                    4'b1001: seg = 7'b0000100;
                endcase
            end
            4'b1011: begin
                an = 4'b1011;
                case(sec[5:4])
                    2'b00: seg = 7'b0000001;
                    2'b01: seg = 7'b1001111;
                    2'b10: seg = 7'b0010010;
                    2'b11: seg = 7'b0000110;
                endcase
            end
            4'b0111: begin
                an = 4'b0111;
                case(sec[3:0])
                    4'b0000: seg = 7'b0000001;
                    4'b0001: seg = 7'b1001111;
                    4'b0010: seg = 7'b0010010;
                    4'b0011: seg = 7'b0000110;
                    4'b0100: seg = 7'b1001100;
                    4'b0101: seg = 7'b0100100;
                    4'b0110: seg = 7'b0100000;
                    4'b0111: seg = 7'b0001111;
                    4'b1000: seg = 7'b0000000;
                    4'b1001: seg = 7'b0000100;
                endcase
            end
            default: begin
                an = 4'b1111;
                seg = 7'b1111111;
            end
        endcase
    end

endmodule

顶层模块将按键消抖模块和分秒计数器模块实例化并连接,同时实现数码管动态显示逻辑,通过扫描不同位的数码管,分时显示分和秒的数值。

五、实验结果与分析

程序在quartus上编译无误后,烧录到板子上运行

将编译后的程序下载到 DE2-115 开发板中,通过实际操作按键进行测试。按下复位按键,数码管显示 "00:00";按下暂停按键,计数器暂停计数,数码管数值保持不变;再次按下暂停按键,计数器继续计数。数码管能够稳定、正确地显示分和秒的数值,实验功能成功实现。

六、总结

本次实验成功在 DE2-115 板子上使用 Verilog 实现了具有按键暂停和按键消抖功能的分秒计数器。通过实验,深入理解了 Verilog 语言的编程方法、按键消抖的原理以及 FPGA 开发流程。在实验过程中,也遇到了如数码管显示编码错误、时序匹配等问题,通过查阅资料和调试得以解决。

相关推荐
Terasic友晶科技20 分钟前
【教程】Agilex 5 SoC 的两种启动模式的开发演示(一)(FPGA Configuration First)
fpga开发·agilex 5 soc
ALINX技术博客24 分钟前
【黑金云课堂】FPGA技术教程Vitis开发:SD卡WAV文件读取音频播放实验
fpga开发·音视频
仲南音2 天前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner3 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20203 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy3 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia3 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20203 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子4 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安4 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi