复用 “流水灯 + 按键切换方向” 的 rst_sync、key_filter 模块
顶层 top.v
module top (
input sys_clk,
input sys_rst_n,
input key_n,
output [3:0] led
);
// ── 时钟参数 ──
parameter CLK_FREQ = 50_000_000; // 时钟频率(Hz)
localparam HALF_SEC = CLK_FREQ / 2; // 0.5s 计数阈值
localparam ONE_MS = CLK_FREQ / 1000; // 1ms 计数阈值
// ── 复位 & 按键(例化前页已有的子模块)──
wire rst_n;
rst_sync u_rst (
.clk(sys_clk), .rst_n_in(sys_rst_n), .rst_n_out(rst_n)
);
wire key_press;
key_filter u_key (
.clk(sys_clk), .rst_n(rst_n), .key_in(key_n), .key_press(key_press)
);
// ── 按键上升沿检测(单周期脉冲)──
reg key_press_d1, key_press_d2;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
key_press_d1 <= 1'b0;
key_press_d2 <= 1'b0;
end else begin
key_press_d1 <= key_press;
key_press_d2 <= key_press_d1;
end
end
wire key_trigger = key_press_d1 & ~key_press_d2;
// ── 基础定时:0.5s tick & 1ms tick ──
reg [$clog2(HALF_SEC)-1:0] cnt_half;
reg [$clog2(ONE_MS)-1:0] cnt_ms;
reg half_sec_tick, ms_tick;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
cnt_half <= 0; half_sec_tick <= 0;
cnt_ms <= 0; ms_tick <= 0;
end else begin
if (cnt_half >= HALF_SEC - 1) begin
cnt_half <= 0;
half_sec_tick <= 1'b1;
end else begin
cnt_half <= cnt_half + 1'b1;
half_sec_tick <= 1'b0;
end
if (cnt_ms >= ONE_MS - 1) begin
cnt_ms <= 0;
ms_tick <= 1'b1;
end else begin
cnt_ms <= cnt_ms + 1'b1;
ms_tick <= 1'b0;
end
end
end
// ── 模式状态机(独热码)──
localparam M_BLINK = 3'b001,
M_SHIFT = 3'b010,
M_FADE = 3'b100;
reg [2:0] mode;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
mode <= M_BLINK;
end else if (key_trigger) begin
case (mode)
M_BLINK: mode <= M_SHIFT;
M_SHIFT: mode <= M_FADE;
M_FADE: mode <= M_BLINK;
default: mode <= M_BLINK;
endcase
end
end
// ── 闪烁:每 0.5s 全部翻转 ──
reg [3:0] led_blink;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
led_blink <= 4'b1111;
end else if (half_sec_tick) begin
led_blink <= ~led_blink;
end
end
// ── 流水:循环左移 ──
reg [3:0] led_shift;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
led_shift <= 4'b0001;
end else if (half_sec_tick) begin
led_shift <= {led_shift[2:0], led_shift[3]};
end
end
// ── 呼吸:PWM 渐亮渐暗 ──
reg [9:0] pwm_cnt;
reg [7:0] duty;
reg duty_dir; // 0=渐亮, 1=渐暗
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
pwm_cnt <= 0;
end else begin
pwm_cnt <= pwm_cnt + 1'b1;
end
end
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
duty <= 0;
duty_dir <= 0;
end else if (ms_tick) begin
if (!duty_dir) begin
if (duty >= 254) begin
duty_dir <= 1'b1;
end else begin
duty <= duty + 2'd2;
end
end else begin
if (duty <= 1) begin
duty_dir <= 1'b0;
end else begin
duty <= duty - 2'd2;
end
end
end
end
wire [3:0] led_fade = (pwm_cnt[9:2] < duty) ? 4'b1111 : 4'b0000;
// ── 模式选择输出(时序锁存,消除毛刺)──
reg [3:0] led_r;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
led_r <= 4'b0000;
end else begin
case (mode)
M_BLINK: led_r <= led_blink;
M_SHIFT: led_r <= led_shift;
M_FADE: led_r <= led_fade;
default: led_r <= 4'b0000;
endcase
end
end
// LED 输出(低电平点亮)
assign led = ~led_r;
endmodule