【问题标题】:Why does this code work only partially?为什么这段代码只能部分工作?
【发布时间】:2015-09-21 06:01:46
【问题描述】:

此代码应该在按下一个按钮时增加一个计数器(输出到 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。引脚分配是:

连接:

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

【问题讨论】:

  • 这可能最好在电子堆栈交换站点询问。
  • 我认为它与编程比电子设计更相关。我使用带有参考设计的电路板,所以问题不是电子问题,而是编程问题。
  • 严格来说,这还是硬件设计,不是编程。 Verilog 是一种硬件 描述语言,而不是一种编程(软件)语言。然而,这条线有些模糊。
  • 如果硬件描述离题,为什么 VHDL 和 Verilog 标签会在 SO 上列出这么大的用户社区?
  • Verilog 和 VHDL 确实处于 SO 和 SE Electronics 的边缘。他们的设计模型和使用的工具确实比 SE:E 更好,但是当涉及到具有 ASIC/FPGA 或布局等的电路板和设计系统时,这些更好地放在 SE:E 中。因此,至少在我看来,如果它与 VHDL 或 Verilog 代码本身有关,它很适合 SO。如果它是与董事会相关的问题,那更适合 SE:E

标签: verilog fpga intel-fpga quartus


【解决方案1】:

正如其他人已经指出的那样,您应该使用 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 的资源(使用您最喜欢的搜索引擎),我在 my profile 上发布了一些资源,但更多的是针对 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

【讨论】:

    【解决方案2】:

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

    always@( posedge CLK_50M)
    begin
        ...
    end
    

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

    然后,触点去抖动逻辑的输出可用于变化检测,每次按下触点时都会进行一次循环指示,然后此指示可用于更新计数器。

    【讨论】:

    • 你能推荐一个从基础开始学习verilog的好资源吗?
    • 对不起,我更喜欢VHDL而不是HDL;但是 amazon.com 上的 Verilog 评论可能是一个不错的起点。
    【解决方案3】:

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

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

    您在某处需要一个低通滤波器。可以在输入信号上使用模拟组件实现,也可以作为硬件中的计数器实现。

    【讨论】:

    • 这并不能解释为什么消极的一面有效(有时双重注册,但有效)但积极的一面却没有。
    • 这可能是由于触点的机械差异很小。尝试更改引脚或触点,看看它是否会逆转行为。
    • 我做到了。更改引脚后,行为保持不变。
    • OK,那大概是FPGA中具体实现的原因吧。 always@( posedge Positive or posedge Negative ) ... 中的代码不会映射到任何原生 FPGA 设计元素,例如触发器。但无论如何,实现这种功能的方式是错误的,所以我认为你不应该在这条路上浪费更多时间;正如我建议的那样,开始学习同步设计的实现对您来说更有用。
    猜你喜欢
    • 1970-01-01
    • 2012-06-10
    • 2017-06-08
    • 1970-01-01
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    相关资源
    最近更新 更多