Verilog(Vivado环境)下橄榄球计分板寄存器加不同分值故障问题
问题根因分析
- 违规将普通按键输入作为寄存器时钟源
FPGA中仅专用时钟网络输入的信号适合作为时钟,你当前把4个按键的上升沿直接加入always块的敏感列表,相当于把普通IO当成了时钟源。这类信号时延不稳定,极易受到毛刺、机械抖动的干扰,每次电平跳变产生的上升沿都会触发加法操作,直接导致分值连续累加。 - if-else分支顺序导致加6功能巧合正常
你将加6的逻辑放在分支最末尾,仅当其余3个按键均为低电平时才会触发。测试时按下达阵按键恰好没有其他按键干扰,所以看起来功能正常,本质是巧合而非逻辑正确。 - 缺失按键消抖与单脉冲触发逻辑
物理开关拨动时会产生5~20ms的机械抖动,这段时间内电平会反复跳变产生多个上升沿。没有消抖和单脉冲转换逻辑的情况下,每次跳变都会触发一次加法,就是你看到的分值快速跳变的直接原因。
修复方案
1. 引入全局同步时钟
所有逻辑统一使用开发板的板载全局时钟(通常为50MHz/100MHz)作为唯一触发时钟,禁止将按键IO作为时钟源使用。
2. 实现按键消抖模块
过滤按键抖动期间的无效电平跳变,输出稳定的按键电平信号:
module key_debounce( input clk, input rst_n, // 低电平复位,可根据你的实际需求改为高电平 input key_in, output reg key_out ); reg [19:0] cnt; // 50MHz时钟下20位计数器可计数约20ms,覆盖常规按键抖动时长 reg key_sync; // 按键输入先打两拍同步到时钟域,避免亚稳态 always @(posedge clk or negedge rst_n) begin if(!rst_n) key_sync <= 1'b1; // 默认按键高电平,按下为低,可根据硬件调整 else key_sync <= key_in; end always @(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt <= 20'd0; key_out <= 1'b1; end else begin if(key_sync != key_out) begin cnt <= cnt + 1'b1; if(cnt == 20'd999_999) begin // 计数满20ms更新输出 key_out <= key_sync; cnt <= 20'd0; end end else cnt <= 20'd0; end end endmodule
3. 实现上升沿检测模块
对消抖后的按键信号做边沿检测,仅在按键按下的上升沿产生一个时钟周期的高电平使能信号,保证每次按键仅触发一次加法:
module edge_detect( input clk, input rst_n, input signal_in, output pos_edge ); reg signal_dly; always @(posedge clk or negedge rst_n) begin if(!rst_n) signal_dly <= 1'b0; else signal_dly <= signal_in; end assign pos_edge = signal_in & ~signal_dly; endmodule
4. 重写得分寄存器逻辑
使用全局时钟触发,通过使能信号控制加法操作,同时增加得分上限99的溢出判断:
module teamAPoints( input clk, input masterReset, input td_en, // 达阵使能,单脉冲信号 input fg_en, // 射门使能,单脉冲信号 input two_pt_en, // 两分转换使能,单脉冲信号 input extra_en, // 附加分使能,单脉冲信号 output reg [6:0] teamAScore ); always @(posedge clk or posedge masterReset) begin if (masterReset) begin teamAScore <= 7'd0; end else begin if(td_en && (teamAScore + 7'd6 <= 7'd99)) teamAScore <= teamAScore + 7'd6; else if(fg_en && (teamAScore + 7'd3 <= 7'd99)) teamAScore <= teamAScore + 7'd3; else if(two_pt_en && (teamAScore + 7'd2 <= 7'd99)) teamAScore <= teamAScore + 7'd2; else if(extra_en && (teamAScore + 7'd1 <= 7'd99)) teamAScore <= teamAScore + 7'd1; else teamAScore <= teamAScore; end end endmodule
5. 顶层模块连线
在顶层模块中对每个按键依次实例化消抖模块和边沿检测模块,将输出的单脉冲使能信号接到得分模块的对应输入即可。
注意:上述代码中的复位极性、按键默认电平需要根据你使用的开发板硬件实际情况调整。
内容的提问来源于stack exchange,提问作者Matt Plexico
相关产品推荐
相关产品推荐

