边沿检测(上升沿 、下降沿,双边沿)好像也是FPGA的电路,不是简单移位寄存器构成的SPI,双边沿

1、上升沿检测
代码如下:
module signal_pos(
input i_clk, //时钟输入
input i_rst_n, //复位信号
input i_signal, // 输入信号 待检测信号
output pos_pulse //输出脉冲信号
);
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)begin
if(!i_rst_n)begin
signal_reg0 <= 1’b0;
signal_reg0 <= 1’b0;
end
else begin
signal_reg0 <= i_signal;
signal_reg1 <= signal_reg0 ;
end
end
assign pos_pulse = ~signal_reg1 & signal_reg0 //上升沿脉冲 宽度:一个时钟周期
endmodule

时序分析如下:
D 为输入原始信号:i_signal
在这里插入图片描述
2、下降沿检测
代码如下:
module signal_neg(
input i_clk, //时钟输入
input i_rst_n, //复位信号
input i_signal, // 输入信号 待检测信号
output neg_pulse //输出脉冲信号
);
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)
begin
if(!i_rst_n)begin
signal_reg0 <= 1’b0;
signal_reg0 <= 1’b0;
end
else begin
signal_reg0 <= i_signal;
signal_reg1 <= signal_reg0 ;
end
end
assign neg_pulse = signal_reg1 & (~signal_reg0) //下降沿脉冲 宽度:一个时钟周期
endmodule
时序分析如下:
D 为输入原始信号:i_signal
在这里插入图片描述
3、双边沿检测
代码如下:
module signal_neg_pos(
input i_clk, //时钟输入
input i_rst_n, //复位信号
input i_signal, // 输入信号 待检测信号
output neg_pos_pulse //输出脉冲信号
);
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)
begin
if(!i_rst_n)begin
signal_reg0 <= 1’b0;
signal_reg0 <= 1’b0;
end
else begin
signal_reg0 <= i_signal;
signal_reg1 <= signal_reg0 ;
end
end
assign neg_pos_pulse = signal_reg1 ^ signal_reg0 //上升沿、下降沿脉冲 宽度:一个时钟周期
endmodule
时序分析如下:
D 为输入原始信号:i_signa
在这里插入图片描述
边沿检测还可以这么写
这里有给出了一种检测边沿的方法,代码大同小异。
module signal_neg_pos(
input i_clk, //时钟输入
input i_rst_n, //复位信号
input i_signal, // 输入信号 待检测信号
output negedge_pulse, //检测下降沿 输出脉冲信号
output posedge_pulse, //检测上升沿 输出脉冲信号
output both_edge_pulse //检测双边沿 输出脉冲信号
);
reg [1:0]signal_edge;
always @(posedge clk) begin
if(!i_rst_n)begin
signal_edge <= 2’b0;
end
else begin
signal_edge <= {signal_edge[0],i_signal} //输入信号从低位进入,左移,bit1为旧状态,bit0 为新状态
end
end
//双边沿沿:旧状态bit1 与 新状态bit0 异或需为1,故需 signal_edge[0] ^ signal_edge[1] == 1
//上升沿:旧状态bit1应为 0,新状态bit0应为 1,故需 signal_edge[1:0] == 2‘b01
//下降沿:旧状态bit1应为 1,新状态bit0应为 0,故需 signal_edge[1:0] == 2‘b10

assign both_edge_pulse = signal_edge[0] ^ signal_edge[1] //双边沿 宽度:一个时钟周期
assign posedge_pulse = (signal_edge[1:0] == 2’b01) ; //上升沿 宽度:一个时钟周期
assign negedge_pulse = (signal_edge[1:0] == 2’b10) ; //下降沿 宽度:一个时钟周期

//类似前一种方案,还可以这样写
//assign both_edge_pulse = signal_edge[0] ^ signal_edge[1] //双边沿 宽度:一个时钟周期
//assign posedge_pulse = ~signal_edge[1] & signal_edge[0] ; //上升沿 宽度:一个时钟周期
//assign negedge_pulse = signal_edge[1] & ~signal_edge[0] ; //下降沿 宽度:一个时钟周期
endmodule

亚稳态解决
避免亚稳态,只需要将输入信号打几拍即可
方案1:
跟上面边沿检测一个思路:
module signal_buff_out(
input i_clk, //时钟输入
input i_rst_n, //复位信号
input i_signal, // 输入信号 待检测信号
output out_buff // 打拍缓冲输出信号
);
reg [15:0] signal_reg;
reg [3:0] bit_num;
always @(posedge clk) begin
if(!i_rst_n)begin
signal_reg <= 16’b0;
end
else begin
signal_edge <= {signal_reg[15:0],i_signal}
end
end
assign out_buff = signal_edge[bit_num]; //根据需要,选择输入信号打拍次数 :0-15 ,0:打一拍
endmodule

方案2
这种方法使用打拍次数较少的场合
module signal_buff_out(
input i_clk, //时钟输入
input i_rst_n, //复位信号
input i_signal, // 输入信号 待检测信号
output out_buff // 打拍缓冲输出信号

              ); 
  • 1

reg signal_reg0;
reg signal_reg1;
reg signal_reg2;
always @(posedge clk)
begin
if(!i_rst_n)begin
signal_reg0 <= 1’b0;
signal_reg1 <= 1’b0;
signal_reg2 <= 1’b0;
end
else begin
signal_reg0 <= i_signal;
signal_reg1 <= signal_reg0 ;
signal_reg2 <= signal_reg1 ;
end
end
//assign out_buff = signal_reg0 ; //固定为1拍
//assign out_buff = signal_reg1 ; //固定为2拍
assign out_buff = signal_reg2 ; //固定为3拍
endmodule
细究下边沿检测原理
我将结合时序图 ,并以这段代码为例逐步分析下是如何实现上升沿检测的
module signal_pos(
input i_clk, //时钟输入
input i_rst_n, //复位信号
input i_signal, // 输入信号 待检测信号
output pos_pulse //输出脉冲信号
);
reg signal_reg0;
reg signal_reg1;
always @(posedge clk)begin
if(!i_rst_n)begin
signal_reg0 <= 1’b0;
signal_reg0 <= 1’b0;
end
else begin
signal_reg0 <= i_signal;
signal_reg1 <= signal_reg0 ;
end
end
assign pos_pulse = ~signal_reg1 & signal_reg0 //上升沿脉冲 宽度:一个时钟周期
endmodule
看下面这两句话:

  signal_reg0 <= i_signal;
  signal_reg1 <= signal_reg0 ; 
  • 1
  • 2

为了看着方便,我将输入信号 i_signal 替换为 in, signal_reg0 替换为reg0, signal_reg1 替换为reg1

  reg0 <= in;
  reg1 <= reg0 ;
  • 1
  • 2

下面这样图,把打拍的实际电路呈现了出来,打了两排,实际上就是让数据IN经过了两个D触发器缓冲输出,这种打拍方式也用于将数据跟时钟信号同步。
至于为上升沿为啥是:~reg1 & reg0 ,根据这张图,不妨这样理解:
在这里插入图片描述
1、先把这两个串联的D触发器理解成一个移位寄存器;
2、上升沿的跳变0 —>1,看成两个进入移位寄存器的数据 :0进入移位寄存器,1后进入移位寄存器;
3、经历一定的时钟周期后,先进入移位寄存器的0,进入了reg1寄存器,后进入的 1,进入了reg0寄存器;
4、reg1中保存的是老状态0,reg0中保存的是新状态1,当检测到相邻的两个D触发器中的数据不同时,说明有跳变沿,所以上升沿就是 ~reg1 & reg0 = 1;
5、因为是采用的相邻的两个D触发器中的数据检测变化,所以4中产生的 ~reg1 & reg0 = 1 也只有一个时钟周期的宽度。
6、要想让检测到的上升沿脉冲信号宽一点,如果你理解了的话,应该知道怎么做了,哈哈!看下图应该懂了吧!!
在这里插入图片描述
还可以以下图的方式来理解,前提是要对阻塞赋值和非阻塞赋值有比较深刻的理解:
结合流程图时序图可以清楚的看到,上升沿脉冲是在2、3之间产生的。

在这里插入图片描述
在这里插入图片描述

边沿检测(上升沿 、下降沿,双边沿)_下降沿检测_正在卷IC的小白的博客-CSDN博客

边沿检测--针对输入信号的跳变进而输出判断结果,上升沿、下降沿可以分别进行寄存器打拍,而后相与或者相或。当然针对与边沿检测,还有其他方法,例如通过移位寄存器,将输入信号打入移位寄存器中,然后对移位寄存器中的信号进行相与、相或和异或。这里进行打拍处理

针对上升沿分析:--当时钟处于上升沿时,检测输入信号是否发生从0到1的跳变。正确理解其中的逻辑就很简单了。

上升沿检测:

module up_decetor(clk,rst,d_in,d_out);
 
input clk;
input rst;
input d_in;
output d_out;

reg d_out_1,d_out_2;

always@(posedge clk or negedge rst) begin
  if(!rst) begin //通过寄存器保存前一个数据,使后一个数据与前一个数据进行比较
    d_out_1 <= 1'b0;
    d_out_2 <= 1'b0;
  end
  else begin
    d_out_1 <= d_in;
    d_out_2 <= d_out_1;
  end
end

assign d_out = (~d_out_2)&d_out_1; //取反相与

endmodule

tb:

module up_decetor_tb;
reg clk;
reg rst;
reg d_in;
wire d_out;

up_decetor u1(
  .clk(clk),
  .rst(rst),
  .d_in(d_in),
  .d_out(d_out)
  );

initial begin
  clk=1'b1;
  rst=1'b0;
  #5;
  rst=1'b1;
end

always #5 clk = ~clk;

/*initial begin
  $vcdpluson;
end*/

initial begin
  repeat(40) begin
    #10;
    d_in = {$random}%2;
  end
end
endmodule

下降沿检测

module down_decetor(clk,rst,d_in,d_out);

input clk;

input rst;

input d_in;

output d_out;

reg d_out_1,d_out_2;

always@(posedge clk or negedge rst) begin

  if(!rst) begin

    d_out_1 <= 1'b0;

    d_out_2 <= 1'b0;

  end

  else begin

    d_out_1 <= d_in;

    d_out_2 <= d_out_1;

  end

end

assign d_out = (~d_out_1)&d_out_2; //

endmodule

tb:

module down_decetor_tb;

reg clk;

reg rst;

reg d_in;

wire d_out;

down_decetor u1(

  .clk(clk),

  .rst(rst),

  .d_in(d_in),

  .d_out(d_out)

  );

initial begin

  clk=1'b1;

  rst=1'b0;

  #5;

  rst=1'b1;

end

always #5 clk = ~clk;

initial begin

  $vcdpluson;

end

initial begin

  #10;

  d_in=1'b1;

  #10;

  d_in=1'b0;

  #10;

  d_in=1'b0;

  #10;

  d_in=1'b1;

  #10;

  d_in=1'b0;

  #20;

  d_in=1'b1;

  #10;

  d_in=1'b1;

  #10;

  d_in=1'b0;

  #30;

  d_in=1'b1;

  #50;

  $finish();

end

endmodule

双边沿检测:

module double_decetor(clk,rst,d_in,d_out);

  

input clk;

input rst;

input d_in;

output d_out;

reg d_out_1,d_out_2;

always@(posedge clk or negedge rst) begin

  if(!rst) begin

    d_out_1 <= 1'b0;

    d_out_2 <= 1'b0;

  end

  else begin

    d_out_1 <= d_in;

    d_out_2 <= d_out_1;

  end

end

assign d_out = d_out_1^d_out_2; //异或

endmodule

tb:

module down_decetor_tb;

reg clk;

reg rst;

reg d_in;

wire d_out;

double_decetor u1(

  .clk(clk),

  .rst(rst),

  .d_in(d_in),

  .d_out(d_out)

  );

initial begin

  clk=1'b1;

  rst=1'b0;

  #5;

  rst=1'b1;

end

always #5 clk = ~clk;

initial begin

  $vcdpluson;

end

initial begin

  #10;

  d_in=1'b1;

  #20;

  d_in=1'b0;

  #10;

  d_in=1'b1;

  #10;

  d_in=1'b0;

  #10;

  d_in=1'b1;

  #10;

  d_in=1'b0;

  #20;

  d_in=1'b1;

  #10;

  d_in=1'b0;

  #30;

  d_in=1'b1;

  #50;

  $finish();

end

endmodule



https://www.cnblogs.com/shadow-fish/p/13418146.html

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据引用\[2\]中的Verilog代码,可以实现多位寄存器检测上升下降沿的功能。在该代码中,使用了两级寄存器来检测下降沿。每个寄存器都会在时钟上升沿时更新,并将前一级寄存器的值存储在当前级寄存器中。通过对两级寄存器的值进行逻辑运算,可以得到下降沿指示信号。具体的代码如下: ```verilog module detect_multi ( input sys_clk, // 时钟(设定为 50MHz) input sys_rst_n, // 复位信号(n 表示低电平有效) input \[N-1:0\] in, // 需要进行上升下降沿检测的输入信号(N为位宽) output \[N-1:0\] in_pos, // 输出的上升沿指示信号 output \[N-1:0\] in_neg // 输出的下降沿指示信号 ); reg \[N-1:0\] in_d1; // 一级寄存器 reg \[N-1:0\] in_d2; // 二级寄存器 assign in_neg = ~in_d1 & in_d2; // 组合逻辑得到下降沿 assign in_pos = in & ~in_d1; // 组合逻辑得到上升沿 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin in_d1 <= {N{1'b0}}; // 复位清零 in_d2 <= {N{1'b0}}; end else begin in_d1 <= in; // 寄存一拍 in_d2 <= in_d1; // 寄存二拍 end end endmodule ``` 在这个代码中,`N`表示输入信号的位宽。通过使用多级寄存器,我们可以同时检测多位输入信号的上升和下降沿。 #### 引用[.reference_title] - *1* *2* *3* [FPGA实现边沿检测电路上升沿下降沿)](https://blog.csdn.net/wuzhikaidetb/article/details/112187021)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值