在de1板的状态机中增加七段显示

时间:2014-11-29 14:26:42

标签: vhdl state-machine seven-segment-display

我正在使用状态机创建一个倒计时器,在启动时显示00:00,当按下Key1时,你可以通过递增/递减分钟来输入一个时间,如果保持上/下按钮5个周期它会上升/下降5.感谢一些非常棒的帮助(@DavidKoontz)我已经完成了代码。没有必要去除我的代码中的按钮b / c我的altera板似乎很好地拾取低信号。因为我只使用一个时钟按钮反应缓慢b / c时钟设置为1Hz。

Library ieee;
USE ieee.std_logic_1164.ALL;
ENTITY CountDownTimer IS
PORT(
CLK,RESET: IN STD_LOGIC;
a1, b1, c1, d1, e1, f1, g1 : OUT STD_LOGIC;
a2, b2, c2, d2, e2, f2, g2 : OUT STD_LOGIC;
a3, b3, c3, d3, e3, f3, g3 : OUT STD_LOGIC;
a4, b4, c4, d4, e4, f4, g4 : OUT STD_LOGIC;
--All 4 buttons for timer
BUTTON0, BUTTON1, BUTTON2, BUTTON3: IN STD_LOGIC;
--LEDR9
ON_OFF_LED: OUT BIT;
--LEDR9-R6
INPUT_LED1, INPUT_LED2, INPUT_LED3, INPUT_LED4: OUT BIT;
--LEDR0
DONE_LED: OUT BIT);
END CountdownTimer;
ARCHITECTURE Counter OF CountDownTimer IS
--Define state machine
TYPE STATE_TYPE IS (A_ON_OFF, B_INPUT, C_COUNTDOWN, D_DONE);
SIGNAL State : STATE_TYPE;
--Buttons produce 0 when pressed, signal for 1 when pressed
SIGNAL B3D0, B3D1, B3D2, B3D3: STD_LOGIC := '0';
SIGNAL B2D0, B2D1, B2D2, B2D3: STD_LOGIC := '0';
SIGNAL CLOCK: STD_LOGIC := '0';
SIGNAL Count: INTEGER:= 1;
--SIGNAL for range of integer values
SIGNAL Minute1 : INTEGER RANGE 0 TO 6;
SIGNAL Minute2 : INTEGER RANGE 0 TO 9;
SIGNAL Second1 : INTEGER RANGE 0 TO 5;
SIGNAL Second2 : INTEGER RANGE 0 TO 9;
--Output for the seven segment displays
SIGNAL OUTPUT_HEX0 :  STD_LOGIC_VECTOR(6 DOWNTO 0);
SIGNAL OUTPUT_HEX1 :  STD_LOGIC_VECTOR (6 DOWNTO 0);
SIGNAL OUTPUT_HEX2 :  STD_LOGIC_VECTOR (6 DOWNTO 0);
SIGNAL OUTPUT_HEX3 :  STD_LOGIC_VECTOR (6 DOWNTO 0);
SIGNAL B3_HOLD: STD_LOGIC := '0'; --Gets 1 if button3 was held
SIGNAL B2_HOLD: STD_LOGIC := '0'; --Gets 1 is button2 was held

BEGIN

             --Segment 1 display pins
             a1 <= OUTPUT_HEX0(6);
             b1 <= OUTPUT_HEX0(5);
             c1 <= OUTPUT_HEX0(4);
             d1 <= OUTPUT_HEX0(3);
             e1 <= OUTPUT_HEX0(2);
             f1 <= OUTPUT_HEX0(1);
             g1 <= OUTPUT_HEX0(0);
             --Segment 2 display pins
             a2 <= OUTPUT_HEX1(6);
             b2 <= OUTPUT_HEX1(5);
             c2 <= OUTPUT_HEX1(4);
             d2 <= OUTPUT_HEX1(3);
             e2 <= OUTPUT_HEX1(2);
             f2 <= OUTPUT_HEX1(1);
             g2 <= OUTPUT_HEX1(0);
             --Segment 3 display pins
             a3 <= OUTPUT_HEX2(6);
             b3 <= OUTPUT_HEX2(5);
             c3 <= OUTPUT_HEX2(4);
             d3 <= OUTPUT_HEX2(3);
             e3 <= OUTPUT_HEX2(2);
             f3 <= OUTPUT_HEX2(1);
             g3 <= OUTPUT_HEX2(0);
             --Segment 4 display pins
             a4 <= OUTPUT_HEX3(6);
             b4 <= OUTPUT_HEX3(5);
             c4 <= OUTPUT_HEX3(4);
             d4 <= OUTPUT_HEX3(3);
             e4 <= OUTPUT_HEX3(2);
             f4 <= OUTPUT_HEX3(1);
             g4 <= OUTPUT_HEX3(0);

            WITH Second2 SELECT
            --One's second place, 0 to 9
            OUTPUT_HEX0 <= "0000001" WHEN 0,
                                "1001111" WHEN 1,
                                "0010010" WHEN 2,
                                "0000110" WHEN 3,
                                "1001100" WHEN 4,
                               "0100100" WHEN 5,
                                "0100000" WHEN 6,
                                "0001101" WHEN 7,
                                "0000000" WHEN 8,
                                "0001100" WHEN 9,
                                "0000001" WHEN OTHERS;
            WITH Second1 SELECT
            --Tens second place, 0 to 5
            OUTPUT_HEX1 <= "0000001" WHEN 0,
                                "1001111" WHEN 1,
                                "0010010" WHEN 2,
                                "0000110" WHEN 3,
                                "1001100" WHEN 4,
                               "0100100" WHEN 5,
                                "0000001" WHEN OTHERS;
            WITH Minute2 SELECT
            --Ones minute place, 0 to 9
            OUTPUT_HEX2 <= "0000001" WHEN 0,
                                "1001111" WHEN 1,
                                "0010010" WHEN 2,
                                "0000110" WHEN 3,
                                "1001100" WHEN 4,
                               "0100100" WHEN 5,
                               "0100000" WHEN 6,
                                "0001101" WHEN 7,
                                "0000000" WHEN 8,
                                "0001100" WHEN 9,
                                "0000001" WHEN OTHERS;
            WITH Minute1 SELECT
            --Tens minute place, 0 to 6
            OUTPUT_HEX3 <= "0000001" WHEN 0,
                                "1001111" WHEN 1,
                                "0010010" WHEN 2,
                                "0000110" WHEN 3,
                                "1001100" WHEN 4,
                               "0100100" WHEN 5,
                               "0100000" WHEN 6,
                                "0000001" WHEN OTHERS;


PROCESS(CLK)
    BEGIN
        IF RISING_EDGE(CLK) THEN 
            Count <= Count + 1;
            IF (Count = 30000000) THEN
                CLOCK <= NOT(CLOCK);
                Count <= 1;
            END IF;
        END IF; 
END PROCESS;

PROCESS(CLOCK)
BEGIN
    IF RISING_EDGE(CLOCK) THEN
        B3D0 <= BUTTON3;
        B3D1 <= NOT B3D0;
        B3D2 <= B3D1;
        B3D3 <= B3D2;
        B2D0 <= BUTTON2;
        B2D1 <= NOT B2D0;
        B2D2 <= B2D1;
        B2D3 <= B2D2;
        B3_HOLD <= B3D1 AND B3D2 AND B3D3;
        B2_HOLD <= B2D1 AND B2D2 AND B2D3;
    END IF;
    END PROCESS;

PROCESS(CLOCK)
BEGIN       
IF RESET = '1' THEN --Async Reset
            State <= A_ON_OFF;
ELSIF RISING_EDGE(CLOCK) THEN

    CASE State IS
---------------------------------A_ON_OFF---------------------------------  
        WHEN A_ON_OFF =>
            --Red LED9
            ON_OFF_LED <= '1';
            Minute1 <= 0;
            Minute2 <= 0;
            Second1 <= 0;
            Second2 <= 0;
            IF (BUTTON0 = '0') THEN
                                    ON_OFF_LED <= '0';
                                    State <= B_INPUT;
            END IF; 
---------------------------------B_INPUT/PAUSE---------------------------------                 

        WHEN B_INPUT =>

            --Light up LEDs
            INPUT_LED1 <= '1';
            INPUT_LED2 <= '1';
            INPUT_LED3 <= '1';
            INPUT_LED4 <= '1';
            IF (Minute1 = 6) THEN
                Minute2 <= 0;
                Second1 <= 0;
                Second2<= 0;
                State <= B_INPUT;
            END IF;
            --Count up button   
            IF (BUTTON3 = '0' AND B3_HOLD = '0') THEN   
                IF (Minute1 = 6 AND Minute2 >= 0) THEN
                    Minute1 <= 0;
                    Minute2 <= 1;
                    Second1 <= 0;
                    Second2 <= 0;
                        State <= B_INPUT;
                ELSIF (Minute2 < 9) THEN
                    Minute2 <= (Minute2 + 1);
                    State <= B_INPUT;
                ELSIF (Minute2 = 9) THEN
                    Minute1 <= (Minute1 + 1);
                    Minute2 <= 0;
                    State <= B_INPUT;
                END IF;
            END IF;
            IF (BUTTON3 = '0' AND B3_HOLD = '1') THEN   
                IF (Minute1 = 6 AND Minute2 >= 0) THEN
                        Minute1 <= 0;
                        Minute2 <= 5;
                        Second1 <= 0;
                        Second2 <= 0;
                        State <= B_INPUT;
                ELSIF (Minute2 < 5) THEN
                    IF (Minute2 = 0) THEN
                        Minute2 <= (Minute2 + 5);
                        State <= B_INPUT;
                    ELSE
                        Minute2 <= (Minute2 + 1);
                        State <= B_INPUT;
                    END IF;
                ELSIF (Minute2 = 5) THEN
                    Minute2 <= 0;
                    Minute1 <= (Minute1 + 1);
                    State <= B_INPUT;
                ELSIF (Minute2 > 5) THEN
                    IF (Minute2 = 9) THEN
                        Minute2 <= 0;
                        Minute1 <= (Minute1 + 1);
                        State <= B_INPUT;
                    ELSE
                        Minute2 <= (Minute2 + 1);
                        State <= B_INPUT;
                    END IF;
                END IF;
            END IF;
            --Count down button
            IF (BUTTON2 = '0' AND B2_HOLD = '0') THEN
                IF ((Minute1 = 0) AND (Minute2 = 0)) THEN
                    Minute1 <= 6;
                    Minute2 <= 0;
                    Second1 <= 0;
                    Second2 <= 0;
                ELSIF (Minute2 = 0) THEN
                    Minute2 <= 9;
                    Minute1 <= (Minute1 - 1);
                    ELSE 
                        Minute2 <= (Minute2 - 1);
                END IF;
                State <= B_INPUT;
            END IF;
            IF (BUTTON2 = '0' AND B2_HOLD = '1') THEN
                IF (Minute1 = 0 AND Minute2 = 0) THEN
                        Minute1 <= 6;
                        Minute2 <= 0;
                        Second1 <= 0;
                        Second2 <= 0;
                        State <= B_INPUT;
                ELSIF (Minute2 = 0 AND Minute1 > 0) THEN
                    Minute1 <= (Minute1 - 1);
                    Minute2 <= 5;
                    State <= B_INPUT;
                ELSIF (Minute2 < 5) THEN
                    IF (Minute2 = 0) THEN
                        Minute1 <= (Minute1 - 1);
                        Minute2 <= 5;
                        State <= B_INPUT;
                    ELSE
                        Minute2 <= (Minute2 - 1);
                        State <= B_INPUT;
                    END IF;
                ELSIF (Minute2 = 5) THEN
                    Minute2 <= (Minute2 - 5);
                    State <= B_INPUT;
                ELSIF (Minute2 > 5) THEN
                    Minute2 <= (Minute2 - 1);
                    State <= B_INPUT;
                END IF;
            END IF;
            --Clear button
            IF (BUTTON1 = '0') THEN
                Minute1 <= 0;
                Minute2 <= 0;
                Second1 <= 0;
                Second2 <= 0;
                State <= B_INPUT;
            END IF;
            --Start Button
            IF (BUTTON0 = '0') THEN
                                    --Turn off LEDs
                                    INPUT_LED1 <= '0';
                                    INPUT_LED2 <= '0';
                                    INPUT_LED3 <= '0';
                                    INPUT_LED4 <= '0';
                                    State <= C_COUNTDOWN;
            END IF;
---------------------------------C_COUNTDOWN---------------------------------                       

            WHEN C_COUNTDOWN =>

            IF (Second2 > 0) THEN
                Second2 <= (Second2 - 1);
            ELSIF (Second2 = 0) THEN
                IF (Second1 > 0) THEN
                    Second2 <= 9;
                    Second1 <= (Second1 - 1);
                ELSIF (Second1 = 0) THEN
                    IF (Minute2 > 0) THEN
                        Second1 <= 5;
                        Minute2 <= (Minute2 - 1);
                        IF (Second2 = 0) THEN
                            Second2 <= 9;
                        END IF;
                    ELSIF (Minute2 = 0) THEN
                            IF (Minute1 > 0) THEN
                                IF (Second1 = 0) THEN
                                    Second1 <= 5;
                                    Minute2 <= (Minute2 - 1);
                                    IF (Second2 = 0) THEN
                                        Second2 <= 9;
                                    END IF;
                                END IF;
                                Minute2 <= 9;
                                Minute1 <= (Minute1 - 1);
                            ELSIF (Minute1 <= 0) THEN
                                                        State <= D_DONE;
                            END IF;
                    END IF;
                END IF;
            END IF;
            --Reset Button
            IF (BUTTON1 = '0') THEN
                                        STATE <= A_ON_OFF;
            --Input button
            ELSIF (BUTTON0 = '0') THEN
                                            STATE <= B_INPUT;
            END IF;
---------------------------------D_DONE---------------------------------                        

            WHEN D_DONE =>
            --LEDR0
            DONE_LED <= '1';
                --Reset button
                IF (BUTTON1 = '0') THEN
                                            DONE_LED <= '0';
                                            STATE <= A_ON_OFF;

                --Input button
                ELSIF (BUTTON0 = '0') THEN
                                                DONE_LED <= '0';
                                                STATE <= B_INPUT;
                END IF;                  
        END CASE;
END IF;
END PROCESS;

END Counter;                  

1 个答案:

答案 0 :(得分:0)

在案例陈述中的选择when b_input中,每minute2 clkbutton3增加clk,它就是一个启用码。它需要转换为一个事件,除非你指望一个真正的慢clock(注意你也生成一个慢clk)。此启用与PROCESS(BUTTON3) BEGIN IF RISING_EDGE(BUTTON3) THEN FF3 <= NOT(BUTTON3); END IF; END PROCESS; 不同步,可能导致设置或保持时间违规导致亚稳态。

在此过程中

ff3

这会将button3指定为低但从不高。上升沿意味着从&#39; 0&#39;到&#39; 1&#39;在ff3。换句话说,您的驾驶clk仅为低。

这就是您的计数器没有变化的原因。除了潜在的亚稳态问题外,还应该为单个minute2启用。

对于模拟,整数范围绑定计数器(例如signal minute2 : integer range 0 to 9; )将溢出。 VHDL没有进行范围限制模运算。

minute2

10 state b_input b_input时,由于范围错误,模拟将退出。

选择 if minute2 = 9 then minute2 <= 0; else minute2 <= minute2 + 1; end if; 中的增量应该类似于:

clk

(还有一个微妙的暗示,你应该模拟这件事。)

您需要使用按钮中的单个clk启用来增加计数器。

执行此操作的方法是:a)去除按钮,b)检测clk域中的and域的上升沿。

所有这一切都很复杂,因为您同时使用&lt; clk clk时钟`作为时钟。

关于如何实现去抖动,边缘检测和单clock启用的建议取决于您的时钟频率实际上是什么。

或者你可以考虑一堆时钟ORing,你可以使用按钮递增内容并为c_countdownlibrary ieee; use ieee.std_logic_1164.all;

您没有在实体声明之前包含context子句:

clk

有一个问题,我应该使用按钮3的Falling_Edge作为ff3,因为这样做我的代码也有问题

如果您遇到问题,您可能会遇到上升边缘问题。所有问题的根源可能都是接触反弹。

在这种情况下,我并不主张使用按钮3的下降沿。

这里的问题是从按钮3产生单个时钟使能(或者将其用作时钟)。它还需要去抖动。开关或按钮弹跳的持续时间取决于几个方面 - 触点的质量,操作的难度以及开关臂的弹性。

有几种方法可以摆脱反弹。例如,您可以使用常开和常闭触点来操作RS锁存器,要求两个开关或按钮信号处于相反的二进制状态。您可以暂时过滤(在10毫秒范围内的时钟间隔),需要N个稳定样本。这也可以过滤掉从异步域到同步(时钟)域的亚稳态。

要使用等效的FF3作为clk的启用,您需要对该按钮进行去抖动,并检测&lt; clk`域中的上升沿。

由于您的按钮几乎可以保证是单刀开关,因此您需要某种时间过滤。如果它的时钟与&#39; clk&#39;您可以简单地使用计数器生成的长间隔启用来连续采样按钮。这允许您在FF3域中使用额外的触发器来检测它曾经是低电平并且它现在很高,该门的输出在现在使用clk的地方使用。 / p>

如果您说Count为50 MHz,则去抖可能需要从debounce_en计数器生成启用。

让我们称之为clock

注意这是设置为在button3的下降沿之后的一段时间采样。一个旧的高点和一两个成功的低点。这是button3掉落后的毫秒数,所以它应该是安全的。

50 Mhz除以4000000得到倒数为12.5或8 ms的 signal debounce_en: std_logic; signal button3_d0, button3_d1, button3_d2: begin 波特。对于去抖按钮3的时间过滤器来说,这是一个很好的起始率:

UNLABELLED1:
    process(clk)
    begin
        if rising_edge(clk) then 
            debounce_en <= '0';  -- one ping only.
            count <= count + 1;
            if count = 4000000 then
                clock <= not clock;
                debounce_en <= '1';  -- for one clk every 4000000
                count <= 1;
            end if;
        end if; 

    end process;

...

debounce_en

我们可以使用button3来代替FF3,而不是生成process (clk) begin if rising_edge(clk) and debounce_en = '1' then button3_d0 <= button3; button3_d1 <= button3_d0; button3_d2 <= button3_d1; end if; button3_enable <= not button3_d1 and button3_d2 and debounce_en;

button3_enable <= not_button3_d1 and not button3_d2 and button3_d3 and debounce_en;

这可能会起作用的原因是因为超过8 ms足够长的时间间隔去抖动其中一个开关。 (如果它没有增加另一个阶段并且:

FF3

这不需要响铃&#39;被三个连续的触发器捕获(30毫秒)。

&#39; button3_enable将用于代替 when b_input => if button3_enable = '1' then -- count up button if minute2 = 9 then minute2 <= 0; else minute2 <= minute2 + 1; end if; input_led <= '1'; --green led7 end if; ,所有三个(或更多)新信号都是std_logic类型,触发器用作移位寄存器。

使用长时间需要已知值的时间滤波器可能会过滤掉按钮上的短脉冲,您很难快速拨动按钮。

至于在案例陈述中操作`minute2:

debounce_en

如果您更改Count的时钟频率(我很想得到),您从clock派生clk的方式可能会发生变化它自己实时运行)。你没有完成C_COUNTDOWN,但看起来理想情况下它会以一秒的速率启用并且具有秒数和分钟计数器级联。

有关DE1声明的去抖按钮的说明

我找到了DE1-SoC板手册,在图3-14和3.6.1节中声称使用74HC245施密特触发缓冲器(名义上是双向的,无疑是单向使用)足以将按钮用作时钟。这取决于电路板的布局,其中一个按键的电容和电感,上拉电阻的大小,以及它们是否这样说......(并且可能它有效,它们提供了它在几代电路板设计中,这对上述描述有何影响?

您仍然需要与clk同步并生成一个{{1}}期限启用。所以不多。