边沿检测有上升沿检测、下降沿检测、双边沿检测。以按键控制LED灯为例,下面是按键原理图
从按键连接的原理图,可以看到,按键未按下时是低电平,当按键按下即为高电平,如果要实现按键按下一次led改变一次状态,即检测按键上升沿。再加上按键消抖代码如下
module key (KEY,LED_N,RST_N,CLK); input [7:4] KEY; //四个按键 output [7:4] LED_N; //四个 LED灯 input RST_N,CLK; //时钟,复位按键 //****************************************************************************** //上升沿检测 //***************************************************************************** reg [7:4]key; always @(posedge CLK or negedge RST_N) if (!RST_N) key <= 4'b0000; else key <= KEY; reg [7:4]key_r; always @ (posedge CLK or negedge RST_N) if (!RST_N) key_r <= 4'b0000; else key_r <= key; wire [7:4] key_an; assign key_an = ~key_r & key; // //*********************************************************************************** reg [19:0] cnt; always @ (posedge CLK or negedge RST_N) if (!RST_N) cnt <= 20'd0; else if (key_an) cnt <= 20'd0; else cnt = cnt + 1'b1;
reg [7:4] low_key;//****************************************************************************** //上升沿检测 //*****************************************************************************
always @ (posedge CLK or negedge RST_N)
if (!RST_N)
low_key <= 4'b0000;
else if (cnt == 20'h000ff)
low_key <= KEY;
reg [7:4] low_key_r;
always @ (posedge CLK or negedge RST_N)
if (!RST_N) low_key_r <= 4'b0000;
else
low_key_r <= low_key;
wire [7:4] led_ctrl = ~low_key_r & low_key;reg [7:4] led;//*****************************************************************************
always @ (posedge CLK or negedge RST_N)
if (!RST_N)
led <= 4'b1111;
else
begin
if (led_ctrl[7])
led[7] <= ~led[7];
if (led_ctrl[6])
led[6] <= ~led[6];
if (led_ctrl[5])
led[5] <= ~led[5];
if (led_ctrl[4])
led[4] <= ~led[4];
end
assign LED_N[7] = led[7], LED_N[6] = led[6], LED_N[5] = led[5], LED_N[4] = led[4];
endmodule 两条*****线中的 代码就是上升沿检测,两个寄存器key,key_r分别储存按键前后两个时钟的值,key_an 由 ~key_r & key得到。时钟周期: 1 2 3 4 5
key : 0000 0000 0000 0000 0001
key_r: xxxx0000 00000000 0000~key_r: xxxx 11111111 11111111
此处假设在第5个时钟周期有按键按下,那么在 第五个时钟周期,key_an的值为 0001。那么这段代码实现的效果就是按键每按下一次相应的led状态改变一次。如果实现的功能是按键按下时led一个 状态,按键松开时 led一个状态,那么就要同时检测led的双边沿。只要把代码中的
assign key_an = ~key_r & key;
wire [7:4] led_ctrl = ~low_key_r & low_key;
更换成assign key_an = key_r ^ key;
wire [7:4] led_ctrl = low_key_r ^ low_key;
即可。
如果按键原理图中,按键按下为低电平,松开为高电平,要实现按键每按下一次,led的值改变一次,就要进行下降沿检测,
代码中的
assign key_an = ~key_r & key;
wire [7:4] led_ctrl = ~low_key_r & low_key;
要更换成assign key_an = key_r & ~key;
wire [7:4] led_ctrl = low_key_r & ~low_key;
解析 如下
时钟周期: 1 2 3 4 5
key : 1111 1111 1111 1111 1110
key_r: xxxx 1111 1111 1111 1111 ~key_r: xxxx 0000 0000 0000 0001
在 第五个时钟周期,key_an的值为 0001。