流水灯的按键方向控制

module liushuideng
(
clk,rst_n,led_0,sw1_n,sw2_n,sw3_n
);
input clk; //时钟信号,50MHZ
input rst_n; //复位信号,低电平有效
input sw1_n,sw2_n,sw3_n; //三个独立按键,低表示按下
output[3:0] led_0; //流水灯,0--灭,1--不灭
//--------------------------------------------------------
reg led_dir; //0--right,1--left
reg led_on; //0--off,1--on

reg[23:0] cnt;

always @(posedge clk or negedge rst_n) //计数
if(!rst_n)
cnt <=24'd0;
else
cnt <= cnt+1'b1;

reg[3:0] led_move;

always @(posedge clk or negedge rst_n) //流水灯
if(!rst_n)
led_move <= 4'b1;
else if(cnt == 24'hffffff && led_on)
begin
if(led_dir)
led_move <= {led_move[2:0],led_move[3]}; //left
else
led_move <= {led_move[0],led_move[3:1]}; //right
end

//---------------------------------------------------------

reg [2:0] key_rst;

always @(posedge clk or negedge rst_n)
if (!rst_n)
key_rst <= 3'b111;
else
key_rst <= {sw3_n,sw2_n,sw1_n}; //每个时钟周期都会把按键值赋给key_rst

reg[2:0] key_rst_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r

always @ (posedge clk or negedge rst_n)
if(!rst_n)
key_rst_r <= 3'b111;
else
key_rst_r <= key_rst; //第二级寄存器,将之前锁存的按键值给key_rst_r

wire[2:0] key_an = key_rst_r & ( ~key_rst );//当寄存器key_rst由1变为0时,led_an的值变为高,维持一个时钟周期

//------------------------------------------------------

reg[23:0] cnt_cn;//计数寄存器

always @ (posedge clk or negedge rst_n)
if (!rst_n)
cnt_cn <= 24'd0; //异步复位
else if(key_an)
cnt_cn <=24'd0;
else
cnt_cn <= cnt_cn + 1'b1;

reg[2:0] low_sw;

always @ (posedge clk or negedge rst_n)
if (!rst_n)
low_sw <= 3'b111;
else if(cnt_cn == 24'hffffff) //满20ms,将按键值锁存到寄存器low_sw中
low_sw <= {sw3_n,sw2_n,sw1_n}; //每个20ms执行一次

//------------------------------------------------------
reg[2:0] low_sw_r;

always @ ( posedge clk or negedge rst_n )
if (!rst_n)
low_sw_r <= 3'b111;
else
low_sw_r <= low_sw; //每个时钟周期采一次

/*
low_sw 111 111 111 110 110 110
~low_sw 000 000 000 001 001 001
low_sw_r 111 111 111 110 110 110

led_ctr1 000 000 000 001 000 000
*/

//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
wire[2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);

always @ (posedge clk or negedge rst_n)
if(!rst_n)
begin
led_on <= 1'b0;
led_dir <= 1'b0;
end
else
begin //某个按键值变化时,LED将做亮灭、左移或右移操作
if ( led_ctrl[0] ) led_on <= ~led_on;
if ( led_ctrl[1] ) led_dir <= 1'b1;
if ( led_ctrl[2] ) led_dir <= 1'b0;
end

assign led_0 = led_dir; //LED

endmodule

原文地址:https://www.cnblogs.com/xinshuwei/p/5647840.html