状态机切换左移/右移(顶层模块)
顶层文件 top.v
module top (
input sys_clk,
input sys_rst_n,
input key_n, // 按键切换方向
output [3:0] led
);
// ── 例化异步复位同步释放 ──
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 dir; // 0=左移, 1=右移
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) dir <= 0;
else if (key_press) dir <= ~dir; // 按一次切换方向
end
// ── 定时 + 移位 ──
parameter CNT_MAX = 25_000_000; // 0.5s
reg [24:0] cnt;
reg [3:0] led_r;
always @(posedge sys_clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
led_r <= 4'b0001;
end else if (cnt >= CNT_MAX - 1) begin
cnt <= 0;
if (!dir)
led_r <= {led_r[2:0], led_r[3]}; // 循环左移
else
led_r <= {led_r[0], led_r[3:1]}; // 循环右移
end else
cnt <= cnt + 1;
end
assign led = ~led_r;
endmodule子模块:rst_sync.v(异步复位同步释放)
module rst_sync (
input clk,
input rst_n_in, // 原始异步复位
output rst_n_out // 同步释放后的复位
);
reg r1, r2;
always @(posedge clk or negedge rst_n_in) begin
if (!rst_n_in) begin r1 <= 0; r2 <= 0; end
else begin r1 <= 1; r2 <= r1; end
end
assign rst_n_out = r2;
endmodule子模块:key_filter.v(两拍同步 + 消抖 + 下降沿检测)
module key_filter #(
parameter CNT_MAX = 1_000_000 // 20ms @ 50MHz
)(
input clk,
input rst_n,
input key_in, // 原始按键输入(低有效)
output key_press // 单脉冲:检测到按下
);
// 两拍同步
reg s1, s2;
always @(posedge clk or negedge rst_n)
if (!rst_n) begin s1 <= 1; s2 <= 1; end
else begin s1 <= key_in; s2 <= s1; end
// 消抖
reg [19:0] cnt;
reg key_db;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin cnt <= 0; key_db <= 1; end
else if (s2 != key_db) begin
if (cnt >= CNT_MAX - 1) begin cnt <= 0; key_db <= s2; end
else cnt <= cnt + 1;
end else cnt <= 0;
end
// 下降沿检测
reg prev;
always @(posedge clk or negedge rst_n)
if (!rst_n) prev <= 1;
else prev <= key_db;
assign key_press = prev & ~key_db;
endmodule