1

此代码应该在按下一个按钮时增加一个计数器(输出到 LED),并在按下另一个按钮时减少它。它可以在递减时正常工作,但在递增时会将 LED 更改为随机配置。

module LED_COUNTER( CLK_50M, LED, Positive, Negative );
input wire CLK_50M;
input wire Positive;
input wire Negative;
output reg[7:0] LED;

always@( posedge Positive or posedge Negative )
begin
    if(Positive == 1)
        LED <= LED + 1;
    else
        LED <= LED - 1; 
end

endmodule

我正在使用这个板:http ://www.ebay.com/itm/111621868286 。引脚分配是:

连接:

交换按钮的引脚分配后,行为保持不变。

4

3 回答 3

2

正如其他人已经指出的那样,您应该使用 时钟,CLK_50M并且应该消除输入的抖动(某些 FPGA 会自动为您执行此操作,请查看您的手册)。

您看到部分功能的原因是合成器解释 RTL 的方式。如果灵敏度列表是边沿触发的,并且该信号在 always 块的主体中​​被引用,那么合成器将认为它是异步电平敏感信号。这是用于异步重置和设置(有时称为清除和预设)。在大多数设计中,ASIC 设计通常使用具有异步复位功能的触发器。FPGA 往往具有有限数量的带有异步设置或休息的触发器,因此请查看您的手册并谨慎使用。

使用您的代码,Negative是时钟,Positive并被视为高电平有效异步输入。

将代码修改为如下所示的功能行为等效(在模拟中),然后Positive将是时钟,并且Negative将是高电平有效异步输入。

always@( posedge Positive or posedge Negative )
begin
    if(Negative == 1)
        LED <= LED - 1;
    else
        LED <= LED + 1; 
end

有几种在线学习 Verilog 的资源(使用您最喜欢的搜索引擎),我的个人资料上发布了一些资源,但更多的是针对 SystemVerilog。
下面是一些伪代码,可以为您的项目指明正确的方向:

always @(posedge CLK_50M)
begin
  past_Positive <= Positive;
  // ...
  case({/* ... , */ past_Positive,Positive})
    4'b0001 : LED <= LED + 1;
    4'b0100 : LED <= LED - 1;
    // ...
  endcase
end
于 2015-09-20T19:18:30.733 回答
1

您没有去抖电路或逻辑。机械开关在物理上会反弹很多,因此您的 50MHz 时钟会在输入信号上看到很多很多的转换,从而导致不稳定的行为。

我忘了提到你甚至没有在同步设计中使用那个 50MHz 时钟。相反,您正在异步寻找转换。

你需要一个低通滤波器。要么使用输入信号上的模拟组件实现,要么作为硬件中的计数器实现。

于 2015-09-20T14:01:31.597 回答
1

首先,将设计更新为同步设计,其中状态仅在 的上升沿发生变化CLK_50M,例如

always@( posedge CLK_50M)
begin
    ...
end

然后为两个开关输入添加去抖动逻辑逻辑;见接触反弹。这可以通过您自己编写的一个小模块来完成;这是一个很好的练习。

然后,触点去抖动逻辑的输出可用于变化检测,每次按下触点时进行单周期指示,然后该指示可用于更新计数器。

于 2015-09-20T14:04:40.250 回答