Увеличение семисегментного дисплея в автомате для платы de1

Я использую конечный автомат для создания таймера обратного отсчета, который при запуске отображает 00:00, и когда нажата клавиша 1, вы можете ввести время, увеличивая / уменьшая минуты на 1, и если кнопка вверх / вниз удерживается в течение 5 циклов, будет увеличиваться / уменьшаться на 5. Благодаря некоторой потрясающей помощи (@DavidKoontz) я закончил код. Нет необходимости разбирать кнопки в моем коде, потому что моя плата альтера, кажется, отлично воспринимает низкие сигналы. Поскольку я использую только один такт, кнопки реагируют медленно, поскольку б / с часы установлены на 1 Гц.

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 ответ

Решение

На выбор when b_input в случае дела вы будете увеличивать minute2 для каждого clkbutton3 низкий, это возможность. Это должно быть преобразовано в событие, если вы не рассчитываете на очень медленный clk (отмечая, что вы также производите медленный clock). Это включение не является синхронным с clk, это может вызвать метастабильность для установки или нарушение времени удержания.

В процессе

PROCESS(BUTTON3)
BEGIN   
IF RISING_EDGE(BUTTON3) THEN
FF3 <= NOT(BUTTON3);
END IF;
END PROCESS;

Это назначит ff3 низкий, но никогда не высокий. Нарастающий фронт означает переход от "0" к "1" на button3, Другими словами, ваше вождение ff3 только низкий

Вот почему ваш счетчик не меняется. Помимо потенциальной проблемы метастабильности, включение должно происходить для одного clk,

Для симуляции счетчиков с целым диапазоном (например, minute2) переполнится. VHDL не выполняет модульную арифметику с ограничением по дальности.

signal minute2 : integer range 0 to 9;

когда minute2 достигает 10 в stateb_input Симуляция завершится из-за ошибки диапазона.

Это увеличение в выборе b_input должен выглядеть примерно так:

                    if minute2 = 9 then
                        minute2 <= 0;
                    else
                        minute2 <= minute2 + 1;
                    end if;

(И есть тонкий намек, что вы должны смоделировать эту вещь.)

Вам нужно использовать один clk включить с помощью кнопки (кнопок) для увеличения счетчиков.

Способ сделать это: а) отменить деблокирование кнопок, б) обнаружить нарастающий фронт в clk домен для одного clk,

Все это сложно, потому что вы используете оба "clkandчасы как часы.

Рекомендация о том, как реализовать де-отскок, обнаружение края и одиночный clk enable зависит от того, какова ваша тактовая частота.

В качестве альтернативы вы могли бы рассмотреть кучу часов ИЛИ, где вы используете кнопки, чтобы увеличивать вещи и ворота clock за c_countdown,

Вы не включили контекстное предложение до объявления сущности:

library ieee;   
use ieee.std_logic_1164.all;

Один вопрос, должен ли я использовать Falling_Edge кнопки 3 для ff3, потому что при этом мой код также имел проблемы

Вероятно, если бы у вас были проблемы с острием, у вас также были бы проблемы с острыми углами. Корень всех проблем, вероятно, будет отказов контактов.

И нет, я не защищаю использование падающего края кнопки 3 в этом случае.

Проблема здесь состоит в том, чтобы произвести одиночное включение часов от кнопки 3 (или альтернативно использовать его как часы). Это также нуждается в разоблачении. Продолжительность отскока переключателя или кнопки зависит от нескольких факторов - массы контактов, от того, как сильно они работают, и от того, насколько упругим является рычаг переключателя.

Есть несколько способов избавиться от отказов. Например, вы можете использовать нормально разомкнутую и нормально замкнутую пару контактов для управления защелкой RS, требуя, чтобы два сигнала переключателя или кнопки находились в противоположных двоичных состояниях. Вы можете временно фильтровать (с интервалом в 10 миллисекунд), требующее N стабильных выборок. Это также отфильтровывает метастабильность от перехода из асинхронного домена в синхронный (синхронизированный) домен.

Использовать эквивалент FF3 в качестве разрешения для clk, вам нужно отменить кнопку и обнаружить передний фронт в домене 'clk'.

Поскольку ваши кнопки почти гарантированно будут однополюсными, вам нужна какая-то временная фильтрация. Если часы для этого связаны с 'clk', вы могли бы просто использовать включение длинного интервала, созданное счетчиком, для последовательной выборки кнопки. Это позволяет использовать дополнительный триггер в clk домен, чтобы обнаружить его раньше был низким, и теперь он высокий, выход этих ворот используется где FF3 используется сейчас.

Если clk 50 МГц, как вы говорите, устранение неполадок может повлечь за собой Count счетчик.

Давайте назовем это debounce_en,

Обратите внимание, что это настройка для сэмплирования через некоторое время после падения края кнопки 3. Старый максимум и один или два последовательных минимума. Это миллисекунды после падения button 3, так что это должно быть безопасно.

50 МГц, разделенная на 4000000, дает clock бода обратной 12,5 или 8 мс. Это хороший стартовый показатель для временного фильтра для удаления кнопки button 3:

    signal debounce_en: std_logic;
    signal button3_d0, button3_d1, button3_d2:

    begin

...

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;

И причина того, что это сработает, заключается в том, что более чем 8 мс - это достаточно большой интервал для отладки одного из этих ключей. (И если это не добавить еще один этап и:

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

Который не требует "звонка", фиксируется тремя последовательными триггерами (30 мс).

button3_enable будет использоваться вместо FF3все три (или более) новых сигналов имеют тип std_logic, а триггеры используются в качестве регистра сдвига.

Использование временного фильтра, для которого требуются столь длительные известные значения, может потенциально отфильтровывать короткие импульсы на кнопках, и вам будет трудно нажимать такие быстрые кнопки.

А что касается работы `minute2 в выражении case:

            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;

И как вы должны были получить debounce_en от Count может быть изменено, если вы измените clockтактовая частота (я бы соблазнился, чтобы он работал в режиме реального времени сам). Вы не завершили C_COUNTDOWN, но, похоже, в идеале он будет работать с разрешением одной секунды и иметь каскадные счетчики секунд и минут.

Примечания к заявлению DE1 о средствах отмены действий

Я нашел руководство по плате DE1-SoC, и на рисунке 3-14 и в разделе 3.6.1 утверждается, что использование триггерного буфера Шмидта 74HC245 (номинально двунаправленный, несомненно, используется однонаправленно) достаточно для использования кнопок в качестве часов. Это будет зависеть от расположения платы, емкости и индуктивности одной из кнопок, размера подтягивающих резисторов и, если они так скажут... (и, вероятно, это работает, они предложили его в нескольких поколениях плат).), как это влияет на приведенное выше описание?

Ну, вы все равно должны синхронизироваться с clk и произвести один clk период включения. Так что не очень.

Другие вопросы по тегам