【verilog】 FPGA倒计时器设计

思路

将时间拆分为6个参数:

        second_1  -> 秒个位
        second_10 -> 秒十位
        minute_1  -> 分个位
        minute_10 -> 分十位
        hour_1;   -> 时个位
        hour_10;  -> 时十位

在异步复位的时候为上述六个参数赋初始值。
然后对50Mhz系统时钟进行计数,计数50M次(即为1s)。然后对六个参数的当前值做出判断,并在下一个clk做出改变。

当计满一秒,且秒的个位大于0时,——》秒的个位减1
当计满一秒,且秒的个位等于0,秒的十位大于0时,——》秒的十位减1,秒的个位变9
当计满一秒,且秒为00,并且分的个位大于0时,——》分的个位减1,秒由00变为59
当计满一秒,且秒为00,并且分的个位等于0,分的十位大于0时,——》分的十位减1,个位变为9,秒由00变为59
当计满一秒,且秒为00,分也为00,时的个位大于0时,——》时的个位减1,分由00变为59,秒也由00变为59
当计满一秒,且秒为00,分也为00,时的个位等于0,时的十位大于0时,——》时的十位减1,个位变9,分由00变为59,秒也由00变为59
当计满一秒,且时分秒为:00 00 00时,——》还原为预设值

仅当【suspend】状态值为1的时候才会对50Mhz系统时钟进行计数,为0时暂停计数,这样就实现了计数器的暂停。

CODE

module down_cnt(
                clk,
                rst,
                suspend,
                second_1,
                second_10,
                minute_1,
                minute_10,
                hour_1,
                hour_10
);
 

        input clk;
        input rst;
        input suspend; //当suspend为状态量,为0时计时暂停,为1时计时继续。
        output reg [3:0] second_1; //秒个位
        output reg [2:0] second_10;//秒十位
        output reg [3:0] minute_1; //分个位
        output reg [2:0] minute_10;//分十位
        output reg [3:0] hour_1;   //时个位
        output reg [1:0] hour_10;  //时十位

        reg [31:0] cnt;//50M -> 1s (50M时钟进行50M次计数得到一秒,)

always@(posedge clk or negedge rst)
        begin
                if(!rst)//复位时设置倒计时初始值
                    begin
                            cnt <= 32'd0;
                            second_1 <= 4'd0;
                            second_10 <= 3'd0;
                            minute_1 <= 4'd1;
                            minute_10 <= 3'd0;
                            hour_1 <= 4'd0;
                            hour_10 <= 2'd0;
                    end	
                    //当计满一秒,且秒的个位大于0时,——》秒的个位减1
                    else if(cnt == 32'd5000_0000 && second_1>4'd0)
                        begin
                            second_1 <= second_1 - 4'd1;
                            cnt <= 32'd0;
                        end
                    //当计满一秒,且秒的个位等于0,秒的十位大于0时,——》秒的十位减1,秒的个位变9
                    else if(cnt == 32'd5000_0000 && second_1==4'd0 && second_10>3'd0 )
                        begin
                            second_10 <= second_10 - 3'd1;
                            second_1 <= 4'd9;
                            cnt <= 32'd0;
                        end
                    //当计满一秒,且秒为00,并且分的个位大于0时,——》分的个位减1,秒由00变为59
                    else if(cnt == 32'd5000_0000 && second_1==4'd0 && second_10==3'd0 && minute_1>4'd0 )
                        begin
                            minute_1 <= minute_1 - 4'd1;	
                            second_10 <= 3'd5;
                            second_1 <= 4'd9;
                            cnt <= 32'd0;
                        end
                    //当计满一秒,且秒为00,并且分的个位等于0,分的十位大于0时,——》分的十位减1,个位变为9,秒由00变为59
                    else if(cnt == 32'd5000_0000 && second_1==4'd0 && second_10==3'd0 && minute_1==4'd0 && minute_10 > 3'd0)
                        begin
                           minute_10 <= minute_10 - 3'd1;
                            minute_1 <= 4'd9;
                            second_10 <= 3'd5;
                            second_1 <= 4'd9;
                            cnt <= 32'd0;
                        end
                    //当计满一秒,且秒为00,分也为00,时的个位大于0时,——》时的个位减1,分由00变为59,秒也由00变为59
                    else if(cnt == 32'd5000_0000 && second_1==4'd0 && second_10==3'd0 && minute_1==4'd0 && minute_10 ==3'd0 && hour_1 >4'd0)
                        begin
                            hour_1 <= hour_1 - 4'd1;
                            minute_10 <= 3'd5;
                            minute_1 <= 4'd9;
                            second_10 <= 3'd5;
                            second_1 <= 4'd9;
                            cnt <= 32'd0;
                        end
                    //当计满一秒,且秒为00,分也为00,时的个位等于0,时的十位大于0时,——》时的十位减1,个位变9,分由00变为59,秒也由00变为59
                    else if(cnt == 32'd5000_0000 && second_1==4'd0 && second_10==3'd0&& minute_1==4'd0 && minute_10 ==3'd0 && hour_1 == 4'd0 && hour_10 > 2'd0 && hour_10< 2'd2 )
                        begin
                            hour_10 <= hour_10 - 2'd1;
                           hour_1 <= 4'd9;
                            minute_10 <= 3'd5;
                            minute_1 <= 4'd9;
                            second_10 <= 3'd5;
                            second_1 <= 4'd9;
                            cnt <= 32'd0;
                        end
                    //当计满一秒,且时分秒为:00 00 00时,——》还原为预设值
                    else if(cnt == 32'd5000_0000 && second_1==4'd0 && second_10==3'd0 && minute_1==4'd0 && minute_10 ==3'd0 && hour_1 == 4'd0 && hour_10 == 2'd0 )
                        begin
                            hour_10 <= 2'd0;
                            hour_1 <= 4'd0;
                            minute_10 <= 3'd0;
                            minute_1 <= 4'd0;
                            second_10 <= 3'd0;
                            second_1 <= 4'd0;
                            cnt <= 32'd0;
                        end                       
                    else if(suspend == 1'b1)
                        begin
                            cnt <= cnt + 32'd1;
                        end
                    else
                        begin
                            cnt <= cnt;
                        end

        end
endmodule

顶层CODE

使用六个数码管来显示六个时间参数,下为顶层文件。(数码管的驱动见:链接

module top(
				clk,
				rst,
				dig,
                suspend,
                dict
				);
    input clk;
    input rst;
    input suspend;
    output  [5:0] dig;  //六个数码管片选
    output  [7:0] dict; //动态数码管段选
    
    wire [23:0] set_data;//数码管显示的内容:4bit*6 
 down_cnt f1(
            .clk(clk),
            .rst(rst),
            .suspend(suspend),
            .second_1(set_data[3:0]),
            .second_10(set_data[7:4]),
            .minute_1(set_data[11:8]),
            .minute_10(set_data[15:12]),
            .hour_1(set_data[19:16]),
            .hour_10(set_data[23:20])
);
                
        dig8_6 f2(
                 .clk(clk),
                 .rst(rst),
                 .set_data(set_data),
                 .dig(dig), 
                 .dict(dict)
               );
               
            
endmodule

<think>我们被要求回答关于FPGA计时器设计的实现方案。根据提供的引用资料,我们可以总结出几个关键点:1.FPGA计时器通常包括分频模块(将高频时钟分频为1Hz)、计数模块(进行秒、分、时的计数)、显示模块(驱动数码管等)以及控制模块(设置、复位等)。2.设计可以采用模块化的思想,便于理解和扩展。3.引用中提到了多种计时器:数字时钟、可设定24小时计时器、会议发言计时器、闹钟等,但核心计时原理类似。因此,我们可以给出一个基本的FPGA计时器设计框架,包括以下几个主要模块:-分频模块:将系统高频时钟(如50MHz)分频为1Hz的时钟信号。-计时模块:包括秒、分、时的计数,并考虑进位(如60秒进位1分钟,60分钟进位1小时,24小时复位)。-显示模块:将计时数据转换成数码管等显示设备所需的信号。-控制模块:实现设置时间、复位、启停等功能。下面我们将详细描述各个模块的设计,并给出Verilog代码示例(注意:代码将作为独立代码块展示,使用单独成段的方式)。注意:由于引用资料中提供了多个不同的项目,我们将综合它们的特点,给出一个通用的设计。步骤1:分频模块功能:将系统时钟(例如50MHz)分频为1Hz的时钟信号,用于计时。计算公式:分频系数=系统时钟频率/目标频率。例如,50MHz分频到1Hz,分频系数为50,000,000。步骤2:计时模块功能:利用1Hz时钟信号进行计时,实现秒、分、时的计数,并处理进位。步骤3:显示模块功能:将计时数据(时、分、秒)转换为数码管显示所需的段选和位选信号。通常需要数码管扫描电路。步骤4:控制模块功能:通过按键等输入设备设置时间、复位计时器、启动/停止等。下面我们给出一个简单的代码框架,仅包含分频和计时模块(以24小时制为例),显示模块和控制模块可根据具体硬件和需求扩展。注意:由于引用[5]中提到了分频器的设计,我们将从分频器开始。</think>### FPGA计时器设计方案 FPGA计时器设计通常采用模块化架构,以下是核心实现方案: #### 1. **系统架构设计** ```mermaid graph TD A[时钟分频模块] --> B[计时控制模块] B --> C[时间计数模块] C --> D[显示驱动模块] E[控制接口] --> B ``` #### 2. **关键模块实现** **① 时钟分频模块**(引用[5]) - 功能:将FPGA板载高频时钟(如50MHz)分频为1Hz计时基准 - Verilog示例: ```verilog module clk_divider( input clk_50M, // 50MHz输入时钟 input rst, // 复位信号 output reg clk_1s // 1Hz输出 ); reg [25:0] cnt; always @(posedge clk_50M or posedge rst) begin if(rst) begin cnt <= 0; clk_1s <= 0; end else if(cnt == 26'd49_999_999) begin // 50MHz→1Hz分频 cnt <= 0; clk_1s <= ~clk_1s; end else cnt <= cnt + 1; end endmodule ``` **② 时间计数模块**(引用[3]) - 实现24小时制计时: ```verilog module time_counter( input clk_1s, // 1Hz时钟 input rst, output [5:0] sec, // 秒(0-59) output [5:0] min, // 分(0-59) output [4:0] hour // 时(0-23) ); reg [5:0] sec_r, min_r; reg [4:0] hour_r; always @(posedge clk_1s or posedge rst) begin if(rst) {sec_r, min_r, hour_r} <= 0; else begin sec_r <= (sec_r == 59) ? 0 : sec_r + 1; if(sec_r == 59) begin min_r <= (min_r == 59) ? 0 : min_r + 1; if(min_r == 59) hour_r <= (hour_r == 23) ? 0 : hour_r + 1; end end end assign sec = sec_r, min = min_r, hour = hour_r; endmodule ``` **③ 控制模块扩展功能**(引用[4]) - 会议发言计时器特性: - 预设时间设置(1-99分钟) - 倒计时模式 - 超时报警信号 - 暂停/继续控制 **④ 显示驱动模块** - 七段数码管动态扫描 - BCD码转换逻辑 - 亮度控制电路 #### 3. **优化设计要点** 1. **时序优化**: - 使用同步复位避免亚稳态 - 添加时钟使能信号替代门控时钟 2. **资源优化**(引用[1]): ```verilog // 复用计数器资源示例 always @(posedge clk) begin if(mode) // 正计时模式 counter <= counter + 1; else // 倒计时模式 counter <= counter - 1; end ``` 3. **报警功能**(引用[5]): - 蜂鸣器驱动电路 - LED闪烁模式控制 - 预报警提示(最后30秒) #### 4. **完整系统集成** ```verilog module digital_timer( input clk_50M, input rst_n, input [1:0] mode, // 00:计时 01:倒计时 10:设置 output [7:0] seg, output [3:0] dig_sel ); wire clk_1s; wire [5:0] sec, min; wire [4:0] hour; clk_divider u_div(.clk_50M(clk_50M), .rst(!rst_n), .clk_1s(clk_1s)); time_counter u_cnt(.clk_1s(clk_1s), .rst(!rst_n), .sec(sec), .min(min), .hour(hour)); display_driver u_disp(.clk(clk_50M), .hour(hour), .min(min), .sec(sec), .seg(seg), .dig_sel(dig_sel)); endmodule ``` ### 设计验证要点 1. **功能仿真**:使用ModelSim验证计时精度 2. **时序分析**:通过Quartus TimeQuest检查时序违例(引用[2]) 3. **板级测试**: - 按键消抖处理 - 显示刷新率调整(>60Hz) - 低功耗模式设计 ### 应用场景扩展(引用[4]) 1. 会议发言限时器 2. 工业流程控制计时 3. 运动竞赛计时系统 4. 实验室反应计时装置 > 实现要点:FPGA并行处理能力可实现多通道独立计时,每个通道可配置不同时间参数,适用于需要高精度同步控制的场景[^3]。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搞IC的那些年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值