FPGA分秒计数器——Verilog语言+DE2-115开发板

发布于:2025-04-05 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、设计目标

        在DE2-115板子上用 Verilog编程实现一个分秒计数器,并具备按键暂停、按键消抖功能。

(1)引脚分配符合DE2-115开发板规范;

(2)基于状态机思想设计,20ms周期消除机械抖动。

二、程序设计实现代码

1、顶层模块

module top(
    input CLOCK_50,     // 50MHz时钟(PIN_Y2)
    input KEY0,         // 复位按钮(PIN_M23)
    input KEY1,         // 暂停按钮(PIN_M21)
    output [6:0] HEX0,  // 秒个位(PIN_G18等)
    output [6:0] HEX1,  // 秒十位(PIN_M24等)
    output [6:0] HEX2,  // 分个位(PIN_K22等)
    output [6:0] HEX3   // 分十位(PIN_K21等)
);
 
// 状态定义
localparam RUN    = 1'b0;
localparam PAUSE  = 1'b1;
 
// 内部信号声明
wire reset = ~KEY0;     // 低电平有效复位
wire clk_1hz;           // 1Hz时钟
wire carry_sec;         
wire key_stable;        // 消抖后的按键信号
reg key_stable_d;       // 用于边沿检测的延迟寄存器
 
// 计数器输出信号定义
wire [3:0] sec_ones; 
wire [3:0] sec_tens;
wire [3:0] min_ones;
wire [3:0] min_tens;
 
// 状态寄存器
reg current_state;
reg next_state;
 
// 消抖后的暂停信号
debounce pause_debouncer(
    .clk(CLOCK_50),
    .button(~KEY1),     // KEY1低电平有效
    .out(key_stable)
);
 
// 边沿检测逻辑(上升沿)
always @(posedge CLOCK_50) begin
    key_stable_d <= key_stable;
end
wire key_rise = key_stable & ~key_stable_d;
 
// 状态转移逻辑
always @(*) begin
    case (current_state)
        RUN:   next_state = key_rise ? PAUSE : RUN;
        PAUSE: next_state = key_rise ? RUN   : PAUSE;
        default: next_state = RUN;
    endcase
end
 
// 状态翻转逻辑(每次按键翻转pause_state)
always @(posedge CLOCK_50 or posedge reset) begin
    if (reset) current_state <= RUN;
    else current_state <= next_state;
end
// 输出控制信号
wire pause = (current_state == PAUSE);
 
// 时钟分频模块实例化
clk_divider clk_div(
    .clk(CLOCK_50),
    .reset(reset),
    .pause(pause),
    .clk_1hz(clk_1hz)
);
 
// 秒计数器模块实例化
second_counter sec_cnt(
    .clk(clk_1hz),
    .reset(reset),
    .enable(~pause),    // 暂停时停止计数
    .sec_ones(sec_ones),
    .sec_tens(sec_tens),
    .carry_sec(carry_sec)
);
 
// 分钟计数器模块实例化
minute_counter min_cnt(
    .clk(clk_1hz),
    .reset(reset),
    .inc(carry_sec),
    .min_ones(min_ones),
    .min_tens(min_tens)
);
 
// 七段译码器实例化
seg7_decoder seg_sec0(.bcd(sec_ones), .seg(HEX0));  // 秒个位
seg7_decoder seg_sec1(.bcd(sec_tens), .seg(HEX1));  // 秒十位
seg7_decoder seg_min0(.bcd(min_ones), .seg(HEX2));  // 分个位
seg7_decoder seg_min1(.bcd(min_tens), .seg(HEX3));  // 分十位
 
endmodule

2、时钟分频模块(带暂停控制)

// 时钟分频模块(带暂停控制)
module clk_divider(
    input clk,
    input reset,
    input pause, 
    output reg clk_1hz
);
reg [25:0] counter;
 
always @(posedge clk or posedge reset) begin
    if (reset) begin
        counter <= 0;
        clk_1hz <= 0;
    end
    else if (!pause) begin  // 暂停时停止分频
        if (counter == 26'd24_999_999) begin
            counter <= 0;
            clk_1hz <= ~clk_1hz;
        end
        else begin
            counter <= counter + 1;
        end
    end
end
endmodule

3、带使能端的秒计数器

// 带使能端的秒计数器
module second_counter(
    input clk,
    input reset,
    input enable,       // 使能信号
    output reg [3:0] sec_ones,
    output reg [3:0] sec_tens,
    output carry_sec    // 改为组合逻辑输出
);
// 组合逻辑判断是否到达59秒
assign carry_sec = (sec_ones == 9) && (sec_tens == 5);
always @(posedge clk or posedge reset) begin
    if (reset) begin
        sec_ones <= 0;
        sec_tens <= 0;
    end
    else if (enable) begin
        if (sec_ones == 9) begin
            sec_ones <= 0;
            if (sec_tens == 5)
                sec_tens <= 0;
            else
                sec_tens <= sec_tens + 1;
        end
        else begin
            sec_ones <= sec_ones + 1;
        end
    end
end
endmodule

4、分钟计数器


// 分钟计数器
module minute_counter(
    input clk,
    input reset,
    input inc,
    output reg [3:0] min_ones,
    output reg [3:0] min_tens
);
always @(posedge clk or posedge reset) begin
    if (reset) begin
        min_ones <= 0;
        min_tens <= 0;
    end
    else if (inc) begin
        if (min_ones == 9) begin
            min_ones <= 0;
            if (min_tens == 5)
                min_tens <= 0;
            else
                min_tens <= min_tens + 1;
        end
        else begin
            min_ones <= min_ones + 1;
        end
    end
end
endmodule

5、七段译码器

// 七段译码器
module seg7_decoder(
    input [3:0] bcd,
    output reg [6:0] seg
);
always @(*) begin
    case (bcd)
        4'd0 : seg = 7'b1000000; // 0
        4'd1 : seg = 7'b1111001; // 1
        4'd2 : seg = 7'b0100100; // 2
        4'd3 : seg = 7'b0110000; // 3
        4'd4 : seg = 7'b0011001; // 4
        4'd5 : seg = 7'b0010010; // 5
        4'd6 : seg = 7'b0000010; // 6
        4'd7 : seg = 7'b1111000; // 7
        4'd8 : seg = 7'b0000000; // 8
        4'd9 : seg = 7'b0010000; // 9
        default : seg = 7'b1111111; // 灭
    endcase
end
endmodule

6、按键消抖模块(20ms)

// 按键消抖模块(20ms消抖)
module debounce(
    input clk,
    input button,
    output reg out
);
reg [19:0] counter;
reg [2:0] button_sync;  // 三级同步器
always @(posedge clk) begin
    // 同步器链
    button_sync <= {button_sync[1:0], button};
    
    // 消抖逻辑
    if (button_sync[2] != out) begin
        counter <= counter + 1;
        if (&counter) begin  // 计满20ms(50MHz时钟)
            out <= button_sync[2];
            counter <= 0;
        end
    end
    else begin
        counter <= 0;
    end
end
endmodule

三、结果演示

四、总结

        状态机设计有效提升了系统的可靠性和可维护性,按键消抖是嵌入式系统设计的必备技能,同时时序分析在FPGA设计中至关重要。由于本人初步学习认知浅薄,上述内容或有诸多不详错漏之处,望各位海涵并指出批正。