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

基于 FPGA 的分秒计数器

基于 FPGA 的分秒计数器

文章目录

  • 基于 FPGA 的分秒计数器
    • 一、设计原理
      • (一)分频器
      • (二)按键控制
      • (三)分秒计时器
    • 二、设计实现
      • (一)分频器模块(clock_divider.v)
      • (二)按键控制模块
      • (三)分秒计时器模块
      • (四)顶层模块(top.v)
    • 三、实现效果
    • 四、总结

一、设计原理

(一)分频器

FPGA 开发板通常提供 50MHz 的时钟信号,但分秒计数器仅需 1Hz 的时钟来实现每秒计数一次的效果。分频器模块的作用就是将 50MHz 的高频时钟分频为 1Hz 的低频时钟。其核心原理是通过一个计数器对输入时钟进行计数,当计数值达到分频系数的一半(对于 50MHz 到 1Hz 的分频,分频系数为 50000000 ,即计数到 25000000)时,翻转输出时钟信号的电平,同时将计数器清零,重新开始计数。

(二)按键控制

  1. 按键消抖:机械按键在按下和松开时会产生抖动,导致按键信号不稳定,可能出现多次触发的情况。为解决这一问题,采用延时消抖的方法。当按键状态保持 20ms 以上时,才认为按键状态稳定,锁存该状态并产生一个脉冲信号。在 50MHz 时钟下,1ms 对应 50000 个时钟周期,因此使用一个 20 位的计数器,计数到 1000000(50000×20)即达到 20ms。
  2. 按键暂停计时:将按键消抖后产生的脉冲信号转换为一个稳定的切换信号。每当检测到有效的按键脉冲时,翻转暂停状态信号,从而实现暂停和继续计时的功能。

(三)分秒计时器

  1. 计时器逻辑:分秒计数器遵循特定的计数规则。秒个位从 0 计数到 9,满 9 后归零并向秒十位进位;秒十位从 0 计数到 5,满 59 秒后归零并向分个位进位;分个位从 0 计数到 9,满 9 后归零并向分十位进位;分十位从 0 计数到 5,满 59 分后归零,最大显示 59:59。
  2. 显示模块:七段数码管有共阳极和共阴极两种类型。共阳极数码管在笔段电极接低电平、公共阳极接高电平时发光;共阴极数码管则相反,驱动信号为高电平、公共阴极接低电平时发光。通过将计数器的输出值转换为对应的七段数码管显示代码,实现时间的可视化。

二、设计实现

(一)分频器模块(clock_divider.v)

module clock_divider #(
    parameter DIVISOR = 50000000  
)(
    input clk_in,
    input reset_n,
    output reg clk_out
);
    reg [31:0] counter;
    always @(posedge clk_in or negedge reset_n) begin
        if (!reset_n) begin
            counter <= 0;
            clk_out <= 0;
        end
        else begin
            if (counter >= (DIVISOR/2 - 1)) begin
                counter <= 0;
                clk_out <= ~clk_out;
            end
            else begin
                counter <= counter + 1;
            end
        end
    end
endmodule

(二)按键控制模块

  1. 按键消抖模块(debounce.v)
module debounce(
    input clk,
    input reset_n,
    input key_in,
    output reg key_pulse
);
    reg [19:0] count;  
    reg key_in_sync1, key_in_sync2;
    reg key_stable;
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            key_in_sync1 <= 1'b1;
            key_in_sync2 <= 1'b1;
            key_stable <= 1'b1;
            count <= 20'd0;
            key_pulse <= 1'b0;
        end
        else begin
            key_in_sync1 <= key_in;
            key_in_sync2 <= key_in_sync1;
            if (key_in_sync2 != key_stable) begin
                key_stable <= key_in_sync2;
                count <= 20'd0;
            end
            else if (count < 20'd1000000) begin  
                count <= count + 1'b1;
            end
            else begin
                key_pulse <= key_in_sync2 & ~key_stable;  
            end
        end
    end
endmodule
  1. 按键暂停计时模块(pause_control.v)
module pause_control(
    input clk,
    input reset_n,
    input pause_pulse,
    output reg pause_toggle
);
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            pause_toggle <= 1'b0;
        end
        else if (pause_pulse) begin
            pause_toggle <= ~pause_toggle;
        end
    end
endmodule

(三)分秒计时器模块

  1. 计时器逻辑模块(min_sec_counter.v)
module min_sec_counter(
    input clk,
    input reset_n,
    input pause,
    output reg [3:0] sec_ones,
    output reg [3:0] sec_tens,
    output reg [3:0] min_ones,
    output reg [3:0] min_tens
);
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            sec_ones <= 4'd0;
            sec_tens <= 4'd0;
            min_ones <= 4'd0;
            min_tens <= 4'd0;
        end
        else if (!pause) begin  
            if (sec_ones == 4'd9) begin
                sec_ones <= 4'd0;
                if (sec_tens == 4'd5) begin
                    sec_tens <= 4'd0;
                    if (min_ones == 4'd9) begin
                        min_ones <= 4'd0;
                        if (min_tens == 4'd5) begin
                            min_tens <= 4'd0;
                        end
                        else begin
                            min_tens <= min_tens + 4'd1;
                        end
                    end
                    else begin
                        min_ones <= min_ones + 4'd1;
                    end
                end
                else begin
                    sec_tens <= sec_tens + 4'd1;
                end
            end
            else begin
                sec_ones <= sec_ones + 4'd1;
            end
        end
    end
endmodule
  1. 显示模块(seven_seg_display.v)
module seven_seg_display(
    input [3:0] digit,
    output reg [6:0] seg
);
    always @(*) begin
        case (digit)
            4'h0: seg = 7'b1000000;  
            4'h1: seg = 7'b1111001;  
            4'h2: seg = 7'b0100100;  
            4'h3: seg = 7'b0110000;  
            4'h4: seg = 7'b0011001;  
            4'h5: seg = 7'b0010010;  
            4'h6: seg = 7'b0000010;  
            4'h7: seg = 7'b1111000;  
            4'h8: seg = 7'b0000000;  
            4'h9: seg = 7'b0010000;  
            default: seg = 7'b1111111;  
        endcase
    end
endmodule

(四)顶层模块(top.v)

module top(
    input clk_50m,
    input reset_n,
    input pause_key,
    output [6:0] hex0,
    output [6:0] hex1,
    output [6:0] hex2,
    output [6:0] hex3,
    output [7:0] ledg  
);
    wire clk_1hz;
    wire pause_pulse;
    wire pause_toggle;
    wire [3:0] sec_ones;
    wire [3:0] sec_tens;
    wire [3:0] min_ones;
    wire [3:0] min_tens;
    clock_divider #(
       .DIVISOR(50000000)
    ) clk_div (
       .clk_in(clk_50m),
       .reset_n(reset_n),
       .clk_out(clk_1hz)
    );
    debounce debounce_pause (
       .clk(clk_50m),
       .reset_n(reset_n),
       .key_in(pause_key),
       .key_pulse(pause_pulse)
    );
    pause_control pause_ctrl (
       .clk(clk_50m),
       .reset_n(reset_n),
       .pause_pulse(pause_pulse),
       .pause_toggle(pause_toggle)
    );
    min_sec_counter counter (
       .clk(clk_1hz),
       .reset_n(reset_n),
       .pause(pause_toggle),
       .sec_ones(sec_ones),
       .sec_tens(sec_tens),
       .min_ones(min_ones),
       .min_tens(min_tens)
    );
    seven_seg_display seg0 (.digit(sec_ones),.seg(hex0));
    seven_seg_display seg1 (.digit(sec_tens),.seg(hex1));
    seven_seg_display seg2 (.digit(min_ones),.seg(hex2));
    seven_seg_display seg3 (.digit(min_tens),.seg(hex3));
endmodule

三、实现效果

通过综合、编译和下载到 FPGA 开发板后,分秒计数器能够准确计时。按下复位按键,计数器归零;按下暂停按键,计时暂停,再次按下则继续计时。七段数码管实时显示当前的分钟和秒数,范围为 00:00 至 59:59,实现了预期的计时功能。
在这里插入图片描述

四、总结

本设计成功利用 Verilog 语言在 FPGA 上实现了分秒计数器,通过多个功能模块的协同工作,完成了时钟分频、按键控制、计时和显示等功能。在设计过程中,各模块之间的信号连接和逻辑关系是关键,需要仔细规划和调试。同时,这种模块化的设计方法提高了代码的可读性和可维护性,为后续功能扩展和优化奠定了基础。

http://www.dtcms.com/a/113754.html

相关文章:

  • 如何实现两个视频融合EasyCVR平台的数据同步?详细步骤指南
  • 爬虫练习案例
  • zk基础—5.Curator的使用与剖析二
  • 打造高效英文单词记忆系统:基于Python的实现与分析
  • $R^n$超平面约束下的向量列
  • 游戏引擎学习第206天
  • React框架的Hooks实现原理
  • MicroPython 开发ESP32应用教程 之 WIFI简单应用 :时间同步、天气信息获取,ST7735 TFT屏驱动及任意中文字符显示
  • Linux制作deb安装包
  • 卡尔曼滤波器浅聊
  • windows 常用命令总结
  • MySQL表的增删改查基础版
  • 【大模型深度学习】如何估算大模型需要的显存
  • JavaScript基础--09-流程控制语句:选择结构(if和switch)
  • 文件系统-inode/软硬件连接(未完结)
  • 用 Python 制作仓库自动化指南
  • Kotlin协程机制
  • 解析keras.layers.Layer中的权重参数
  • Linux内核——段描述符详解
  • SeaTunnel系列之:Apache SeaTunnel编译和安装
  • 《SQL赋能人工智能:解锁特征工程的隐秘力量》
  • python基础-11-调试程序
  • DrissionPage高级技巧:从爬虫到自动化测试
  • Python FastApi(13):APIRouter
  • 操作系统知识点(二)
  • 超级科学软件实验室(中国) : Super Scientific Software Laboratory (SSSLab)
  • Vue2与Vue3不同
  • Deformable DETR(复习专用)
  • 基于Spark的哔哩哔哩舆情数据分析系统
  • 【RK3588 嵌入式图形编程】-SDL2-扫雷游戏-创建网格