本次笔记记录的是尖峰脉冲和边沿检测例程
1.尖峰脉冲
尖峰脉冲是电路设计中非常重要的一种信号,很多大型设计中模块间的级联握手信号一般都会使用尖峰脉冲,正确的应用尖峰脉冲信号,可以有效的减少系统的逻辑冗余,提高系统稳定性和执行效率
本次笔记以统计按键次消抖次数为例,产生尖峰脉冲(详细按键消抖接下笔记细述)
设计系统结构
例程:
moduleSpike_pulse(
clk,
rst_,
key_in,
sum
);
inputclk,rst_;
inputkey_in;//外部信号输入
outputreg[3:0]sum;//按键按下次数统计
regrst_n;//异步复位同步释放
always@(posedgeclk)
rst_n<=rst_;
reg[9:0]cnt;//消抖延时计数
regstate;
regpos_flag;//尖峰脉冲寄存器
always@(posedgeclkornegedgerst_n)
begin
if(!rst_n)begin
cnt<=0;
state<=0;
pos_flag<=0;
end
elsebegin
case(state)
0: begin
if(cnt<10)begin//消抖延时未开始计数
if(!key_in)//key_in==0按键按下
cnt<=cnt+1;
else
cnt<=0;
end
elsebegin
pos_flag<=1;
cnt<=0;
state<=1;
end
end
1: begin
pos_flag<=0;
if(key_in)//key_in==1按键放开
state<=0;
end
default:state<=0;
endcase
end
end
always@(posedgeclkornegedgerst_n)
if(!rst_n)
sum<=0;
elseif(pos_flag)
sum<=sum+1'b1;
endmodule
//tb
`timescale1ns/1ns
`defineclock_period20
moduleSpike_pulse_tb;
regclk,rst_;
regkey_in;
wire[3:0]sum;
initialclk=1;
always#(`clock_period/2)clk=~clk;
always@(posedgeclk)//随机函数使用
begin
#(`clock_period*50)key_in={$random}%2;
end
initialbegin
rst_=0;
key_in=1;
#(`clock_period*5);
rst_=1;
#(`clock_period+1);
//press_key;
#(`clock_period*1000);
$stop;
end
// taskpress_key;//任务函数的使用
// begin
// #500key_in=0;
// #500key_in=1;
// #500key_in=0;
// #500key_in=1;
// #500key_in=0;
// #500key_in=1;
// #500key_in=0;
// #500key_in=1;
// #500key_in=0;
// #500key_in=1;
// #500key_in=0;
// #500key_in=1;
// end
// endtask
Spike_pulseSpike_pulse(
.clk(clk),
.rst_(rst_),
.key_in(key_in),
.sum(sum)
);
endmodule
仿真:
2.边沿检测
边沿检测,就是检测输入信号或者FPGA 内部逻辑信号的跳变,即对信号上升沿或者下降沿的检测
分析一下这个电路结构和工作原理可以得到
( 1 ) 当信号出现上升沿以后, pos_edge 会出现一个时钟周期的“尖峰脉冲”
( 2 ) 当信号出现下降沿以后, neg_edge 会出现一个时钟周期的“尖峰脉冲”
例程:
moduleEdge_check(
clk,
rst_n,
key,
p_edge,
n_edge
);
inputclk,rst_n;
inputkey;
outputp_edge,n_edge;//上升沿和下降沿检测标志
regkey_r;//键值寄存器
always@(posedgeclkornegedgerst_n)
if(!rst_n)
key_r<=1;
else
key_r<=key;
assignn_edge=key_r&(!key);//key由1->0n_edge=1;
assignp_edge=!key_r&key;//key由0->1p_edge=1;
endmodule
//tb
`timescale1ns/1ns
`defineclock_period20
moduleEdge_check_tb;
regclk,rst_n;
regkey;
wirep_edge,n_edge;
initialclk=1;
always#(`clock_period/2)clk=~clk;
always@(posedgeclk)//随机函数使用
begin
#(`clock_period*50)key={$random}%2;
end
initialbegin
rst_n=0;
key=1;
#(`clock_period*5);
rst_n=1;
#(`clock_period+1);
//press_key;
#(`clock_period*1000);
$stop;
end
Edge_checkEdge_check(
.clk(clk),
.rst_n(rst_n),
.key(key),
.p_edge(p_edge),
.n_edge(n_edge)
);
endmodule
仿真: