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 开发流程。在实验过程中,也遇到了如数码管显示编码错误、时序匹配等问题,通过查阅资料和调试得以解决。

相关推荐
贝塔实验室8 分钟前
LDPC 码的度分布
线性代数·算法·数学建模·fpga开发·硬件工程·信息与通信·信号处理
javajenius15 小时前
Quartus II下载安装教程Quartus II 18保姆级安装步骤(附安装包)
其他·fpga开发
颜子鱼16 小时前
FPGA中复位信号的省略
fpga开发
cycf18 小时前
面向模块的综合技术之过约束(十)
fpga开发
颜子鱼19 小时前
FPGA-状态机架构
fpga开发
颜子鱼19 小时前
FPGA-状态机
fpga开发
GateWorld1 天前
FPGA设计中的“幽灵信号:一条走线,两种命运——浅析路径延迟导致的逻辑错误
fpga开发
云雾J视界1 天前
RISC-V开源处理器实战:从Verilog RTL设计到FPGA原型验证
fpga开发·开源·verilog·risc-v·rtl·数字系统
我爱C编程1 天前
【仿真测试】基于FPGA的完整BPSK通信链路实现,含频偏锁定,帧同步,定时点,Viterbi译码,信道,误码统计
fpga开发·bpsk·帧同步·viterbi译码·频偏锁定·定时点
tiger1191 天前
FPGA在AI时代的定位?
人工智能·fpga开发