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

音乐网站素材百度销售平台

音乐网站素材,百度销售平台,公司法人变更的基本流程,公司英文网站建设FPGA学习(三)——数码管实现四位分秒计数器 目录 FPGA学习(三)——数码管实现四位分秒计数器一、实验要求二、实验思考三、四位分秒计数器实现1、代码实现2、添加按键消抖模块3、添加状态机思想4、模块化重构代码5、实现效果 四、总结 一、实验要求 1、用FPGA控制四个数码管&a…

FPGA学习(三)——数码管实现四位分秒计数器

目录

  • FPGA学习(三)——数码管实现四位分秒计数器
  • 一、实验要求
  • 二、实验思考
  • 三、四位分秒计数器实现
    • 1、代码实现
    • 2、添加按键消抖模块
    • 3、添加状态机思想
    • 4、模块化重构代码
    • 5、实现效果
  • 四、总结

一、实验要求

1、用FPGA控制四个数码管,分别显示分钟、秒钟,计数范围都是0~59。

2、按键控制复位和暂停。当复位时所有计数器归零,当启动/暂停按下,暂停计数,再次接下时继续。

3、采用状态机思想实现。

二、实验思考

1、数码管显示。为了在数码管上显示四位分秒计数器,在DE2-115开发板上使用四位共阳极的七段数码管,如hex3-hex0,分别作为分钟的十位、个位,秒的十位、个位。

2、计数逻辑。秒的计数器是0到59,当秒到59后,分钟加一,秒归零。分钟同样到59后归零。用一个4位的BCD计数器,每个单位用4位表示。例如,秒的个位和十位各用4位二进制码,组合成0-59的范围。

reg [3:0] sec_one; // 0-9
reg	[3:0] sec_ten; // 0-5
reg [3:0] min_one;
reg [3:0] min_ten;/*详细的计数逻辑*/

3、分频逻辑。将50MHz的时钟分频成1Hz的信号,这样每秒钟计数器加一。分频的话,50MHz等于50,000,000 Hz,要得到1Hz,需要计数50,000,000次,需要26位计数器

reg [DIV_WIDTH-1:0] counter;always @(posedge clk or posedge reset) beginif (reset) begincounter <= 0;clk_out <= 0;end else begincounter <= counter + 1;clk_out <= counter[DIV_WIDTH-1];  // 取最高位作为分频输出end
end

4、复位/暂停。可以采用按键作为控制信号,当按键按下时,复位/启动/暂停计数。

	if (reset) begin{sec_ones, sec_tens, min_ones, min_tens} <= 16'd0; // 全部清零end else if (!start_pause) begin // KEY1按下时暂停(低电平有效)

5、状态机。首先要定义系统可能达到的所有状态。可能的状态包有复位状态、运行状态、暂停状态以及空闲状态。此外考虑状态转移的条件和时机,将按键信号作为状态转移的触发条件,同时需要确保状态转移只在按键事件发生时进行一次切换,而不是持续切换。这可能需要边缘检测,即检测按键信号的上升沿或下降沿。同时,每个状态下的行为也需要明确,如:在RUNNING状态下,计数器每秒递增;在IDLE状态下,计数器保持不变,而复位信号无论当前处于什么状态,都应强制回到初始状态。

三、四位分秒计数器实现

1、代码实现

首先,在不考虑状态机的情况下,先来简单的实现一下这个分秒计数器。代码如下 :

module clock(input clk_50m,          // 50MHz系统时钟input reset_btn,        // 复位按键(直接连接)input pause_btn,        // 暂停按键(直接连接)output [7:0] HEX3,      // 分钟十位output [7:0] HEX2,      // 分钟个位output [7:0] HEX1,      // 秒十位output [7:0] HEX0       // 秒个位
);// 内部信号定义
wire clk_1hz;
wire [3:0] min_ten, min_one;
wire [3:0] sec_ten, sec_one;
wire carry;
reg pause_state;            // 暂停状态寄存器// 1Hz时钟生成(简化版)
reg [25:0] clk_div;
always @(posedge clk_50m or posedge reset_btn) beginif (reset_btn) beginclk_div <= 0;endelse beginclk_div <= clk_div + 1;end
end
assign clk_1hz = clk_div[25] & ~pause_state;  // 暂停时停止时钟// 暂停状态控制
always @(posedge clk_50m or posedge reset_btn) beginif (reset_btn) beginpause_state <= 1'b0;endelse if (pause_btn) beginpause_state <= ~pause_state;  // 每次按下切换暂停状态end
end// 秒计数器(0-59)
reg [3:0] sec_one, sec_ten;
always @(posedge clk_1hz or posedge reset_btn) beginif (reset_btn) beginsec_one <= 0;sec_ten <= 0;end else beginif (sec_one == 9) beginsec_one <= 0;if (sec_ten == 5) sec_ten <= 0;else sec_ten <= sec_ten + 1;end else beginsec_one <= sec_one + 1;endend
end
assign carry = (sec_one == 9) && (sec_ten == 5);// 分钟计数器(0-59)
reg [3:0] min_one, min_ten;
always @(posedge carry or posedge reset_btn) beginif (reset_btn) beginmin_one <= 0;min_ten <= 0;end else beginif (min_one == 9) beginmin_one <= 0;if (min_ten == 5) min_ten <= 0;else min_ten <= min_ten + 1;end else beginmin_one <= min_one + 1;endend
end// 数码管显示驱动
function [7:0] digit_to_seg;input [3:0] digit;input dot;begincase(digit)0: digit_to_seg = {dot, 7'b1000000};1: digit_to_seg = {dot, 7'b1111001};2: digit_to_seg = {dot, 7'b0100100};3: digit_to_seg = {dot, 7'b0110000};4: digit_to_seg = {dot, 7'b0011001};5: digit_to_seg = {dot, 7'b0010010};6: digit_to_seg = {dot, 7'b0000010};7: digit_to_seg = {dot, 7'b1111000};8: digit_to_seg = {dot, 7'b0000000};9: digit_to_seg = {dot, 7'b0010000};default: digit_to_seg = {dot, 7'b1111111};endcaseend
endfunctionassign HEX3 = digit_to_seg(min_ten, 1'b1);  // 分十位带小数点
assign HEX2 = digit_to_seg(min_one, 1'b0);
assign HEX1 = digit_to_seg(sec_ten, 1'b1);  // 秒十位带小数点
assign HEX0 = digit_to_seg(sec_one, 1'b0);endmodule

上述代码只是简单的实现,而在实际中,按键输入控制复位和启动/暂停,硬件会有机械抖动,可能导致误触发,因此我们要为上述代码添加上按键的消抖模块。

2、添加按键消抖模块

在编写消抖模块时,通常的做法是使用计数器来检测按键状态的稳定。当检测到按键状态变化时,启动一个计数器,如果在20ms内状态没有变化,则认为按键稳定,输出新的状态。

消抖模块代码如下:

module button_debounce(input clk,          // 50MHz时钟input button_in,    // 原始按键输入output reg button_out  // 消抖后的按键信号
);reg [19:0] counter;     // 20位计数器(50MHz/2^20 ≈ 21ms)
reg button_sync;
reg button_prev;always @(posedge clk) begin// 同步输入信号,防止亚稳态button_sync <= button_in;// 消抖处理逻辑if (button_sync != button_prev) beginbutton_prev <= button_sync;counter <= 0;end else if (counter[19]) begin  // 计数器满(约21ms)button_out <= button_prev;end else begincounter <= counter + 1;end
endendmodule

3、添加状态机思想

module fsm_controller(input clk,input reset,input pause,output reg running_o  // 明确输出端口命名
);// Verilog-2001兼容的状态定义
parameter [1:0] IDLE    = 2'b00,RUNNING = 2'b01,PAUSED  = 2'b10;reg [1:0] current_state, next_state;// 状态寄存器更新
always @(posedge clk or posedge reset) beginif (reset) begincurrent_state <= IDLE;end else begincurrent_state <= next_state;end
end// 状态转移逻辑
always @(*) begincase (current_state)IDLE:    next_state = RUNNING;RUNNING: next_state = pause ? PAUSED : RUNNING;PAUSED:  next_state = pause ? RUNNING : PAUSED;default: next_state = IDLE;endcase
end// 输出逻辑
always @(*) beginrunning_o = (current_state == RUNNING);
endendmodule

4、模块化重构代码

将上述按键消抖模块及状态机思想加入,并模块化代码。完整代码如下:

clock.v

/** 顶层模块:clock_mmss_static_top* 修改说明:明确声明running信号并统一连接*/
module clock(input clk_50m,          // 50MHz系统时钟input reset_btn,        // 按键1 - 复位(KEY0)input pause_btn,        // 按键2 - 暂停/恢复(KEY1)output [7:0] HEX3,      // 分钟十位(最左数码管)output [7:0] HEX2,      // 分钟个位(带小数点)output [7:0] HEX1,      // 秒十位output [7:0] HEX0       // 秒个位(最右数码管)
);// 内部信号定义
wire clk_1hz;
wire reset_pulse, pause_pulse;
wire running;  // 统一使用wire类型连接模块
wire [3:0] min_ten, min_one;
wire [3:0] sec_ten, sec_one;// 实例化时钟分频模块
clock_divider #(.DIV_WIDTH(25)  // 50MHz -> 1Hz (2^25 = 33,554,432)
) u_clock_div (.clk(clk_50m),.reset(reset_pulse),.clk_out(clk_1hz)
);// 实例化按键消抖模块
button_debounce u_reset_debounce (.clk(clk_50m),.button_in(reset_btn),.button_out(reset_pulse)
);button_debounce u_pause_debounce (.clk(clk_50m),.button_in(pause_btn),.button_out(pause_pulse)
);// 实例化状态机控制器(关键修改)
fsm_controller u_fsm (.clk(clk_50m),.reset(reset_pulse),.pause(pause_pulse),.running_o(running)  // 统一端口命名
);// 实例化秒计数器
second_counter u_sec_counter (.clk(clk_1hz),.reset(reset_pulse),.enable(running),  // 直接使用running信号.sec_ten(sec_ten),.sec_one(sec_one),.carry(carry_w)
);// 实例化分钟计数器
minute_counter u_min_counter (.clk(carry_w),.reset(reset_pulse),.enable(running),  // 直接使用running信号.min_ten(min_ten),.min_one(min_one)
);// 实例化静态显示驱动
static_display u_display (.min_ten(min_ten),.min_one(min_one),.sec_ten(sec_ten),.sec_one(sec_one),.HEX3(HEX3),.HEX2(HEX2),.HEX1(HEX1),.HEX0(HEX0)
);endmodule

clock_divider.v

/** 模块名称:clock_divider* 功能:将输入时钟分频为较低频率*/
module clock_divider #(parameter DIV_WIDTH = 25  // 分频计数器位宽
)(input clk,input reset,output reg clk_out
);reg [DIV_WIDTH-1:0] counter;always @(posedge clk or posedge reset) beginif (reset) begincounter <= 0;clk_out <= 0;end else begincounter <= counter + 1;clk_out <= counter[DIV_WIDTH-1];  // 取最高位作为分频输出end
endendmodule

button_debounce.v

/** 模块名称:button_debounce* 功能:对机械按键进行消抖处理(约20ms消抖时间)*/
module button_debounce(input clk,          // 50MHz时钟input button_in,    // 原始按键输入output reg button_out  // 消抖后的按键信号
);reg [19:0] counter;     // 20位计数器(50MHz/2^20 ≈ 21ms)
reg button_sync;
reg button_prev;always @(posedge clk) begin// 同步输入信号,防止亚稳态button_sync <= button_in;// 消抖处理逻辑if (button_sync != button_prev) beginbutton_prev <= button_sync;counter <= 0;end else if (counter[19]) begin  // 计数器满(约21ms)button_out <= button_prev;end else begincounter <= counter + 1;end
endendmodule

second_counter.v

module second_counter(input clk,input reset,input enable,output reg [3:0] sec_ten,output reg [3:0] sec_one,output carry  // 改为连续赋值方式
);// 进位条件:59秒时产生1个时钟周期高电平assign carry = (sec_one == 9) && (sec_ten == 5) && enable;always @(posedge clk or posedge reset) beginif (reset) {sec_ten, sec_one} <= 8'h0;else if (enable) beginif ({sec_ten, sec_one} == 8'h59) {sec_ten, sec_one} <= 8'h0;else if (sec_one == 9) beginsec_one <= 0;sec_ten <= sec_ten + 1;endelse sec_one <= sec_one + 1;endend
endmodule

minute_counter.v

/** 模块名称:minute_counter* 功能:实现0-59分钟计数*/
module minute_counter(input clk,          // 由秒进位驱动input reset,input enable,output reg [3:0] min_ten,  // 分十位(0-5)output reg [3:0] min_one   // 分个位(0-9)
);always @(posedge clk or posedge reset) beginif (reset) beginmin_ten <= 0;min_one <= 0;end else if (enable) beginif (min_one == 9) beginmin_one <= 0;if (min_ten == 5) beginmin_ten <= 0;end else beginmin_ten <= min_ten + 1;endend else beginmin_one <= min_one + 1;endend
endendmodule

static_display.v

/** 模块名称:static_display* 功能:驱动4位数码管静态显示MM:SS* DE2-115数码管为共阳极,低电平点亮*/
module static_display(input [3:0] min_ten,  // 分钟十位input [3:0] min_one,  // 分钟个位input [3:0] sec_ten,  // 秒钟十位input [3:0] sec_one,  // 秒钟个位output [7:0] HEX3,    // 分钟十位(最左)output [7:0] HEX2,    // 分钟个位(带小数点)output [7:0] HEX1,    // 秒钟十位output [7:0] HEX0     // 秒钟个位(最右)
);// 数字到7段码的转换(共阳极,低电平点亮)
function [7:0] digit_to_seg;input [3:0] digit;input dot;  // 小数点控制begincase(digit)0: digit_to_seg = {dot, 7'b1000000}; // 01: digit_to_seg = {dot, 7'b1111001}; // 12: digit_to_seg = {dot, 7'b0100100}; // 23: digit_to_seg = {dot, 7'b0110000}; // 34: digit_to_seg = {dot, 7'b0011001}; // 45: digit_to_seg = {dot, 7'b0010010}; // 56: digit_to_seg = {dot, 7'b0000010}; // 67: digit_to_seg = {dot, 7'b1111000}; // 78: digit_to_seg = {dot, 7'b0000000}; // 89: digit_to_seg = {dot, 7'b0010000}; // 9default: digit_to_seg = {dot, 7'b1111111}; // 灭endcaseend
endfunction// 数码管连接(使用HEX2的小数点作为冒号)
assign HEX3 = digit_to_seg(min_ten, 1'b1);  // 分钟十位,点亮小数点
assign HEX2 = digit_to_seg(min_one, 1'b0);  // 分钟个位
assign HEX1 = digit_to_seg(sec_ten, 1'b1);  // 秒钟十位,点亮小数点
assign HEX0 = digit_to_seg(sec_one, 1'b0);  // 秒钟个位endmodule

fsm_controller.v

/** 模块名称:fsm_controller*/
module fsm_controller(input clk,input reset,input pause,output reg running_o  // 明确输出端口命名
);// Verilog-2001兼容的状态定义
parameter [1:0] IDLE    = 2'b00,RUNNING = 2'b01,PAUSED  = 2'b10;reg [1:0] current_state, next_state;// 状态寄存器更新
always @(posedge clk or posedge reset) beginif (reset) begincurrent_state <= IDLE;end else begincurrent_state <= next_state;end
end// 状态转移逻辑
always @(*) begincase (current_state)IDLE:    next_state = RUNNING;RUNNING: next_state = pause ? PAUSED : RUNNING;PAUSED:  next_state = pause ? RUNNING : PAUSED;default: next_state = IDLE;endcase
end// 输出逻辑
always @(*) beginrunning_o = (current_state == RUNNING);
endendmodule

5、实现效果

分秒计数器

四、总结

在这次基于DE2-115开发板的四位分秒计数器设计实验中,我深刻体会到了数字系统设计的完整流程与工程思维的重要性。从最初简单的分频计数到最终的模块化重构,整个过程让我对FPGA开发有了更立体的认识。通过引入消抖模块并优化参数,最终实现了可靠的按键检测。而三段式状态机的设计,不仅让逻辑更清晰,调试效率也大幅提升。最让我受益的是最后的模块化重构过程,将系统拆分为功能独立的模块,提高了代码复用性。

http://www.dtcms.com/wzjs/416146.html

相关文章:

  • 聊城专业做网站百度广告怎么推广
  • 买家乡的特产网站建设样本互联网推广引流是做什么的
  • 开源项目管理系统seo网站编辑是做什么的
  • 自己主机做网站服务器吗免费的网络推广渠道
  • 做网站应该了解什么问题seo外包推广
  • 阿里云网站备案多久四年级写一小段新闻
  • 市场营销专业网站培训心得模板
  • 虚拟主机 部署网站吗网络广告营销策略
  • 乔拓云微信小程序宁波seo关键词优化报价
  • 电脑做的本地网站手机看零基础怎么做电商
  • 巢湖商城网站建设百度风云榜排行榜
  • 网络设计的专业有哪些哈尔滨网络推广优化
  • 设计工作室与网站建设工作室wordpress免费网站
  • 电商网站建设包括哪些方面重庆网站seo好不好
  • java 建网站荆州网站seo
  • 广州中企动力网站制作seo教程视频论坛
  • vs210做网站seo人工智能
  • 网站做任务赚钱如何做企业网页
  • icp备案查询站长工具南宁seo怎么做优化团队
  • 个人电影网站建设推广普通话手抄报内容大全
  • 网站建设中关村如何网站seo
  • 自己做网站建设推广点击器
  • 装修设计费无锡谷歌优化
  • 做任务转比特币的网站今日新闻快讯
  • b2c电商网站uc浏览器关键词排名优化
  • 网站建设存在的困难表白网站制作
  • 镇江市扬中市做网站wordpress建站
  • 网站开发的安全性原则网站如何建立
  • 西安学校网站建设价格google推广教程
  • 做网站需要学php吗网站推广计划书范文